UNPKG

8.61 kBJavaScriptView Raw
1var debug = require('debug')('nodemon');
2var path = require('path');
3var monitor = require('./monitor');
4var cli = require('./cli');
5var version = require('./version');
6var util = require('util');
7var utils = require('./utils');
8var bus = utils.bus;
9var help = require('./help');
10var config = require('./config');
11var spawn = require('./spawn');
12const defaults = require('./config/defaults')
13var eventHandlers = {};
14
15// this is fairly dirty, but theoretically sound since it's part of the
16// stable module API
17config.required = utils.isRequired;
18
19function nodemon(settings) {
20 bus.emit('boot');
21 nodemon.reset();
22
23 // allow the cli string as the argument to nodemon, and allow for
24 // `node nodemon -V app.js` or just `-V app.js`
25 if (typeof settings === 'string') {
26 settings = settings.trim();
27 if (settings.indexOf('node') !== 0) {
28 if (settings.indexOf('nodemon') !== 0) {
29 settings = 'nodemon ' + settings;
30 }
31 settings = 'node ' + settings;
32 }
33 settings = cli.parse(settings);
34 }
35
36 // set the debug flag as early as possible to get all the detailed logging
37 if (settings.verbose) {
38 utils.debug = true;
39 }
40
41 if (settings.help) {
42 process.stdout._handle.setBlocking(true); // nodejs/node#6456
43 console.log(help(settings.help));
44 if (!config.required) {
45 process.exit(0);
46 }
47 }
48
49 if (settings.version) {
50 version().then(function (v) {
51 console.log(v);
52 if (!config.required) {
53 process.exit(0);
54 }
55 });
56 return;
57 }
58
59 // nodemon tools like grunt-nodemon. This affects where
60 // the script is being run from, and will affect where
61 // nodemon looks for the nodemon.json files
62 if (settings.cwd) {
63 // this is protection to make sure we haven't dont the chdir already...
64 // say like in cli/parse.js (which is where we do this once already!)
65 if (process.cwd() !== path.resolve(config.system.cwd, settings.cwd)) {
66 process.chdir(settings.cwd);
67 }
68 }
69
70 const cwd = process.cwd();
71
72 config.load(settings, function (config) {
73 if (!config.options.dump && !config.options.execOptions.script &&
74 config.options.execOptions.exec === 'node') {
75 if (!config.required) {
76 console.log(help('usage'));
77 process.exit();
78 }
79 return;
80 }
81
82 // before we print anything, update the colour setting on logging
83 utils.colours = config.options.colours;
84
85 // always echo out the current version
86 utils.log.info(version.pinned);
87
88 const cwd = process.cwd();
89
90 if (config.options.cwd) {
91 utils.log.detail('process root: ' + cwd);
92 }
93
94 config.loaded.map(file => file.replace(cwd, '.')).forEach(file => {
95 utils.log.detail('reading config ' + file);
96 });
97
98 if (config.options.stdin && config.options.restartable) {
99 // allow nodemon to restart when the use types 'rs\n'
100 process.stdin.resume();
101 process.stdin.setEncoding('utf8');
102 process.stdin.on('data', data => {
103 const str = data.toString().trim().toLowerCase();
104
105 // if the keys entered match the restartable value, then restart!
106 if (str === config.options.restartable) {
107 bus.emit('restart');
108 } else if (data.charCodeAt(0) === 12) { // ctrl+l
109 console.clear();
110 }
111 });
112 } else if (config.options.stdin) {
113 // so let's make sure we don't eat the key presses
114 // but also, since we're wrapping, watch out for
115 // special keys, like ctrl+c x 2 or '.exit' or ctrl+d or ctrl+l
116 var ctrlC = false;
117 var buffer = '';
118
119 process.stdin.on('data', function (data) {
120 data = data.toString();
121 buffer += data;
122 const chr = data.charCodeAt(0);
123
124 // if restartable, echo back
125 if (chr === 3) {
126 if (ctrlC) {
127 process.exit(0);
128 }
129
130 ctrlC = true;
131 return;
132 } else if (buffer === '.exit' || chr === 4) { // ctrl+d
133 process.exit();
134 } else if (chr === 13 || chr === 10) { // enter / carriage return
135 buffer = '';
136 } else if (chr === 12) { // ctrl+l
137 console.clear();
138 buffer = '';
139 }
140 ctrlC = false;
141 });
142 if (process.stdin.setRawMode) {
143 process.stdin.setRawMode(true);
144 }
145 }
146
147 if (config.options.restartable) {
148 utils.log.info('to restart at any time, enter `' +
149 config.options.restartable + '`');
150 }
151
152 if (!config.required) {
153 const restartSignal = config.options.signal === 'SIGUSR2' ? 'SIGHUP' : 'SIGUSR2';
154 process.on(restartSignal, nodemon.restart);
155 utils.bus.on('error', () => {
156 utils.log.fail((new Error().stack));
157 });
158 utils.log.detail((config.options.restartable ? 'or ' : '') + 'send ' +
159 restartSignal + ' to ' + process.pid + ' to restart');
160 }
161
162 const ignoring = config.options.monitor.map(function (rule) {
163 if (rule.slice(0, 1) !== '!') {
164 return false;
165 }
166
167 rule = rule.slice(1);
168
169 // don't notify of default ignores
170 if (defaults.ignoreRoot.indexOf(rule) !== -1) {
171 return false;
172 return rule.slice(3).slice(0, -3);
173 }
174
175 if (rule.startsWith(cwd)) {
176 return rule.replace(cwd, '.');
177 }
178
179 return rule;
180 }).filter(Boolean).join(' ');
181 if (ignoring) utils.log.detail('ignoring: ' + ignoring);
182
183 utils.log.info('watching: ' + config.options.monitor.map(function (rule) {
184 return rule.slice(0, 1) !== '!' ? rule : false;
185 }).filter(Boolean).join(' '));
186
187 utils.log.detail('watching extensions: ' + (config.options.execOptions.ext || '(all)'));
188
189 if (config.options.dump) {
190 utils.log._log('log', '--------------');
191 utils.log._log('log', 'node: ' + process.version);
192 utils.log._log('log', 'nodemon: ' + version.pinned);
193 utils.log._log('log', 'command: ' + process.argv.join(' '));
194 utils.log._log('log', 'cwd: ' + cwd);
195 utils.log._log('log', ['OS:', process.platform, process.arch].join(' '));
196 utils.log._log('log', '--------------');
197 utils.log._log('log', util.inspect(config, { depth: null }));
198 utils.log._log('log', '--------------');
199 if (!config.required) {
200 process.exit();
201 }
202
203 return;
204 }
205
206 config.run = true;
207
208 if (config.options.stdout === false) {
209 nodemon.on('start', function () {
210 nodemon.stdout = bus.stdout;
211 nodemon.stderr = bus.stderr;
212
213 bus.emit('readable');
214 });
215 }
216
217 if (config.options.events && Object.keys(config.options.events).length) {
218 Object.keys(config.options.events).forEach(function (key) {
219 utils.log.detail('bind ' + key + ' -> `' +
220 config.options.events[key] + '`');
221 nodemon.on(key, function () {
222 if (config.options && config.options.events) {
223 spawn(config.options.events[key], config,
224 [].slice.apply(arguments));
225 }
226 });
227 });
228 }
229
230 monitor.run(config.options);
231
232 });
233
234 return nodemon;
235}
236
237nodemon.restart = function () {
238 utils.log.status('restarting child process');
239 bus.emit('restart');
240 return nodemon;
241};
242
243nodemon.addListener = nodemon.on = function (event, handler) {
244 if (!eventHandlers[event]) { eventHandlers[event] = []; }
245 eventHandlers[event].push(handler);
246 bus.on(event, handler);
247 return nodemon;
248};
249
250nodemon.once = function (event, handler) {
251 if (!eventHandlers[event]) { eventHandlers[event] = []; }
252 eventHandlers[event].push(handler);
253 bus.once(event, function () {
254 debug('bus.once(%s)', event);
255 eventHandlers[event].splice(eventHandlers[event].indexOf(handler), 1);
256 handler.apply(this, arguments);
257 });
258 return nodemon;
259};
260
261nodemon.emit = function () {
262 bus.emit.apply(bus, [].slice.call(arguments));
263 return nodemon;
264};
265
266nodemon.removeAllListeners = function (event) {
267 // unbind only the `nodemon.on` event handlers
268 Object.keys(eventHandlers).filter(function (e) {
269 return event ? e === event : true;
270 }).forEach(function (event) {
271 eventHandlers[event].forEach(function (handler) {
272 bus.removeListener(event, handler);
273 eventHandlers[event].splice(eventHandlers[event].indexOf(handler), 1);
274 });
275 });
276
277 return nodemon;
278};
279
280nodemon.reset = function (done) {
281 bus.emit('reset', done);
282};
283
284bus.on('reset', function (done) {
285 debug('reset');
286 nodemon.removeAllListeners();
287 monitor.run.kill(true, function () {
288 utils.reset();
289 config.reset();
290 config.run = false;
291 if (done) {
292 done();
293 }
294 });
295});
296
297// expose the full config
298nodemon.config = config;
299
300module.exports = nodemon;
301