Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80698 views
1
module.exports = function (args, opts) {
2
if (!opts) opts = {};
3
4
var flags = { bools : {}, strings : {} };
5
6
[].concat(opts['boolean']).filter(Boolean).forEach(function (key) {
7
flags.bools[key] = true;
8
});
9
10
[].concat(opts.string).filter(Boolean).forEach(function (key) {
11
flags.strings[key] = true;
12
});
13
14
var aliases = {};
15
Object.keys(opts.alias || {}).forEach(function (key) {
16
aliases[key] = [].concat(opts.alias[key]);
17
aliases[key].forEach(function (x) {
18
aliases[x] = [key].concat(aliases[key].filter(function (y) {
19
return x !== y;
20
}));
21
});
22
});
23
24
var defaults = opts['default'] || {};
25
26
var argv = { _ : [] };
27
Object.keys(flags.bools).forEach(function (key) {
28
setArg(key, defaults[key] === undefined ? false : defaults[key]);
29
});
30
31
var notFlags = [];
32
33
if (args.indexOf('--') !== -1) {
34
notFlags = args.slice(args.indexOf('--')+1);
35
args = args.slice(0, args.indexOf('--'));
36
}
37
38
function setArg (key, val) {
39
var value = !flags.strings[key] && isNumber(val)
40
? Number(val) : val
41
;
42
setKey(argv, key.split('.'), value);
43
44
(aliases[key] || []).forEach(function (x) {
45
setKey(argv, x.split('.'), value);
46
});
47
}
48
49
for (var i = 0; i < args.length; i++) {
50
var arg = args[i];
51
52
if (/^--.+=/.test(arg)) {
53
// Using [\s\S] instead of . because js doesn't support the
54
// 'dotall' regex modifier. See:
55
// http://stackoverflow.com/a/1068308/13216
56
var m = arg.match(/^--([^=]+)=([\s\S]*)$/);
57
setArg(m[1], m[2]);
58
}
59
else if (/^--no-.+/.test(arg)) {
60
var key = arg.match(/^--no-(.+)/)[1];
61
setArg(key, false);
62
}
63
else if (/^--.+/.test(arg)) {
64
var key = arg.match(/^--(.+)/)[1];
65
var next = args[i + 1];
66
if (next !== undefined && !/^-/.test(next)
67
&& !flags.bools[key]
68
&& (aliases[key] ? !flags.bools[aliases[key]] : true)) {
69
setArg(key, next);
70
i++;
71
}
72
else if (/^(true|false)$/.test(next)) {
73
setArg(key, next === 'true');
74
i++;
75
}
76
else {
77
setArg(key, flags.strings[key] ? '' : true);
78
}
79
}
80
else if (/^-[^-]+/.test(arg)) {
81
var letters = arg.slice(1,-1).split('');
82
83
var broken = false;
84
for (var j = 0; j < letters.length; j++) {
85
var next = arg.slice(j+2);
86
87
if (next === '-') {
88
setArg(letters[j], next)
89
continue;
90
}
91
92
if (/[A-Za-z]/.test(letters[j])
93
&& /-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) {
94
setArg(letters[j], next);
95
broken = true;
96
break;
97
}
98
99
if (letters[j+1] && letters[j+1].match(/\W/)) {
100
setArg(letters[j], arg.slice(j+2));
101
broken = true;
102
break;
103
}
104
else {
105
setArg(letters[j], flags.strings[letters[j]] ? '' : true);
106
}
107
}
108
109
var key = arg.slice(-1)[0];
110
if (!broken && key !== '-') {
111
if (args[i+1] && !/^(-|--)[^-]/.test(args[i+1])
112
&& !flags.bools[key]
113
&& (aliases[key] ? !flags.bools[aliases[key]] : true)) {
114
setArg(key, args[i+1]);
115
i++;
116
}
117
else if (args[i+1] && /true|false/.test(args[i+1])) {
118
setArg(key, args[i+1] === 'true');
119
i++;
120
}
121
else {
122
setArg(key, flags.strings[key] ? '' : true);
123
}
124
}
125
}
126
else {
127
argv._.push(
128
flags.strings['_'] || !isNumber(arg) ? arg : Number(arg)
129
);
130
}
131
}
132
133
Object.keys(defaults).forEach(function (key) {
134
if (!hasKey(argv, key.split('.'))) {
135
setKey(argv, key.split('.'), defaults[key]);
136
137
(aliases[key] || []).forEach(function (x) {
138
setKey(argv, x.split('.'), defaults[key]);
139
});
140
}
141
});
142
143
notFlags.forEach(function(key) {
144
argv._.push(key);
145
});
146
147
return argv;
148
};
149
150
function hasKey (obj, keys) {
151
var o = obj;
152
keys.slice(0,-1).forEach(function (key) {
153
o = (o[key] || {});
154
});
155
156
var key = keys[keys.length - 1];
157
return key in o;
158
}
159
160
function setKey (obj, keys, value) {
161
var o = obj;
162
keys.slice(0,-1).forEach(function (key) {
163
if (o[key] === undefined) o[key] = {};
164
o = o[key];
165
});
166
167
var key = keys[keys.length - 1];
168
if (o[key] === undefined || typeof o[key] === 'boolean') {
169
o[key] = value;
170
}
171
else if (Array.isArray(o[key])) {
172
o[key].push(value);
173
}
174
else {
175
o[key] = [ o[key], value ];
176
}
177
}
178
179
function isNumber (x) {
180
if (typeof x === 'number') return true;
181
if (/^0x[0-9a-f]+$/i.test(x)) return true;
182
return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x);
183
}
184
185
function longest (xs) {
186
return Math.max.apply(null, xs.map(function (x) { return x.length }));
187
}
188
189