breadc 0.1.1 → 0.4.0
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.
- package/README.md +18 -13
- package/dist/index.cjs +453 -63
- package/dist/index.d.ts +298 -35
- package/dist/index.mjs +453 -62
- package/package.json +7 -9
package/dist/index.mjs
CHANGED
|
@@ -1,33 +1,284 @@
|
|
|
1
|
-
import { blue, yellow, red } from 'kolorist';
|
|
1
|
+
import { blue, yellow, red, gray } from 'kolorist';
|
|
2
2
|
export { default as kolorist } from 'kolorist';
|
|
3
|
-
import minimist from 'minimist';
|
|
4
|
-
export { default as minimist } from 'minimist';
|
|
5
|
-
import createDebug from 'debug';
|
|
6
|
-
export { default as createDebug } from 'debug';
|
|
7
3
|
|
|
8
|
-
function
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
4
|
+
var minimist = function (args, opts) {
|
|
5
|
+
if (!opts) opts = {};
|
|
6
|
+
|
|
7
|
+
var flags = { bools : {}, strings : {}, unknownFn: null };
|
|
8
|
+
|
|
9
|
+
if (typeof opts['unknown'] === 'function') {
|
|
10
|
+
flags.unknownFn = opts['unknown'];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (typeof opts['boolean'] === 'boolean' && opts['boolean']) {
|
|
14
|
+
flags.allBools = true;
|
|
15
|
+
} else {
|
|
16
|
+
[].concat(opts['boolean']).filter(Boolean).forEach(function (key) {
|
|
17
|
+
flags.bools[key] = true;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
var aliases = {};
|
|
22
|
+
Object.keys(opts.alias || {}).forEach(function (key) {
|
|
23
|
+
aliases[key] = [].concat(opts.alias[key]);
|
|
24
|
+
aliases[key].forEach(function (x) {
|
|
25
|
+
aliases[x] = [key].concat(aliases[key].filter(function (y) {
|
|
26
|
+
return x !== y;
|
|
27
|
+
}));
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
[].concat(opts.string).filter(Boolean).forEach(function (key) {
|
|
32
|
+
flags.strings[key] = true;
|
|
33
|
+
if (aliases[key]) {
|
|
34
|
+
flags.strings[aliases[key]] = true;
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
var defaults = opts['default'] || {};
|
|
39
|
+
|
|
40
|
+
var argv = { _ : [] };
|
|
41
|
+
Object.keys(flags.bools).forEach(function (key) {
|
|
42
|
+
setArg(key, defaults[key] === undefined ? false : defaults[key]);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
var notFlags = [];
|
|
46
|
+
|
|
47
|
+
if (args.indexOf('--') !== -1) {
|
|
48
|
+
notFlags = args.slice(args.indexOf('--')+1);
|
|
49
|
+
args = args.slice(0, args.indexOf('--'));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function argDefined(key, arg) {
|
|
53
|
+
return (flags.allBools && /^--[^=]+$/.test(arg)) ||
|
|
54
|
+
flags.strings[key] || flags.bools[key] || aliases[key];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function setArg (key, val, arg) {
|
|
58
|
+
if (arg && flags.unknownFn && !argDefined(key, arg)) {
|
|
59
|
+
if (flags.unknownFn(arg) === false) return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
var value = !flags.strings[key] && isNumber(val)
|
|
63
|
+
? Number(val) : val
|
|
64
|
+
;
|
|
65
|
+
setKey(argv, key.split('.'), value);
|
|
66
|
+
|
|
67
|
+
(aliases[key] || []).forEach(function (x) {
|
|
68
|
+
setKey(argv, x.split('.'), value);
|
|
69
|
+
});
|
|
25
70
|
}
|
|
71
|
+
|
|
72
|
+
function setKey (obj, keys, value) {
|
|
73
|
+
var o = obj;
|
|
74
|
+
for (var i = 0; i < keys.length-1; i++) {
|
|
75
|
+
var key = keys[i];
|
|
76
|
+
if (isConstructorOrProto(o, key)) return;
|
|
77
|
+
if (o[key] === undefined) o[key] = {};
|
|
78
|
+
if (o[key] === Object.prototype || o[key] === Number.prototype
|
|
79
|
+
|| o[key] === String.prototype) o[key] = {};
|
|
80
|
+
if (o[key] === Array.prototype) o[key] = [];
|
|
81
|
+
o = o[key];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
var key = keys[keys.length - 1];
|
|
85
|
+
if (isConstructorOrProto(o, key)) return;
|
|
86
|
+
if (o === Object.prototype || o === Number.prototype
|
|
87
|
+
|| o === String.prototype) o = {};
|
|
88
|
+
if (o === Array.prototype) o = [];
|
|
89
|
+
if (o[key] === undefined || flags.bools[key] || typeof o[key] === 'boolean') {
|
|
90
|
+
o[key] = value;
|
|
91
|
+
}
|
|
92
|
+
else if (Array.isArray(o[key])) {
|
|
93
|
+
o[key].push(value);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
o[key] = [ o[key], value ];
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function aliasIsBoolean(key) {
|
|
101
|
+
return aliases[key].some(function (x) {
|
|
102
|
+
return flags.bools[x];
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
for (var i = 0; i < args.length; i++) {
|
|
107
|
+
var arg = args[i];
|
|
108
|
+
|
|
109
|
+
if (/^--.+=/.test(arg)) {
|
|
110
|
+
// Using [\s\S] instead of . because js doesn't support the
|
|
111
|
+
// 'dotall' regex modifier. See:
|
|
112
|
+
// http://stackoverflow.com/a/1068308/13216
|
|
113
|
+
var m = arg.match(/^--([^=]+)=([\s\S]*)$/);
|
|
114
|
+
var key = m[1];
|
|
115
|
+
var value = m[2];
|
|
116
|
+
if (flags.bools[key]) {
|
|
117
|
+
value = value !== 'false';
|
|
118
|
+
}
|
|
119
|
+
setArg(key, value, arg);
|
|
120
|
+
}
|
|
121
|
+
else if (/^--no-.+/.test(arg)) {
|
|
122
|
+
var key = arg.match(/^--no-(.+)/)[1];
|
|
123
|
+
setArg(key, false, arg);
|
|
124
|
+
}
|
|
125
|
+
else if (/^--.+/.test(arg)) {
|
|
126
|
+
var key = arg.match(/^--(.+)/)[1];
|
|
127
|
+
var next = args[i + 1];
|
|
128
|
+
if (next !== undefined && !/^-/.test(next)
|
|
129
|
+
&& !flags.bools[key]
|
|
130
|
+
&& !flags.allBools
|
|
131
|
+
&& (aliases[key] ? !aliasIsBoolean(key) : true)) {
|
|
132
|
+
setArg(key, next, arg);
|
|
133
|
+
i++;
|
|
134
|
+
}
|
|
135
|
+
else if (/^(true|false)$/.test(next)) {
|
|
136
|
+
setArg(key, next === 'true', arg);
|
|
137
|
+
i++;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
setArg(key, flags.strings[key] ? '' : true, arg);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
else if (/^-[^-]+/.test(arg)) {
|
|
144
|
+
var letters = arg.slice(1,-1).split('');
|
|
145
|
+
|
|
146
|
+
var broken = false;
|
|
147
|
+
for (var j = 0; j < letters.length; j++) {
|
|
148
|
+
var next = arg.slice(j+2);
|
|
149
|
+
|
|
150
|
+
if (next === '-') {
|
|
151
|
+
setArg(letters[j], next, arg);
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (/[A-Za-z]/.test(letters[j]) && /=/.test(next)) {
|
|
156
|
+
setArg(letters[j], next.split('=')[1], arg);
|
|
157
|
+
broken = true;
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (/[A-Za-z]/.test(letters[j])
|
|
162
|
+
&& /-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) {
|
|
163
|
+
setArg(letters[j], next, arg);
|
|
164
|
+
broken = true;
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (letters[j+1] && letters[j+1].match(/\W/)) {
|
|
169
|
+
setArg(letters[j], arg.slice(j+2), arg);
|
|
170
|
+
broken = true;
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
setArg(letters[j], flags.strings[letters[j]] ? '' : true, arg);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
var key = arg.slice(-1)[0];
|
|
179
|
+
if (!broken && key !== '-') {
|
|
180
|
+
if (args[i+1] && !/^(-|--)[^-]/.test(args[i+1])
|
|
181
|
+
&& !flags.bools[key]
|
|
182
|
+
&& (aliases[key] ? !aliasIsBoolean(key) : true)) {
|
|
183
|
+
setArg(key, args[i+1], arg);
|
|
184
|
+
i++;
|
|
185
|
+
}
|
|
186
|
+
else if (args[i+1] && /^(true|false)$/.test(args[i+1])) {
|
|
187
|
+
setArg(key, args[i+1] === 'true', arg);
|
|
188
|
+
i++;
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
setArg(key, flags.strings[key] ? '' : true, arg);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
if (!flags.unknownFn || flags.unknownFn(arg) !== false) {
|
|
197
|
+
argv._.push(
|
|
198
|
+
flags.strings['_'] || !isNumber(arg) ? arg : Number(arg)
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
if (opts.stopEarly) {
|
|
202
|
+
argv._.push.apply(argv._, args.slice(i + 1));
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
Object.keys(defaults).forEach(function (key) {
|
|
209
|
+
if (!hasKey(argv, key.split('.'))) {
|
|
210
|
+
setKey(argv, key.split('.'), defaults[key]);
|
|
211
|
+
|
|
212
|
+
(aliases[key] || []).forEach(function (x) {
|
|
213
|
+
setKey(argv, x.split('.'), defaults[key]);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
if (opts['--']) {
|
|
219
|
+
argv['--'] = new Array();
|
|
220
|
+
notFlags.forEach(function(key) {
|
|
221
|
+
argv['--'].push(key);
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
notFlags.forEach(function(key) {
|
|
226
|
+
argv._.push(key);
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return argv;
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
function hasKey (obj, keys) {
|
|
234
|
+
var o = obj;
|
|
235
|
+
keys.slice(0,-1).forEach(function (key) {
|
|
236
|
+
o = (o[key] || {});
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
var key = keys[keys.length - 1];
|
|
240
|
+
return key in o;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function isNumber (x) {
|
|
244
|
+
if (typeof x === 'number') return true;
|
|
245
|
+
if (/^0x[0-9a-f]+$/i.test(x)) return true;
|
|
246
|
+
return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
function isConstructorOrProto (obj, key) {
|
|
251
|
+
return key === 'constructor' && typeof obj[key] === 'function' || key === '__proto__';
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function createDefaultLogger(name, logger) {
|
|
255
|
+
const println = !!logger && typeof logger === "function" ? logger : logger?.println ?? ((message, ...args) => {
|
|
256
|
+
console.log(message, ...args);
|
|
257
|
+
});
|
|
258
|
+
const info = typeof logger === "object" && logger?.info ? logger.info : (message, ...args) => {
|
|
259
|
+
println(`${blue("INFO")} ${message}`, ...args);
|
|
260
|
+
};
|
|
261
|
+
const warn = typeof logger === "object" && logger?.warn ? logger.warn : (message, ...args) => {
|
|
262
|
+
println(`${yellow("WARN")} ${message}`, ...args);
|
|
263
|
+
};
|
|
264
|
+
const error = typeof logger === "object" && logger?.error ? logger.error : (message, ...args) => {
|
|
265
|
+
println(`${red("ERROR")} ${message}`, ...args);
|
|
266
|
+
};
|
|
267
|
+
const debug = typeof logger === "object" && logger?.debug ? logger.debug : (message, ...args) => {
|
|
268
|
+
println(`${gray(name)} ${message}`, ...args);
|
|
269
|
+
};
|
|
270
|
+
return {
|
|
271
|
+
println,
|
|
272
|
+
info,
|
|
273
|
+
warn,
|
|
274
|
+
error,
|
|
275
|
+
debug
|
|
26
276
|
};
|
|
27
277
|
}
|
|
28
278
|
|
|
29
279
|
const _Option = class {
|
|
30
280
|
constructor(format, config = {}) {
|
|
281
|
+
this.format = format;
|
|
31
282
|
const match = _Option.OptionRE.exec(format);
|
|
32
283
|
if (match) {
|
|
33
284
|
if (match[3]) {
|
|
@@ -43,25 +294,28 @@ const _Option = class {
|
|
|
43
294
|
throw new Error(`Can not parse option format from "${format}"`);
|
|
44
295
|
}
|
|
45
296
|
this.description = config.description ?? "";
|
|
46
|
-
this.
|
|
297
|
+
this.required = format.indexOf("<") !== -1;
|
|
298
|
+
this.default = config.default;
|
|
299
|
+
this.construct = config.construct;
|
|
47
300
|
}
|
|
48
301
|
};
|
|
49
302
|
let Option = _Option;
|
|
50
303
|
Option.OptionRE = /^(-[a-zA-Z], )?--([a-zA-Z.]+)( \[[a-zA-Z]+\]| <[a-zA-Z]+>)?$/;
|
|
51
304
|
|
|
52
|
-
class
|
|
305
|
+
const _Command = class {
|
|
53
306
|
constructor(format, config) {
|
|
54
307
|
this.options = [];
|
|
55
308
|
this.format = config.condition ? [format] : format.split(" ").map((t) => t.trim()).filter(Boolean);
|
|
309
|
+
this.default = this.format.length === 0 || this.format[0][0] === "[" || this.format[0][0] === "<";
|
|
56
310
|
this.description = config.description ?? "";
|
|
57
311
|
this.conditionFn = config.condition;
|
|
58
312
|
this.logger = config.logger;
|
|
313
|
+
if (this.format.length > _Command.MaxDep) {
|
|
314
|
+
this.logger.warn(`Command format string "${format}" is too long`);
|
|
315
|
+
}
|
|
59
316
|
}
|
|
60
317
|
option(format, configOrDescription = "", otherConfig = {}) {
|
|
61
|
-
const config = otherConfig;
|
|
62
|
-
if (typeof configOrDescription === "string") {
|
|
63
|
-
config.description = configOrDescription;
|
|
64
|
-
}
|
|
318
|
+
const config = typeof configOrDescription === "object" ? configOrDescription : { ...otherConfig, description: configOrDescription };
|
|
65
319
|
try {
|
|
66
320
|
const option = new Option(format, config);
|
|
67
321
|
this.options.push(option);
|
|
@@ -70,13 +324,18 @@ class Command {
|
|
|
70
324
|
}
|
|
71
325
|
return this;
|
|
72
326
|
}
|
|
327
|
+
get hasConditionFn() {
|
|
328
|
+
return !!this.conditionFn;
|
|
329
|
+
}
|
|
73
330
|
shouldRun(args) {
|
|
74
331
|
if (this.conditionFn) {
|
|
75
332
|
return this.conditionFn(args);
|
|
76
333
|
} else {
|
|
77
|
-
|
|
334
|
+
if (this.default)
|
|
335
|
+
return true;
|
|
336
|
+
const isCmd = (t) => t[0] !== "[" && t[0] !== "<";
|
|
78
337
|
for (let i = 0; i < this.format.length; i++) {
|
|
79
|
-
if (
|
|
338
|
+
if (!isCmd(this.format[i])) {
|
|
80
339
|
return true;
|
|
81
340
|
}
|
|
82
341
|
if (i >= args["_"].length || this.format[i] !== args["_"][i]) {
|
|
@@ -86,7 +345,7 @@ class Command {
|
|
|
86
345
|
return true;
|
|
87
346
|
}
|
|
88
347
|
}
|
|
89
|
-
parseArgs(args) {
|
|
348
|
+
parseArgs(args, globalOptions) {
|
|
90
349
|
if (this.conditionFn) {
|
|
91
350
|
const argumentss2 = args["_"];
|
|
92
351
|
const options2 = args;
|
|
@@ -97,33 +356,62 @@ class Command {
|
|
|
97
356
|
options: args
|
|
98
357
|
};
|
|
99
358
|
}
|
|
100
|
-
const
|
|
359
|
+
const isCmd = (t) => t[0] !== "[" && t[0] !== "<";
|
|
101
360
|
const argumentss = [];
|
|
102
361
|
for (let i = 0; i < this.format.length; i++) {
|
|
103
|
-
if (
|
|
362
|
+
if (isCmd(this.format[i]))
|
|
104
363
|
continue;
|
|
105
364
|
if (i < args["_"].length) {
|
|
106
365
|
if (this.format[i].startsWith("[...")) {
|
|
107
|
-
argumentss.push(args["_"].slice(i));
|
|
366
|
+
argumentss.push(args["_"].slice(i).map(String));
|
|
108
367
|
} else {
|
|
109
|
-
argumentss.push(args["_"][i]);
|
|
368
|
+
argumentss.push(String(args["_"][i]));
|
|
110
369
|
}
|
|
111
370
|
} else {
|
|
112
371
|
if (this.format[i].startsWith("<")) {
|
|
372
|
+
this.logger.warn(`You should provide the argument "${this.format[i]}"`);
|
|
113
373
|
argumentss.push(void 0);
|
|
114
374
|
} else if (this.format[i].startsWith("[...")) {
|
|
115
375
|
argumentss.push([]);
|
|
116
376
|
} else if (this.format[i].startsWith("[")) {
|
|
117
377
|
argumentss.push(void 0);
|
|
118
|
-
} else
|
|
378
|
+
} else {
|
|
379
|
+
this.logger.warn(`unknown format string ("${this.format[i]}")`);
|
|
380
|
+
}
|
|
119
381
|
}
|
|
120
382
|
}
|
|
383
|
+
const fullOptions = globalOptions.concat(this.options).reduce((map, o) => {
|
|
384
|
+
map.set(o.name, o);
|
|
385
|
+
return map;
|
|
386
|
+
}, /* @__PURE__ */ new Map());
|
|
121
387
|
const options = args;
|
|
122
388
|
delete options["_"];
|
|
389
|
+
for (const [name, rawOption] of fullOptions) {
|
|
390
|
+
if (rawOption.required) {
|
|
391
|
+
if (options[name] === void 0) {
|
|
392
|
+
options[name] = false;
|
|
393
|
+
} else if (options[name] === "") {
|
|
394
|
+
options[name] = true;
|
|
395
|
+
}
|
|
396
|
+
} else {
|
|
397
|
+
if (options[name] === false) {
|
|
398
|
+
options[name] = void 0;
|
|
399
|
+
} else if (!(name in options)) {
|
|
400
|
+
options[name] = void 0;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
if (rawOption.construct) {
|
|
404
|
+
options[name] = rawOption.construct(options[name]);
|
|
405
|
+
} else if (rawOption.default) {
|
|
406
|
+
if (!options[name]) {
|
|
407
|
+
options[name] = rawOption.default;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
123
411
|
return {
|
|
124
412
|
command: this,
|
|
125
413
|
arguments: argumentss,
|
|
126
|
-
options
|
|
414
|
+
options
|
|
127
415
|
};
|
|
128
416
|
}
|
|
129
417
|
action(fn) {
|
|
@@ -131,17 +419,29 @@ class Command {
|
|
|
131
419
|
return this;
|
|
132
420
|
}
|
|
133
421
|
async run(...args) {
|
|
134
|
-
|
|
422
|
+
if (this.actionFn) {
|
|
423
|
+
this.actionFn(...args);
|
|
424
|
+
} else {
|
|
425
|
+
this.logger.warn(`You may miss action function in "${this.format}"`);
|
|
426
|
+
}
|
|
135
427
|
}
|
|
136
|
-
}
|
|
137
|
-
Command
|
|
138
|
-
|
|
428
|
+
};
|
|
429
|
+
let Command = _Command;
|
|
430
|
+
Command.MaxDep = 5;
|
|
431
|
+
function createHelpCommand(breadc) {
|
|
432
|
+
let helpCommand = void 0;
|
|
139
433
|
return new Command("-h, --help", {
|
|
140
434
|
condition(args) {
|
|
141
|
-
const isEmpty = !args["
|
|
142
|
-
if (args.help && isEmpty) {
|
|
143
|
-
|
|
144
|
-
|
|
435
|
+
const isEmpty = !args["--"]?.length;
|
|
436
|
+
if ((args.help || args.h) && isEmpty) {
|
|
437
|
+
if (args["_"].length > 0) {
|
|
438
|
+
for (const cmd of breadc.commands) {
|
|
439
|
+
if (!cmd.hasConditionFn && !cmd.default && cmd.shouldRun(args)) {
|
|
440
|
+
helpCommand = cmd;
|
|
441
|
+
return true;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
145
445
|
return true;
|
|
146
446
|
} else {
|
|
147
447
|
return false;
|
|
@@ -149,10 +449,12 @@ function createVersionCommand(breadc) {
|
|
|
149
449
|
},
|
|
150
450
|
logger: breadc.logger
|
|
151
451
|
}).action(() => {
|
|
152
|
-
breadc.
|
|
452
|
+
for (const line of breadc.help(helpCommand)) {
|
|
453
|
+
breadc.logger.println(line);
|
|
454
|
+
}
|
|
153
455
|
});
|
|
154
456
|
}
|
|
155
|
-
function
|
|
457
|
+
function createVersionCommand(breadc) {
|
|
156
458
|
return new Command("-v, --version", {
|
|
157
459
|
condition(args) {
|
|
158
460
|
const isEmpty = !args["_"].length && !args["--"]?.length;
|
|
@@ -166,7 +468,7 @@ function createHelpCommand(breadc) {
|
|
|
166
468
|
},
|
|
167
469
|
logger: breadc.logger
|
|
168
470
|
}).action(() => {
|
|
169
|
-
breadc.logger.println(
|
|
471
|
+
breadc.logger.println(breadc.version());
|
|
170
472
|
});
|
|
171
473
|
}
|
|
172
474
|
|
|
@@ -175,22 +477,78 @@ class Breadc {
|
|
|
175
477
|
this.options = [];
|
|
176
478
|
this.commands = [];
|
|
177
479
|
this.name = name;
|
|
178
|
-
this.
|
|
179
|
-
this.
|
|
480
|
+
this._version = option.version ?? "unknown";
|
|
481
|
+
this.description = option.description;
|
|
482
|
+
this.logger = createDefaultLogger(name, option.logger);
|
|
180
483
|
const breadc = {
|
|
181
484
|
name: this.name,
|
|
182
|
-
version: this.version,
|
|
485
|
+
version: () => this.version.call(this),
|
|
486
|
+
help: (command) => this.help.call(this, command),
|
|
183
487
|
logger: this.logger,
|
|
184
488
|
options: this.options,
|
|
185
489
|
commands: this.commands
|
|
186
490
|
};
|
|
187
|
-
this.commands
|
|
491
|
+
this.commands.push(createVersionCommand(breadc), createHelpCommand(breadc));
|
|
188
492
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
493
|
+
version() {
|
|
494
|
+
return `${this.name}/${this._version}`;
|
|
495
|
+
}
|
|
496
|
+
help(command) {
|
|
497
|
+
const output = [];
|
|
498
|
+
const println = (msg) => output.push(msg);
|
|
499
|
+
println(this.version());
|
|
500
|
+
if (!command) {
|
|
501
|
+
if (this.description) {
|
|
502
|
+
println("");
|
|
503
|
+
if (Array.isArray(this.description)) {
|
|
504
|
+
for (const line of this.description) {
|
|
505
|
+
println(line);
|
|
506
|
+
}
|
|
507
|
+
} else {
|
|
508
|
+
println(this.description);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
} else {
|
|
512
|
+
if (command.description) {
|
|
513
|
+
println("");
|
|
514
|
+
println(command.description);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
if (!command) {
|
|
518
|
+
if (this.defaultCommand) {
|
|
519
|
+
println(``);
|
|
520
|
+
println(`Usage:`);
|
|
521
|
+
println(` $ ${this.name} ${this.defaultCommand.format.join(" ")}`);
|
|
522
|
+
}
|
|
523
|
+
} else {
|
|
524
|
+
println(``);
|
|
525
|
+
println(`Usage:`);
|
|
526
|
+
println(` $ ${this.name} ${command.format.join(" ")}`);
|
|
193
527
|
}
|
|
528
|
+
if (!command && this.commands.length > 2) {
|
|
529
|
+
println(``);
|
|
530
|
+
println(`Commands:`);
|
|
531
|
+
const commandHelps = this.commands.filter((c) => !c.hasConditionFn).map((c) => [` $ ${this.name} ${c.format.join(" ")}`, c.description]);
|
|
532
|
+
for (const line of twoColumn(commandHelps)) {
|
|
533
|
+
println(line);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
println(``);
|
|
537
|
+
println(`Options:`);
|
|
538
|
+
const optionHelps = [].concat([
|
|
539
|
+
...command ? command.options.map((o) => [` ${o.format}`, o.description]) : [],
|
|
540
|
+
...this.options.map((o) => [` ${o.format}`, o.description]),
|
|
541
|
+
[` -h, --help`, `Display this message`],
|
|
542
|
+
[` -v, --version`, `Display version number`]
|
|
543
|
+
]);
|
|
544
|
+
for (const line of twoColumn(optionHelps)) {
|
|
545
|
+
println(line);
|
|
546
|
+
}
|
|
547
|
+
println(``);
|
|
548
|
+
return output;
|
|
549
|
+
}
|
|
550
|
+
option(format, configOrDescription = "", otherConfig = {}) {
|
|
551
|
+
const config = typeof configOrDescription === "object" ? configOrDescription : { ...otherConfig, description: configOrDescription };
|
|
194
552
|
try {
|
|
195
553
|
const option = new Option(format, config);
|
|
196
554
|
this.options.push(option);
|
|
@@ -199,13 +557,23 @@ class Breadc {
|
|
|
199
557
|
}
|
|
200
558
|
return this;
|
|
201
559
|
}
|
|
202
|
-
command(format,
|
|
560
|
+
command(format, configOrDescription = "", otherConfig = {}) {
|
|
561
|
+
const config = typeof configOrDescription === "object" ? configOrDescription : { ...otherConfig, description: configOrDescription };
|
|
203
562
|
const command = new Command(format, { ...config, logger: this.logger });
|
|
563
|
+
if (command.default) {
|
|
564
|
+
if (this.defaultCommand) {
|
|
565
|
+
this.logger.warn("You can not have two default commands.");
|
|
566
|
+
}
|
|
567
|
+
this.defaultCommand = command;
|
|
568
|
+
}
|
|
204
569
|
this.commands.push(command);
|
|
205
570
|
return command;
|
|
206
571
|
}
|
|
207
572
|
parse(args) {
|
|
208
|
-
const allowOptions = [
|
|
573
|
+
const allowOptions = [
|
|
574
|
+
...this.options,
|
|
575
|
+
...this.commands.flatMap((c) => c.options)
|
|
576
|
+
];
|
|
209
577
|
const alias = allowOptions.reduce((map, o) => {
|
|
210
578
|
if (o.shortcut) {
|
|
211
579
|
map[o.shortcut] = o.name;
|
|
@@ -215,16 +583,31 @@ class Breadc {
|
|
|
215
583
|
const argv = minimist(args, {
|
|
216
584
|
string: allowOptions.filter((o) => o.type === "string").map((o) => o.name),
|
|
217
585
|
boolean: allowOptions.filter((o) => o.type === "boolean").map((o) => o.name),
|
|
218
|
-
alias
|
|
586
|
+
alias,
|
|
587
|
+
unknown: (t) => {
|
|
588
|
+
if (t[0] !== "-")
|
|
589
|
+
return true;
|
|
590
|
+
else {
|
|
591
|
+
if (["--help", "-h", "--version", "-v"].includes(t)) {
|
|
592
|
+
return true;
|
|
593
|
+
} else {
|
|
594
|
+
this.logger.warn(`Find unknown flag "${t}"`);
|
|
595
|
+
return false;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
219
599
|
});
|
|
220
600
|
for (const shortcut of Object.keys(alias)) {
|
|
221
601
|
delete argv[shortcut];
|
|
222
602
|
}
|
|
223
603
|
for (const command of this.commands) {
|
|
224
|
-
if (command.shouldRun(argv)) {
|
|
225
|
-
return command.parseArgs(argv);
|
|
604
|
+
if (!command.default && command.shouldRun(argv)) {
|
|
605
|
+
return command.parseArgs(argv, this.options);
|
|
226
606
|
}
|
|
227
607
|
}
|
|
608
|
+
if (this.defaultCommand) {
|
|
609
|
+
return this.defaultCommand.parseArgs(argv, this.options);
|
|
610
|
+
}
|
|
228
611
|
const argumentss = argv["_"];
|
|
229
612
|
const options = argv;
|
|
230
613
|
delete options["_"];
|
|
@@ -241,9 +624,17 @@ class Breadc {
|
|
|
241
624
|
}
|
|
242
625
|
}
|
|
243
626
|
}
|
|
627
|
+
function twoColumn(texts, split = " ") {
|
|
628
|
+
const left = padRight(texts.map((t) => t[0]));
|
|
629
|
+
return left.map((l, idx) => l + split + texts[idx][1]);
|
|
630
|
+
}
|
|
631
|
+
function padRight(texts, fill = " ") {
|
|
632
|
+
const length = texts.map((t) => t.length).reduce((max, l) => Math.max(max, l), 0);
|
|
633
|
+
return texts.map((t) => t + fill.repeat(length - t.length));
|
|
634
|
+
}
|
|
244
635
|
|
|
245
636
|
function breadc(name, option = {}) {
|
|
246
637
|
return new Breadc(name, option);
|
|
247
638
|
}
|
|
248
639
|
|
|
249
|
-
export { breadc as default };
|
|
640
|
+
export { breadc as default, minimist };
|