nodemon-sudo 0.0.1-security → 3.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of nodemon-sudo might be problematic. Click here for more details.
- package/.prettierrc.json +3 -0
- package/LICENSE +21 -0
- package/README.md +437 -3
- package/bin/nodemon.js +16 -0
- package/bin/windows-kill.exe +0 -0
- package/doc/cli/authors.txt +8 -0
- package/doc/cli/config.txt +44 -0
- package/doc/cli/help.txt +29 -0
- package/doc/cli/logo.txt +20 -0
- package/doc/cli/options.txt +36 -0
- package/doc/cli/topics.txt +8 -0
- package/doc/cli/usage.txt +3 -0
- package/doc/cli/whoami.txt +9 -0
- package/index.d.ts +124 -0
- package/jsconfig.json +7 -0
- package/lib/cli/index.js +49 -0
- package/lib/cli/parse.js +230 -0
- package/lib/config/command.js +43 -0
- package/lib/config/defaults.js +34 -0
- package/lib/config/exec.js +240 -0
- package/lib/config/index.js +93 -0
- package/lib/config/load.js +225 -0
- package/lib/help/index.js +27 -0
- package/lib/index.js +1 -0
- package/lib/monitor/index.js +4 -0
- package/lib/monitor/match.js +288 -0
- package/lib/monitor/run.js +562 -0
- package/lib/monitor/signals.js +34 -0
- package/lib/monitor/watch.js +244 -0
- package/lib/nodemon.js +317 -0
- package/lib/rules/add.js +89 -0
- package/lib/rules/index.js +53 -0
- package/lib/rules/parse.js +43 -0
- package/lib/spawn.js +74 -0
- package/lib/utils/bus.js +44 -0
- package/lib/utils/clone.js +40 -0
- package/lib/utils/colour.js +26 -0
- package/lib/utils/index.js +103 -0
- package/lib/utils/log.js +82 -0
- package/lib/utils/merge.js +47 -0
- package/lib/version.js +100 -0
- package/package.json +78 -4
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
module.exports.watch = watch;
|
|
2
|
+
module.exports.resetWatchers = resetWatchers;
|
|
3
|
+
|
|
4
|
+
var debug = require('debug')('nodemon:watch');
|
|
5
|
+
var debugRoot = require('debug')('nodemon');
|
|
6
|
+
var chokidar = require('chokidar');
|
|
7
|
+
var undefsafe = require('undefsafe');
|
|
8
|
+
var config = require('../config');
|
|
9
|
+
var path = require('path');
|
|
10
|
+
var utils = require('../utils');
|
|
11
|
+
var bus = utils.bus;
|
|
12
|
+
var match = require('./match');
|
|
13
|
+
var watchers = [];
|
|
14
|
+
var debouncedBus;
|
|
15
|
+
|
|
16
|
+
bus.on('reset', resetWatchers);
|
|
17
|
+
|
|
18
|
+
function resetWatchers() {
|
|
19
|
+
debugRoot('resetting watchers');
|
|
20
|
+
watchers.forEach(function (watcher) {
|
|
21
|
+
watcher.close();
|
|
22
|
+
});
|
|
23
|
+
watchers = [];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function 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
|
+
|
|
137
|
+
function 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
|
+
|
|
223
|
+
function 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
|
+
|
|
236
|
+
function 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
|
+
}
|
package/lib/nodemon.js
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
var debug = require('debug')('nodemon');
|
|
2
|
+
var path = require('path');
|
|
3
|
+
var monitor = require('./monitor');
|
|
4
|
+
var cli = require('./cli');
|
|
5
|
+
var version = require('./version');
|
|
6
|
+
var util = require('util');
|
|
7
|
+
var utils = require('./utils');
|
|
8
|
+
var bus = utils.bus;
|
|
9
|
+
var help = require('./help');
|
|
10
|
+
/** @type {import('..').NodemonEventConfig} */
|
|
11
|
+
var config = require('./config');
|
|
12
|
+
var spawn = require('./spawn');
|
|
13
|
+
const defaults = require('./config/defaults')
|
|
14
|
+
var eventHandlers = {};
|
|
15
|
+
|
|
16
|
+
// this is fairly dirty, but theoretically sound since it's part of the
|
|
17
|
+
// stable module API
|
|
18
|
+
config.required = utils.isRequired;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {import('..').NodemonSettings | string} settings
|
|
22
|
+
* @returns {import('..').Nodemon}
|
|
23
|
+
*/
|
|
24
|
+
function nodemon(settings) {
|
|
25
|
+
bus.emit('boot');
|
|
26
|
+
nodemon.reset();
|
|
27
|
+
|
|
28
|
+
/** @type {import('..').NodemonSettings} */
|
|
29
|
+
let options
|
|
30
|
+
|
|
31
|
+
// allow the cli string as the argument to nodemon, and allow for
|
|
32
|
+
// `node nodemon -V app.js` or just `-V app.js`
|
|
33
|
+
if (typeof settings === 'string') {
|
|
34
|
+
settings = settings.trim();
|
|
35
|
+
if (settings.indexOf('node') !== 0) {
|
|
36
|
+
if (settings.indexOf('nodemon') !== 0) {
|
|
37
|
+
settings = 'nodemon ' + settings;
|
|
38
|
+
}
|
|
39
|
+
settings = 'node ' + settings;
|
|
40
|
+
}
|
|
41
|
+
options = cli.parse(settings);
|
|
42
|
+
} else options = settings;
|
|
43
|
+
|
|
44
|
+
// set the debug flag as early as possible to get all the detailed logging
|
|
45
|
+
if (options.verbose) {
|
|
46
|
+
utils.debug = true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (options.help) {
|
|
50
|
+
if (process.stdout.isTTY) {
|
|
51
|
+
process.stdout._handle.setBlocking(true); // nodejs/node#6456
|
|
52
|
+
}
|
|
53
|
+
console.log(help(options.help));
|
|
54
|
+
if (!config.required) {
|
|
55
|
+
process.exit(0);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (options.version) {
|
|
60
|
+
version().then(function (v) {
|
|
61
|
+
console.log(v);
|
|
62
|
+
if (!config.required) {
|
|
63
|
+
process.exit(0);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// nodemon tools like grunt-nodemon. This affects where
|
|
70
|
+
// the script is being run from, and will affect where
|
|
71
|
+
// nodemon looks for the nodemon.json files
|
|
72
|
+
if (options.cwd) {
|
|
73
|
+
// this is protection to make sure we haven't dont the chdir already...
|
|
74
|
+
// say like in cli/parse.js (which is where we do this once already!)
|
|
75
|
+
if (process.cwd() !== path.resolve(config.system.cwd, options.cwd)) {
|
|
76
|
+
process.chdir(options.cwd);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
config.load(options, function (config) {
|
|
81
|
+
if (!config.options.dump && !config.options.execOptions.script &&
|
|
82
|
+
config.options.execOptions.exec === 'node') {
|
|
83
|
+
if (!config.required) {
|
|
84
|
+
console.log(help('usage'));
|
|
85
|
+
process.exit();
|
|
86
|
+
}
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// before we print anything, update the colour setting on logging
|
|
91
|
+
utils.colours = config.options.colours;
|
|
92
|
+
|
|
93
|
+
// always echo out the current version
|
|
94
|
+
utils.log.info(version.pinned);
|
|
95
|
+
|
|
96
|
+
const cwd = process.cwd();
|
|
97
|
+
|
|
98
|
+
if (config.options.cwd) {
|
|
99
|
+
utils.log.detail('process root: ' + cwd);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
config.loaded.map(file => file.replace(cwd, '.')).forEach(file => {
|
|
103
|
+
utils.log.detail('reading config ' + file);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
if (config.options.stdin && config.options.restartable) {
|
|
107
|
+
// allow nodemon to restart when the use types 'rs\n'
|
|
108
|
+
process.stdin.resume();
|
|
109
|
+
process.stdin.setEncoding('utf8');
|
|
110
|
+
process.stdin.on('data', data => {
|
|
111
|
+
const str = data.toString().trim().toLowerCase();
|
|
112
|
+
|
|
113
|
+
// if the keys entered match the restartable value, then restart!
|
|
114
|
+
if (str === config.options.restartable) {
|
|
115
|
+
bus.emit('restart');
|
|
116
|
+
} else if (data.charCodeAt(0) === 12) { // ctrl+l
|
|
117
|
+
console.clear();
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
} else if (config.options.stdin) {
|
|
121
|
+
// so let's make sure we don't eat the key presses
|
|
122
|
+
// but also, since we're wrapping, watch out for
|
|
123
|
+
// special keys, like ctrl+c x 2 or '.exit' or ctrl+d or ctrl+l
|
|
124
|
+
var ctrlC = false;
|
|
125
|
+
var buffer = '';
|
|
126
|
+
|
|
127
|
+
process.stdin.on('data', function (data) {
|
|
128
|
+
data = data.toString();
|
|
129
|
+
buffer += data;
|
|
130
|
+
const chr = data.charCodeAt(0);
|
|
131
|
+
|
|
132
|
+
// if restartable, echo back
|
|
133
|
+
if (chr === 3) {
|
|
134
|
+
if (ctrlC) {
|
|
135
|
+
process.exit(0);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
ctrlC = true;
|
|
139
|
+
return;
|
|
140
|
+
} else if (buffer === '.exit' || chr === 4) { // ctrl+d
|
|
141
|
+
process.exit();
|
|
142
|
+
} else if (chr === 13 || chr === 10) { // enter / carriage return
|
|
143
|
+
buffer = '';
|
|
144
|
+
} else if (chr === 12) { // ctrl+l
|
|
145
|
+
console.clear();
|
|
146
|
+
buffer = '';
|
|
147
|
+
}
|
|
148
|
+
ctrlC = false;
|
|
149
|
+
});
|
|
150
|
+
if (process.stdin.setRawMode) {
|
|
151
|
+
process.stdin.setRawMode(true);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (config.options.restartable) {
|
|
156
|
+
utils.log.info('to restart at any time, enter `' +
|
|
157
|
+
config.options.restartable + '`');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (!config.required) {
|
|
161
|
+
const restartSignal = config.options.signal === 'SIGUSR2' ? 'SIGHUP' : 'SIGUSR2';
|
|
162
|
+
process.on(restartSignal, nodemon.restart);
|
|
163
|
+
utils.bus.on('error', () => {
|
|
164
|
+
utils.log.fail((new Error().stack));
|
|
165
|
+
});
|
|
166
|
+
utils.log.detail((config.options.restartable ? 'or ' : '') + 'send ' +
|
|
167
|
+
restartSignal + ' to ' + process.pid + ' to restart');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const ignoring = config.options.monitor.map(function (rule) {
|
|
171
|
+
if (rule.slice(0, 1) !== '!') {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
rule = rule.slice(1);
|
|
176
|
+
|
|
177
|
+
// don't notify of default ignores
|
|
178
|
+
if (defaults.ignoreRoot.indexOf(rule) !== -1) {
|
|
179
|
+
return false;
|
|
180
|
+
// return rule.slice(3).slice(0, -3);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (rule.startsWith(cwd)) {
|
|
184
|
+
return rule.replace(cwd, '.');
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return rule;
|
|
188
|
+
}).filter(Boolean).join(' ');
|
|
189
|
+
if (ignoring) utils.log.detail('ignoring: ' + ignoring);
|
|
190
|
+
|
|
191
|
+
utils.log.info('watching path(s): ' + config.options.monitor.map(function (rule) {
|
|
192
|
+
if (rule.slice(0, 1) !== '!') {
|
|
193
|
+
try {
|
|
194
|
+
rule = path.relative(process.cwd(), rule);
|
|
195
|
+
} catch (e) {}
|
|
196
|
+
|
|
197
|
+
return rule;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return false;
|
|
201
|
+
}).filter(Boolean).join(' '));
|
|
202
|
+
|
|
203
|
+
utils.log.info('watching extensions: ' + (config.options.execOptions.ext || '(all)'));
|
|
204
|
+
|
|
205
|
+
if (config.options.dump) {
|
|
206
|
+
utils.log._log('log', '--------------');
|
|
207
|
+
utils.log._log('log', 'node: ' + process.version);
|
|
208
|
+
utils.log._log('log', 'nodemon: ' + version.pinned);
|
|
209
|
+
utils.log._log('log', 'command: ' + process.argv.join(' '));
|
|
210
|
+
utils.log._log('log', 'cwd: ' + cwd);
|
|
211
|
+
utils.log._log('log', ['OS:', process.platform, process.arch].join(' '));
|
|
212
|
+
utils.log._log('log', '--------------');
|
|
213
|
+
utils.log._log('log', util.inspect(config, { depth: null }));
|
|
214
|
+
utils.log._log('log', '--------------');
|
|
215
|
+
if (!config.required) {
|
|
216
|
+
process.exit();
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
config.run = true;
|
|
223
|
+
|
|
224
|
+
if (config.options.stdout === false) {
|
|
225
|
+
nodemon.on('start', function () {
|
|
226
|
+
nodemon.stdout = bus.stdout;
|
|
227
|
+
nodemon.stderr = bus.stderr;
|
|
228
|
+
|
|
229
|
+
bus.emit('readable');
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (config.options.events && Object.keys(config.options.events).length) {
|
|
234
|
+
Object.keys(config.options.events).forEach(function (key) {
|
|
235
|
+
utils.log.detail('bind ' + key + ' -> `' +
|
|
236
|
+
config.options.events[key] + '`');
|
|
237
|
+
nodemon.on(key, function () {
|
|
238
|
+
if (config.options && config.options.events) {
|
|
239
|
+
spawn(config.options.events[key], config,
|
|
240
|
+
[].slice.apply(arguments));
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
monitor.run(config.options);
|
|
247
|
+
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
return nodemon;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
nodemon.restart = function () {
|
|
254
|
+
utils.log.status('restarting child process');
|
|
255
|
+
bus.emit('restart');
|
|
256
|
+
return nodemon;
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
nodemon.addListener = nodemon.on = function (event, handler) {
|
|
260
|
+
if (!eventHandlers[event]) { eventHandlers[event] = []; }
|
|
261
|
+
eventHandlers[event].push(handler);
|
|
262
|
+
bus.on(event, handler);
|
|
263
|
+
return nodemon;
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
nodemon.once = function (event, handler) {
|
|
267
|
+
if (!eventHandlers[event]) { eventHandlers[event] = []; }
|
|
268
|
+
eventHandlers[event].push(handler);
|
|
269
|
+
bus.once(event, function () {
|
|
270
|
+
debug('bus.once(%s)', event);
|
|
271
|
+
eventHandlers[event].splice(eventHandlers[event].indexOf(handler), 1);
|
|
272
|
+
handler.apply(this, arguments);
|
|
273
|
+
});
|
|
274
|
+
return nodemon;
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
nodemon.emit = function () {
|
|
278
|
+
bus.emit.apply(bus, [].slice.call(arguments));
|
|
279
|
+
return nodemon;
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
nodemon.removeAllListeners = function (event) {
|
|
283
|
+
// unbind only the `nodemon.on` event handlers
|
|
284
|
+
Object.keys(eventHandlers).filter(function (e) {
|
|
285
|
+
return event ? e === event : true;
|
|
286
|
+
}).forEach(function (event) {
|
|
287
|
+
eventHandlers[event].forEach(function (handler) {
|
|
288
|
+
bus.removeListener(event, handler);
|
|
289
|
+
eventHandlers[event].splice(eventHandlers[event].indexOf(handler), 1);
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
return nodemon;
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
nodemon.reset = function (done) {
|
|
297
|
+
bus.emit('reset', done);
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
bus.on('reset', function (done) {
|
|
301
|
+
debug('reset');
|
|
302
|
+
nodemon.removeAllListeners();
|
|
303
|
+
monitor.run.kill(true, function () {
|
|
304
|
+
utils.reset();
|
|
305
|
+
config.reset();
|
|
306
|
+
config.run = false;
|
|
307
|
+
if (done) {
|
|
308
|
+
done();
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
// expose the full config
|
|
314
|
+
nodemon.config = config;
|
|
315
|
+
|
|
316
|
+
module.exports = nodemon;
|
|
317
|
+
|
package/lib/rules/add.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var utils = require('../utils');
|
|
4
|
+
|
|
5
|
+
// internal
|
|
6
|
+
var reEscComments = /\\#/g;
|
|
7
|
+
// note that '^^' is used in place of escaped comments
|
|
8
|
+
var reUnescapeComments = /\^\^/g;
|
|
9
|
+
var reComments = /#.*$/;
|
|
10
|
+
var reEscapeChars = /[.|\-[\]()\\]/g;
|
|
11
|
+
var reAsterisk = /\*/g;
|
|
12
|
+
|
|
13
|
+
module.exports = add;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Converts file patterns or regular expressions to nodemon
|
|
17
|
+
* compatible RegExp matching rules. Note: the `rules` argument
|
|
18
|
+
* object is modified to include the new rule and new RegExp
|
|
19
|
+
*
|
|
20
|
+
* ### Example:
|
|
21
|
+
*
|
|
22
|
+
* var rules = { watch: [], ignore: [] };
|
|
23
|
+
* add(rules, 'watch', '*.js');
|
|
24
|
+
* add(rules, 'ignore', '/public/');
|
|
25
|
+
* add(rules, 'watch', ':(\d)*\.js'); // note: string based regexp
|
|
26
|
+
* add(rules, 'watch', /\d*\.js/);
|
|
27
|
+
*
|
|
28
|
+
* @param {Object} rules containing `watch` and `ignore`. Also updated during
|
|
29
|
+
* execution
|
|
30
|
+
* @param {String} which must be either "watch" or "ignore"
|
|
31
|
+
* @param {String|RegExp} rule the actual rule.
|
|
32
|
+
*/
|
|
33
|
+
function add(rules, which, rule) {
|
|
34
|
+
if (!{ ignore: 1, watch: 1}[which]) {
|
|
35
|
+
throw new Error('rules/index.js#add requires "ignore" or "watch" as the ' +
|
|
36
|
+
'first argument');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (Array.isArray(rule)) {
|
|
40
|
+
rule.forEach(function (rule) {
|
|
41
|
+
add(rules, which, rule);
|
|
42
|
+
});
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// support the rule being a RegExp, but reformat it to
|
|
47
|
+
// the custom :<regexp> format that we're working with.
|
|
48
|
+
if (rule instanceof RegExp) {
|
|
49
|
+
// rule = ':' + rule.toString().replace(/^\/(.*?)\/$/g, '$1');
|
|
50
|
+
utils.log.error('RegExp format no longer supported, but globs are.');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// remove comments and trim lines
|
|
55
|
+
// this mess of replace methods is escaping "\#" to allow for emacs temp files
|
|
56
|
+
|
|
57
|
+
// first up strip comments and remove blank head or tails
|
|
58
|
+
rule = (rule || '').replace(reEscComments, '^^')
|
|
59
|
+
.replace(reComments, '')
|
|
60
|
+
.replace(reUnescapeComments, '#').trim();
|
|
61
|
+
|
|
62
|
+
var regexp = false;
|
|
63
|
+
|
|
64
|
+
if (typeof rule === 'string' && rule.substring(0, 1) === ':') {
|
|
65
|
+
rule = rule.substring(1);
|
|
66
|
+
utils.log.error('RegExp no longer supported: ' + rule);
|
|
67
|
+
regexp = true;
|
|
68
|
+
} else if (rule.length === 0) {
|
|
69
|
+
// blank line (or it was a comment)
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (regexp) {
|
|
74
|
+
// rules[which].push(rule);
|
|
75
|
+
} else {
|
|
76
|
+
// rule = rule.replace(reEscapeChars, '\\$&')
|
|
77
|
+
// .replace(reAsterisk, '.*');
|
|
78
|
+
|
|
79
|
+
rules[which].push(rule);
|
|
80
|
+
// compile a regexp of all the rules for this ignore or watch
|
|
81
|
+
var re = rules[which].map(function (rule) {
|
|
82
|
+
return rule.replace(reEscapeChars, '\\$&')
|
|
83
|
+
.replace(reAsterisk, '.*');
|
|
84
|
+
}).join('|');
|
|
85
|
+
|
|
86
|
+
// used for the directory matching
|
|
87
|
+
rules[which].re = new RegExp(re);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
var utils = require('../utils');
|
|
3
|
+
var add = require('./add');
|
|
4
|
+
var parse = require('./parse');
|
|
5
|
+
|
|
6
|
+
// exported
|
|
7
|
+
var rules = { ignore: [], watch: [] };
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Loads a nodemon config file and populates the ignore
|
|
11
|
+
* and watch rules with it's contents, and calls callback
|
|
12
|
+
* with the new rules
|
|
13
|
+
*
|
|
14
|
+
* @param {String} filename
|
|
15
|
+
* @param {Function} callback
|
|
16
|
+
*/
|
|
17
|
+
function load(filename, callback) {
|
|
18
|
+
parse(filename, function (err, result) {
|
|
19
|
+
if (err) {
|
|
20
|
+
// we should have bombed already, but
|
|
21
|
+
utils.log.error(err);
|
|
22
|
+
callback(err);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (result.raw) {
|
|
26
|
+
result.raw.forEach(add.bind(null, rules, 'ignore'));
|
|
27
|
+
} else {
|
|
28
|
+
result.ignore.forEach(add.bind(null, rules, 'ignore'));
|
|
29
|
+
result.watch.forEach(add.bind(null, rules, 'watch'));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
callback(null, rules);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = {
|
|
37
|
+
reset: function () { // just used for testing
|
|
38
|
+
rules.ignore.length = rules.watch.length = 0;
|
|
39
|
+
delete rules.ignore.re;
|
|
40
|
+
delete rules.watch.re;
|
|
41
|
+
},
|
|
42
|
+
load: load,
|
|
43
|
+
ignore: {
|
|
44
|
+
test: add.bind(null, rules, 'ignore'),
|
|
45
|
+
add: add.bind(null, rules, 'ignore'),
|
|
46
|
+
},
|
|
47
|
+
watch: {
|
|
48
|
+
test: add.bind(null, rules, 'watch'),
|
|
49
|
+
add: add.bind(null, rules, 'watch'),
|
|
50
|
+
},
|
|
51
|
+
add: add.bind(null, rules),
|
|
52
|
+
rules: rules,
|
|
53
|
+
};
|