source: node_modules/nodemon/lib/monitor/watch.js@ 81bc7da

finki-main main
Last change on this file since 81bc7da was 81bc7da, checked in by Klimentina Efremova <klimentina08642@…>, 3 months ago

Initial commit

  • Property mode set to 100644
File size: 6.4 KB
Line 
1module.exports.watch = watch;
2module.exports.resetWatchers = resetWatchers;
3
4var debug = require('debug')('nodemon:watch');
5var debugRoot = require('debug')('nodemon');
6var chokidar = require('chokidar');
7var undefsafe = require('undefsafe');
8var config = require('../config');
9var path = require('path');
10var utils = require('../utils');
11var bus = utils.bus;
12var match = require('./match');
13var watchers = [];
14var debouncedBus;
15
16bus.on('reset', resetWatchers);
17
18function resetWatchers() {
19 debugRoot('resetting watchers');
20 watchers.forEach(function (watcher) {
21 watcher.close();
22 });
23 watchers = [];
24}
25
26function watch() {
27 if (watchers.length) {
28 debug('early exit on watch, still watching (%s)', watchers.length);
29 return;
30 }
31
32 var dirs = [].slice.call(config.dirs);
33
34 debugRoot('start watch on: %s', dirs.join(', '));
35 const rootIgnored = config.options.ignore;
36 debugRoot('ignored', rootIgnored);
37
38 var watchedFiles = [];
39
40 const promise = new Promise(function (resolve) {
41 const dotFilePattern = /[/\\]\./;
42 var ignored = match.rulesToMonitor(
43 [], // not needed
44 Array.from(rootIgnored),
45 config
46 ).map(pattern => pattern.slice(1));
47
48 const addDotFile = dirs.filter(dir => dir.match(dotFilePattern));
49
50 // don't ignore dotfiles if explicitly watched.
51 if (addDotFile.length === 0) {
52 ignored.push(dotFilePattern);
53 }
54
55 var watchOptions = {
56 ignorePermissionErrors: true,
57 ignored: ignored,
58 persistent: true,
59 usePolling: config.options.legacyWatch || false,
60 interval: config.options.pollingInterval,
61 // note to future developer: I've gone back and forth on adding `cwd`
62 // to the props and in some cases it fixes bugs but typically it causes
63 // bugs elsewhere (since nodemon is used is so many ways). the final
64 // decision is to *not* use it at all and work around it
65 // cwd: ...
66 };
67
68 if (utils.isWindows) {
69 watchOptions.disableGlobbing = true;
70 }
71
72 if (utils.isIBMi) {
73 watchOptions.usePolling = true;
74 }
75
76 if (process.env.TEST) {
77 watchOptions.useFsEvents = false;
78 }
79
80 var watcher = chokidar.watch(
81 dirs,
82 Object.assign({}, watchOptions, config.options.watchOptions || {})
83 );
84
85 watcher.ready = false;
86
87 var total = 0;
88
89 watcher.on('change', filterAndRestart);
90 watcher.on('unlink', filterAndRestart);
91 watcher.on('add', function (file) {
92 if (watcher.ready) {
93 return filterAndRestart(file);
94 }
95
96 watchedFiles.push(file);
97 bus.emit('watching', file);
98 debug('chokidar watching: %s', file);
99 });
100 watcher.on('ready', function () {
101 watchedFiles = Array.from(new Set(watchedFiles)); // ensure no dupes
102 total = watchedFiles.length;
103 watcher.ready = true;
104 resolve(total);
105 debugRoot('watch is complete');
106 });
107
108 watcher.on('error', function (error) {
109 if (error.code === 'EINVAL') {
110 utils.log.error(
111 'Internal watch failed. Likely cause: too many ' +
112 'files being watched (perhaps from the root of a drive?\n' +
113 'See https://github.com/paulmillr/chokidar/issues/229 for details'
114 );
115 } else {
116 utils.log.error('Internal watch failed: ' + error.message);
117 process.exit(1);
118 }
119 });
120
121 watchers.push(watcher);
122 });
123
124 return promise.catch(e => {
125 // this is a core error and it should break nodemon - so I have to break
126 // out of a promise using the setTimeout
127 setTimeout(() => {
128 throw e;
129 });
130 }).then(function () {
131 utils.log.detail(`watching ${watchedFiles.length} file${
132 watchedFiles.length === 1 ? '' : 's'}`);
133 return watchedFiles;
134 });
135}
136
137function filterAndRestart(files) {
138 if (!Array.isArray(files)) {
139 files = [files];
140 }
141
142 if (files.length) {
143 var cwd = process.cwd();
144 if (this.options && this.options.cwd) {
145 cwd = this.options.cwd;
146 }
147
148 utils.log.detail(
149 'files triggering change check: ' +
150 files
151 .map(file => {
152 const res = path.relative(cwd, file);
153 return res;
154 })
155 .join(', ')
156 );
157
158 // make sure the path is right and drop an empty
159 // filenames (sometimes on windows)
160 files = files.filter(Boolean).map(file => {
161 return path.relative(process.cwd(), path.relative(cwd, file));
162 });
163
164 if (utils.isWindows) {
165 // ensure the drive letter is in uppercase (c:\foo -> C:\foo)
166 files = files.map(f => {
167 if (f.indexOf(':') === -1) { return f; }
168 return f[0].toUpperCase() + f.slice(1);
169 });
170 }
171
172
173 debug('filterAndRestart on', files);
174
175 var matched = match(
176 files,
177 config.options.monitor,
178 undefsafe(config, 'options.execOptions.ext')
179 );
180
181 debug('matched?', JSON.stringify(matched));
182
183 // if there's no matches, then test to see if the changed file is the
184 // running script, if so, let's allow a restart
185 if (config.options.execOptions && config.options.execOptions.script) {
186 const script = path.resolve(config.options.execOptions.script);
187 if (matched.result.length === 0 && script) {
188 const length = script.length;
189 files.find(file => {
190 if (file.substr(-length, length) === script) {
191 matched = {
192 result: [file],
193 total: 1,
194 };
195 return true;
196 }
197 });
198 }
199 }
200
201 utils.log.detail(
202 'changes after filters (before/after): ' +
203 [files.length, matched.result.length].join('/')
204 );
205
206 // reset the last check so we're only looking at recently modified files
207 config.lastStarted = Date.now();
208
209 if (matched.result.length) {
210 if (config.options.delay > 0) {
211 utils.log.detail('delaying restart for ' + config.options.delay + 'ms');
212 if (debouncedBus === undefined) {
213 debouncedBus = debounce(restartBus, config.options.delay);
214 }
215 debouncedBus(matched);
216 } else {
217 return restartBus(matched);
218 }
219 }
220 }
221}
222
223function restartBus(matched) {
224 utils.log.status('restarting due to changes...');
225 matched.result.map(file => {
226 utils.log.detail(path.relative(process.cwd(), file));
227 });
228
229 if (config.options.verbose) {
230 utils.log._log('');
231 }
232
233 bus.emit('restart', matched.result);
234}
235
236function debounce(fn, delay) {
237 var timer = null;
238 return function () {
239 const context = this;
240 const args = arguments;
241 clearTimeout(timer);
242 timer = setTimeout(() =>fn.apply(context, args), delay);
243 };
244}
Note: See TracBrowser for help on using the repository browser.