-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
195 lines (167 loc) · 5.53 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
/**
* index.js
* Created by jady on 2016/8/12.
*/
var fs = require("fs");
var watch = require("node-watch");
var pathutil = require("path");
var path2reg = require("path-to-regexp");
function Mock() {
return this._init.apply(this, Array.prototype.slice.call(arguments));
}
Mock.prototype = {
constructor: Mock,
_init: function(options) {
this._options = options;
this._path2RegMap = {};
var root = options.root;
// 从默认路径获取配置文件
var configPath = pathutil.resolve(root + "/mock.config.js");
this._reloadConfig(configPath);
// 如果需要热替换,那就跟踪配置文件的变化
if (this._config.hot) {
var _this = this;
// 注意:这里只能跟踪文件夹,不能只跟踪文件
var watcher = watch(root, function(filename) {
if (filename !== configPath) return;
delete require.cache[configPath];
_this._path2RegMap = {};
_this._reloadConfig(configPath);
});
watcher.on("error", function(filename) {
console.error(`Error on Watch(Mock):`, filename);
});
}
},
deal: function(req, res, next) {
var pathname = req.path || "/";
// 如果配置文件中设置为忽略,那就忽略之
var pathConfig = this._configOfPath(pathname);
if ((typeof pathConfig == "boolean" && pathConfig === false)
|| (typeof pathConfig == "object" && pathConfig != null && pathConfig.ignore === true)) {
// 明确表示不处理
return next();
}
// 如果配置信息就是一个方法,那就交给其来处理
if (typeof pathConfig == "function") {
return pathConfig(req, res, next);
}
// 下面就是自动在路径下寻找匹配文件
// 获得所有可能的路径信息,找到第一个存在的文件
var paths = this._getPaths(pathname);
for (var path of paths) {
if (isExist(path)) {
// 如果是js文件,那就读取这个js文件,然后调用之
if (path.length > 3 && path.substr(path.length - 3).toLowerCase() === ".js") {
var mod = require(path);
if (typeof mod === "function") {
return mod(req, res, next);
}
// 如果是热替换,那就直接删除这个缓存
if (this._config.hot) {
delete require.cache[path];
}
}
res.sendFile(path);
return;
}
}
next();
},
/**
* 获得配置信息
* @returns {{}}
* @private
*/
_reloadConfig: function(configPath) {
var config = {};
if (isExist(configPath)) {
config = require(configPath);
}
this._config = config;
},
/**
* 获得该路径的配置信息
* @param pathname
* @private
*/
_configOfPath: function(pathname) {
// 如果在路径配置中显示忽略这个路径,那就直接忽略之
var ignore = this._options.ignore;
if (ignore) {
if (pathname.indexOf(ignore) == 0) {
return false;
}
}
// 如果不存在配置信息,那就直接返回
var pathsConfig = this._config.paths;
if (!pathsConfig) return null;
var path2RegMap = this._path2RegMap;
for (var path in pathsConfig) {
var reg = path2RegMap[path] || (path2RegMap[path] = path2reg(path, []));
if (reg.test(pathname)) {
return pathsConfig[path];
}
}
return null;
},
/**
* 获得可能的路径名
* @param pathname
* @returns {Array}
* @private
*/
_getPaths: function(pathname) {
var prefix = this._options.root + pathname;
var paths;
if (pathname.charAt(pathname.length - 1) === "/") {
// pathname是个路径,比如: /path/name/
paths = [ prefix + "index.js",
prefix + "index.json",
prefix + "index.html"
];
} else {
var result = ExtReg.exec(pathname);
if (result && result[1]) {
// pathname有后缀,比如:/path/to/filename.do
var ext = result[1].toLowerCase();
if (ext != "js") {
paths = [ prefix + ".js",
prefix + ".json",
prefix + ".html"
];
}
paths.push(prefix);
} else {
// pathname没有后缀,比如:/path/name
paths = [ prefix + ".js",
prefix + ".json",
prefix + ".html",
prefix + "/index.js",
prefix + "/index.json",
prefix + "/index.html"
];
}
}
return paths;
}
};
// 获取后缀的正则表达式
var ExtReg = /\.(\w+)$/;
/**
* 判断某个文件是否存在
* @param filename
* @returns {boolean}
*/
function isExist(filename) {
try {
fs.accessSync(filename, fs.R_OK);
return true;
} catch (e) {
return false;
}
}
module.exports = function(options) {
var instance = new Mock(options);
return instance.deal.bind(instance);
};