UNPKG

6.04 kBJavaScriptView Raw
1/*
2
3nodemon is a utility for node, and replaces the use of the executable
4node. So the user calls `nodemon foo.js` instead.
5
6nodemon can be run in a number of ways:
7
8`nodemon` - tries to use package.json#main property to run
9`nodemon` - if no package, looks for index.js
10`nodemon app.js` - runs app.js
11`nodemon --arg app.js --apparg` - eats arg1, and runs app.js with apparg
12`nodemon --apparg` - as above, but passes apparg to package.json#main (or
13 index.js)
14`nodemon --debug app.js
15
16*/
17
18var fs = require('fs');
19var path = require('path');
20var existsSync = fs.existsSync || path.existsSync;
21
22module.exports = parse;
23
24/**
25 * Parses the command line arguments `process.argv` and returns the
26 * nodemon options, the user script and the executable script.
27 *
28 * @param {Array} full process arguments, including `node` leading arg
29 * @return {Object} { options, script, args }
30 */
31function parse(argv) {
32 if (typeof argv === 'string') {
33 argv = argv.split(' ');
34 }
35
36 var eat = function (i, args) {
37 if (i <= args.length) {
38 return args.splice(i + 1, 1).pop();
39 }
40 };
41
42 var args = argv.slice(2);
43 var script = null;
44 var nodemonOptions = { scriptPosition: null };
45
46 var nodemonOpt = nodemonOption.bind(null, nodemonOptions);
47 var lookForArgs = true;
48
49 // move forward through the arguments
50 for (var i = 0; i < args.length; i++) {
51 // if the argument looks like a file, then stop eating
52 if (!script) {
53 if (args[i] === '.' || existsSync(args[i])) {
54 script = args.splice(i, 1).pop();
55
56 // we capture the position of the script because we'll reinsert it in
57 // the right place in run.js:command (though I'm not sure we should even
58 // take it out of the array in the first place, but this solves passing
59 // arguments to the exec process for now).
60 nodemonOptions.scriptPosition = i;
61 i--;
62 continue;
63 }
64 }
65
66 if (lookForArgs) {
67 // respect the standard way of saying: hereafter belongs to my script
68 if (args[i] === '--') {
69 args.splice(i, 1);
70 nodemonOptions.scriptPosition = i;
71 // cycle back one argument, as we just ate this one up
72 i--;
73
74 // ignore all further nodemon arguments
75 lookForArgs = false;
76
77 // move to the next iteration
78 continue;
79 }
80
81 if (nodemonOpt(args[i], eat.bind(null, i, args)) !== false) {
82 args.splice(i, 1);
83 // cycle back one argument, as we just ate this one up
84 i--;
85 }
86 }
87 }
88
89 nodemonOptions.script = script;
90 nodemonOptions.args = args;
91
92 return nodemonOptions;
93}
94
95
96/**
97 * Given an argument (ie. from process.argv), sets nodemon
98 * options and can eat up the argument value
99 *
100 * @param {Object} options object that will be updated
101 * @param {Sting} current argument from argv
102 * @param {Function} the callback to eat up the next argument in argv
103 * @return {Boolean} false if argument was not a nodemon arg
104 */
105function nodemonOption(options, arg, eatNext) {
106 // line separation on purpose to help legibility
107 if (arg === '--help' || arg === '-h' || arg === '-?') {
108 var help = eatNext();
109 options.help = help ? help : true;
110 } else
111
112 if (arg === '--version' || arg === '-v') {
113 options.version = true;
114 } else
115
116 if (arg === '--no-update-notifier') {
117 options.noUpdateNotifier = true;
118 } else
119
120 if (arg === '--spawn') {
121 options.spawn = true;
122 } else
123
124 if (arg === '--dump') {
125 options.dump = true;
126 } else
127
128 if (arg === '--verbose' || arg === '-V') {
129 options.verbose = true;
130 } else
131
132 if (arg === '--legacy-watch' || arg === '-L') {
133 options.legacyWatch = true;
134 } else
135
136 if (arg === '--polling-interval' || arg === '-P') {
137 options.pollingInterval = parseInt(eatNext(), 10);
138 } else
139
140 // Depricated as this is "on" by default
141 if (arg === '--js') {
142 options.js = true;
143 } else
144
145 if (arg === '--quiet' || arg === '-q') {
146 options.quiet = true;
147 } else
148
149 if (arg === '--config') {
150 options.configFile = eatNext();
151 } else
152
153 if (arg === '--watch' || arg === '-w') {
154 if (!options.watch) { options.watch = []; }
155 options.watch.push(eatNext());
156 } else
157
158 if (arg === '--ignore' || arg === '-i') {
159 if (!options.ignore) { options.ignore = []; }
160 options.ignore.push(eatNext());
161 } else
162
163 if (arg === '--exitcrash') {
164 options.exitcrash = true;
165 } else
166
167 if (arg === '--delay' || arg === '-d') {
168 options.delay = parseDelay(eatNext());
169 } else
170
171 if (arg === '--exec' || arg === '-x') {
172 options.exec = eatNext();
173 } else
174
175 if (arg === '--no-stdin' || arg === '-I') {
176 options.stdin = false;
177 } else
178
179 if (arg === '--on-change-only' || arg === '-C') {
180 options.runOnChangeOnly = true;
181 } else
182
183 if (arg === '--ext' || arg === '-e') {
184 options.ext = eatNext();
185 } else
186
187 if (arg === '--no-colours' || arg === '--no-colors') {
188 options.colours = false;
189 } else
190
191 if (arg === '--signal' || arg === '-s') {
192 options.signal = eatNext();
193 } else
194
195 if (arg === '--cwd') {
196 options.cwd = eatNext();
197
198 // go ahead and change directory. This is primarily for nodemon tools like
199 // grunt-nodemon - we're doing this early because it will affect where the
200 // user script is searched for.
201 process.chdir(path.resolve(options.cwd));
202 } else {
203
204 // this means we didn't match
205 return false;
206 }
207}
208
209/**
210 * Given an argument (ie. from nodemonOption()), will parse and return the
211 * equivalent millisecond value or 0 if the argument cannot be parsed
212 *
213 * @param {String} argument value given to the --delay option
214 * @return {Number} millisecond equivalent of the argument
215 */
216function parseDelay(value) {
217 var millisPerSecond = 1000;
218 var millis = 0;
219
220 if (value.match(/^\d*ms$/)) {
221 // Explicitly parse for milliseconds when using ms time specifier
222 millis = parseInt(value, 10);
223 } else {
224 // Otherwise, parse for seconds, with or without time specifier then convert
225 millis = parseFloat(value) * millisPerSecond;
226 }
227
228 return isNaN(millis) ? 0 : millis;
229}
230