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