breadc 0.1.0 → 0.3.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 +34 -7
- package/dist/index.cjs +452 -62
- package/dist/index.d.ts +295 -32
- package/dist/index.mjs +452 -61
- 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 ?? "";
|
|
297
|
+
this.required = format.indexOf("<") !== -1;
|
|
298
|
+
this.default = config.default;
|
|
46
299
|
this.construct = config.construct ?? ((text) => text ?? config.default ?? void 0);
|
|
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,55 @@ 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
|
+
}
|
|
123
404
|
return {
|
|
124
405
|
command: this,
|
|
125
406
|
arguments: argumentss,
|
|
126
|
-
options
|
|
407
|
+
options
|
|
127
408
|
};
|
|
128
409
|
}
|
|
129
410
|
action(fn) {
|
|
@@ -131,17 +412,29 @@ class Command {
|
|
|
131
412
|
return this;
|
|
132
413
|
}
|
|
133
414
|
async run(...args) {
|
|
134
|
-
|
|
415
|
+
if (this.actionFn) {
|
|
416
|
+
this.actionFn(...args);
|
|
417
|
+
} else {
|
|
418
|
+
this.logger.warn(`You may miss action function in "${this.format}"`);
|
|
419
|
+
}
|
|
135
420
|
}
|
|
136
|
-
}
|
|
137
|
-
Command
|
|
138
|
-
|
|
421
|
+
};
|
|
422
|
+
let Command = _Command;
|
|
423
|
+
Command.MaxDep = 5;
|
|
424
|
+
function createHelpCommand(breadc) {
|
|
425
|
+
let helpCommand = void 0;
|
|
139
426
|
return new Command("-h, --help", {
|
|
140
427
|
condition(args) {
|
|
141
|
-
const isEmpty = !args["
|
|
142
|
-
if (args.help && isEmpty) {
|
|
143
|
-
|
|
144
|
-
|
|
428
|
+
const isEmpty = !args["--"]?.length;
|
|
429
|
+
if ((args.help || args.h) && isEmpty) {
|
|
430
|
+
if (args["_"].length > 0) {
|
|
431
|
+
for (const cmd of breadc.commands) {
|
|
432
|
+
if (!cmd.hasConditionFn && !cmd.default && cmd.shouldRun(args)) {
|
|
433
|
+
helpCommand = cmd;
|
|
434
|
+
return true;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
145
438
|
return true;
|
|
146
439
|
} else {
|
|
147
440
|
return false;
|
|
@@ -149,10 +442,12 @@ function createVersionCommand(breadc) {
|
|
|
149
442
|
},
|
|
150
443
|
logger: breadc.logger
|
|
151
444
|
}).action(() => {
|
|
152
|
-
breadc.
|
|
445
|
+
for (const line of breadc.help(helpCommand)) {
|
|
446
|
+
breadc.logger.println(line);
|
|
447
|
+
}
|
|
153
448
|
});
|
|
154
449
|
}
|
|
155
|
-
function
|
|
450
|
+
function createVersionCommand(breadc) {
|
|
156
451
|
return new Command("-v, --version", {
|
|
157
452
|
condition(args) {
|
|
158
453
|
const isEmpty = !args["_"].length && !args["--"]?.length;
|
|
@@ -166,7 +461,7 @@ function createHelpCommand(breadc) {
|
|
|
166
461
|
},
|
|
167
462
|
logger: breadc.logger
|
|
168
463
|
}).action(() => {
|
|
169
|
-
breadc.logger.println(
|
|
464
|
+
breadc.logger.println(breadc.version());
|
|
170
465
|
});
|
|
171
466
|
}
|
|
172
467
|
|
|
@@ -175,22 +470,78 @@ class Breadc {
|
|
|
175
470
|
this.options = [];
|
|
176
471
|
this.commands = [];
|
|
177
472
|
this.name = name;
|
|
178
|
-
this.
|
|
179
|
-
this.
|
|
473
|
+
this._version = option.version ?? "unknown";
|
|
474
|
+
this.description = option.description;
|
|
475
|
+
this.logger = createDefaultLogger(name, option.logger);
|
|
180
476
|
const breadc = {
|
|
181
477
|
name: this.name,
|
|
182
|
-
version: this.version,
|
|
478
|
+
version: () => this.version.call(this),
|
|
479
|
+
help: (command) => this.help.call(this, command),
|
|
183
480
|
logger: this.logger,
|
|
184
481
|
options: this.options,
|
|
185
482
|
commands: this.commands
|
|
186
483
|
};
|
|
187
|
-
this.commands
|
|
484
|
+
this.commands.push(createVersionCommand(breadc), createHelpCommand(breadc));
|
|
188
485
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
486
|
+
version() {
|
|
487
|
+
return `${this.name}/${this._version}`;
|
|
488
|
+
}
|
|
489
|
+
help(command) {
|
|
490
|
+
const output = [];
|
|
491
|
+
const println = (msg) => output.push(msg);
|
|
492
|
+
println(this.version());
|
|
493
|
+
if (!command) {
|
|
494
|
+
if (this.description) {
|
|
495
|
+
println("");
|
|
496
|
+
if (Array.isArray(this.description)) {
|
|
497
|
+
for (const line of this.description) {
|
|
498
|
+
println(line);
|
|
499
|
+
}
|
|
500
|
+
} else {
|
|
501
|
+
println(this.description);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
} else {
|
|
505
|
+
if (command.description) {
|
|
506
|
+
println("");
|
|
507
|
+
println(command.description);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
if (!command) {
|
|
511
|
+
if (this.defaultCommand) {
|
|
512
|
+
println(``);
|
|
513
|
+
println(`Usage:`);
|
|
514
|
+
println(` $ ${this.name} ${this.defaultCommand.format.join(" ")}`);
|
|
515
|
+
}
|
|
516
|
+
} else {
|
|
517
|
+
println(``);
|
|
518
|
+
println(`Usage:`);
|
|
519
|
+
println(` $ ${this.name} ${command.format.join(" ")}`);
|
|
520
|
+
}
|
|
521
|
+
if (!command && this.commands.length > 2) {
|
|
522
|
+
println(``);
|
|
523
|
+
println(`Commands:`);
|
|
524
|
+
const commandHelps = this.commands.filter((c) => !c.hasConditionFn).map((c) => [` $ ${this.name} ${c.format.join(" ")}`, c.description]);
|
|
525
|
+
for (const line of twoColumn(commandHelps)) {
|
|
526
|
+
println(line);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
println(``);
|
|
530
|
+
println(`Options:`);
|
|
531
|
+
const optionHelps = [].concat([
|
|
532
|
+
...command ? command.options.map((o) => [` ${o.format}`, o.description]) : [],
|
|
533
|
+
...this.options.map((o) => [` ${o.format}`, o.description]),
|
|
534
|
+
[` -h, --help`, `Display this message`],
|
|
535
|
+
[` -v, --version`, `Display version number`]
|
|
536
|
+
]);
|
|
537
|
+
for (const line of twoColumn(optionHelps)) {
|
|
538
|
+
println(line);
|
|
193
539
|
}
|
|
540
|
+
println(``);
|
|
541
|
+
return output;
|
|
542
|
+
}
|
|
543
|
+
option(format, configOrDescription = "", otherConfig = {}) {
|
|
544
|
+
const config = typeof configOrDescription === "object" ? configOrDescription : { ...otherConfig, description: configOrDescription };
|
|
194
545
|
try {
|
|
195
546
|
const option = new Option(format, config);
|
|
196
547
|
this.options.push(option);
|
|
@@ -199,32 +550,64 @@ class Breadc {
|
|
|
199
550
|
}
|
|
200
551
|
return this;
|
|
201
552
|
}
|
|
202
|
-
command(format,
|
|
553
|
+
command(format, configOrDescription = "", otherConfig = {}) {
|
|
554
|
+
const config = typeof configOrDescription === "object" ? configOrDescription : { ...otherConfig, description: configOrDescription };
|
|
203
555
|
const command = new Command(format, { ...config, logger: this.logger });
|
|
556
|
+
if (command.default) {
|
|
557
|
+
if (this.defaultCommand) {
|
|
558
|
+
this.logger.warn("You can not have two default commands.");
|
|
559
|
+
}
|
|
560
|
+
this.defaultCommand = command;
|
|
561
|
+
}
|
|
204
562
|
this.commands.push(command);
|
|
205
563
|
return command;
|
|
206
564
|
}
|
|
207
565
|
parse(args) {
|
|
208
|
-
const allowOptions = [
|
|
566
|
+
const allowOptions = [
|
|
567
|
+
...this.options,
|
|
568
|
+
...this.commands.flatMap((c) => c.options)
|
|
569
|
+
];
|
|
209
570
|
const alias = allowOptions.reduce((map, o) => {
|
|
210
571
|
if (o.shortcut) {
|
|
211
572
|
map[o.shortcut] = o.name;
|
|
212
573
|
}
|
|
213
574
|
return map;
|
|
214
575
|
}, {});
|
|
576
|
+
const defaults = allowOptions.reduce((map, o) => {
|
|
577
|
+
if (o.default) {
|
|
578
|
+
map[o.name] = o.default;
|
|
579
|
+
}
|
|
580
|
+
return map;
|
|
581
|
+
}, {});
|
|
215
582
|
const argv = minimist(args, {
|
|
216
583
|
string: allowOptions.filter((o) => o.type === "string").map((o) => o.name),
|
|
217
584
|
boolean: allowOptions.filter((o) => o.type === "boolean").map((o) => o.name),
|
|
218
|
-
alias
|
|
585
|
+
alias,
|
|
586
|
+
default: defaults,
|
|
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 };
|