1 | const minimatch = require('minimatch');
|
2 | const path = require('path');
|
3 | const fs = require('fs');
|
4 | const debug = require('debug')('nodemon:match');
|
5 | const utils = require('../utils');
|
6 |
|
7 | module.exports = match;
|
8 | module.exports.rulesToMonitor = rulesToMonitor;
|
9 |
|
10 | function rulesToMonitor(watch, ignore, config) {
|
11 | var monitor = [];
|
12 |
|
13 | if (!Array.isArray(ignore)) {
|
14 | if (ignore) {
|
15 | ignore = [ignore];
|
16 | } else {
|
17 | ignore = [];
|
18 | }
|
19 | }
|
20 |
|
21 | if (!Array.isArray(watch)) {
|
22 | if (watch) {
|
23 | watch = [watch];
|
24 | } else {
|
25 | watch = [];
|
26 | }
|
27 | }
|
28 |
|
29 | if (watch && watch.length) {
|
30 | monitor = utils.clone(watch);
|
31 | }
|
32 |
|
33 | if (ignore) {
|
34 | [].push.apply(monitor, (ignore || []).map(function (rule) {
|
35 | return '!' + rule;
|
36 | }));
|
37 | }
|
38 |
|
39 | var cwd = process.cwd();
|
40 |
|
41 |
|
42 |
|
43 | monitor = monitor.map(function (rule) {
|
44 | var not = rule.slice(0, 1) === '!';
|
45 |
|
46 | if (not) {
|
47 | rule = rule.slice(1);
|
48 | }
|
49 |
|
50 | if (rule === '.' || rule === '.*') {
|
51 | rule = '*.*';
|
52 | }
|
53 |
|
54 | var dir = path.resolve(cwd, rule);
|
55 |
|
56 | try {
|
57 | var stat = fs.statSync(dir);
|
58 | if (stat.isDirectory()) {
|
59 | rule = dir;
|
60 | if (rule.slice(-1) !== '/') {
|
61 | rule += '/';
|
62 | }
|
63 | rule += '**/*';
|
64 |
|
65 |
|
66 | if (!not) {
|
67 | config.dirs.push(dir);
|
68 | }
|
69 | } else {
|
70 |
|
71 |
|
72 | throw new Error();
|
73 | }
|
74 | } catch (e) {
|
75 | var base = tryBaseDir(dir);
|
76 | if (!not && base) {
|
77 | if (config.dirs.indexOf(base) === -1) {
|
78 | config.dirs.push(base);
|
79 | }
|
80 | }
|
81 | }
|
82 |
|
83 | if (rule.slice(-1) === '/') {
|
84 |
|
85 | rule += '*';
|
86 | }
|
87 |
|
88 |
|
89 |
|
90 | if (rule.slice(-4) !== '**/*' &&
|
91 | rule.slice(-1) === '*' &&
|
92 | rule.indexOf('*.') === -1) {
|
93 |
|
94 | if (rule.slice(-2) !== '**') {
|
95 | rule += '*/*';
|
96 | }
|
97 | }
|
98 |
|
99 |
|
100 | return (not ? '!' : '') + rule;
|
101 | });
|
102 |
|
103 | return monitor;
|
104 | }
|
105 |
|
106 | function tryBaseDir(dir) {
|
107 | var stat;
|
108 | if (/[?*\{\[]+/.test(dir)) {
|
109 | try {
|
110 | var base = path.dirname(dir.replace(/([?*\{\[]+.*$)/, 'foo'));
|
111 | stat = fs.statSync(base);
|
112 | if (stat.isDirectory()) {
|
113 | return base;
|
114 | }
|
115 | } catch (error) {
|
116 |
|
117 | }
|
118 | } else {
|
119 | try {
|
120 | stat = fs.statSync(dir);
|
121 |
|
122 |
|
123 | if (stat.isFile() || stat.isDirectory()) {
|
124 | return dir;
|
125 | }
|
126 | } catch (e) { }
|
127 | }
|
128 |
|
129 | return false;
|
130 | }
|
131 |
|
132 | function match(files, monitor, ext) {
|
133 |
|
134 |
|
135 | const cwd = process.cwd();
|
136 | var rules = monitor.sort(function (a, b) {
|
137 | var r = b.split(path.sep).length - a.split(path.sep).length;
|
138 | var aIsIgnore = a.slice(0, 1) === '!';
|
139 | var bIsIgnore = b.slice(0, 1) === '!';
|
140 |
|
141 | if (aIsIgnore || bIsIgnore) {
|
142 | if (aIsIgnore) {
|
143 | return -1;
|
144 | }
|
145 |
|
146 | return 1;
|
147 | }
|
148 |
|
149 | if (r === 0) {
|
150 | return b.length - a.length;
|
151 | }
|
152 | return r;
|
153 | }).map(function (s) {
|
154 | var prefix = s.slice(0, 1);
|
155 |
|
156 | if (prefix === '!') {
|
157 | if (s.indexOf('!' + cwd) === 0) {
|
158 | return s;
|
159 | }
|
160 | return '!**' + (prefix !== path.sep ? path.sep : '') + s.slice(1);
|
161 | }
|
162 |
|
163 |
|
164 | if (s.indexOf('.') === 0) {
|
165 | return path.resolve(cwd, s);
|
166 | }
|
167 |
|
168 | if (s.indexOf(cwd) === 0) {
|
169 | return s;
|
170 | }
|
171 |
|
172 | return '**' + (prefix !== path.sep ? path.sep : '') + s;
|
173 | });
|
174 |
|
175 | debug('rules', rules);
|
176 |
|
177 | var good = [];
|
178 | var whitelist = [];
|
179 | var ignored = 0;
|
180 | var watched = 0;
|
181 | var usedRules = [];
|
182 | var minimatchOpts = {
|
183 | dot: true,
|
184 | };
|
185 |
|
186 |
|
187 | if (utils.isWindows) {
|
188 | minimatchOpts.nocase = true;
|
189 | }
|
190 |
|
191 | files.forEach(function (file) {
|
192 | file = path.resolve(cwd, file);
|
193 |
|
194 | var matched = false;
|
195 | for (var i = 0; i < rules.length; i++) {
|
196 | if (rules[i].slice(0, 1) === '!') {
|
197 | if (!minimatch(file, rules[i], minimatchOpts)) {
|
198 | ignored++;
|
199 | matched = true;
|
200 | break;
|
201 | }
|
202 | } else {
|
203 | debug('match', file, minimatch(file, rules[i], minimatchOpts));
|
204 | if (minimatch(file, rules[i], minimatchOpts)) {
|
205 | watched++;
|
206 |
|
207 |
|
208 | if (usedRules.indexOf(rules[i]) === -1) {
|
209 | usedRules.push(rules[i]);
|
210 | utils.log.detail('matched rule: ' + rules[i]);
|
211 | }
|
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 | if (rules[i] !== '**' + path.sep + '*.*' &&
|
218 | rules[i].slice(-3) === '*.*') {
|
219 | whitelist.push(file);
|
220 | } else if (path.basename(file) === path.basename(rules[i])) {
|
221 |
|
222 | whitelist.push(file);
|
223 | } else {
|
224 | good.push(file);
|
225 | }
|
226 | matched = true;
|
227 | break;
|
228 | } else {
|
229 |
|
230 | }
|
231 | }
|
232 | }
|
233 | if (!matched) {
|
234 | ignored++;
|
235 | }
|
236 | });
|
237 |
|
238 | debug('good', good)
|
239 |
|
240 |
|
241 | if (ext) {
|
242 | if (ext.indexOf(',') === -1) {
|
243 | ext = '**/*.' + ext;
|
244 | } else {
|
245 | ext = '**/*.{' + ext + '}';
|
246 | }
|
247 |
|
248 | good = good.filter(function (file) {
|
249 |
|
250 | return minimatch(path.basename(file), ext, minimatchOpts);
|
251 | });
|
252 | }
|
253 |
|
254 | var result = good.concat(whitelist);
|
255 |
|
256 | if (utils.isWindows) {
|
257 |
|
258 | result = result.map(function (file) {
|
259 | return file.slice(0, 1).toLowerCase() + file.slice(1);
|
260 | });
|
261 | }
|
262 |
|
263 | return {
|
264 | result: result,
|
265 | ignored: ignored,
|
266 | watched: watched,
|
267 | total: files.length,
|
268 | };
|
269 | }
|