breadc 0.8.2 → 0.8.4
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 +1 -1
- package/dist/index.cjs +133 -94
- package/dist/index.d.ts +2 -0
- package/dist/index.mjs +133 -94
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Yet another Command Line Application Framework with fully strong **[TypeScript](
|
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
|
-
+ ⚡️ **Light-weight**: Only
|
|
11
|
+
+ ⚡️ **Light-weight**: Only 75 kB (Unpacked).
|
|
12
12
|
+ 📖 **East to Learn**: Breadc is basically compatible with [cac](https://github.com/cacjs/cac) and there are only 5 APIs for building a CLI application: `breadc`, `command`, `option`, `action`, `run`.
|
|
13
13
|
+ 💻 **TypeScript Infer**: IDE will automatically infer the type of your command action function.
|
|
14
14
|
|
package/dist/index.cjs
CHANGED
|
@@ -128,6 +128,7 @@ class Token {
|
|
|
128
128
|
return this._type = "string";
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
|
+
/* c8 ignore next 1 */
|
|
131
132
|
}
|
|
132
133
|
class Lexer {
|
|
133
134
|
constructor(rawArgs) {
|
|
@@ -140,7 +141,7 @@ class Lexer {
|
|
|
140
141
|
return value ? new Token(value) : void 0;
|
|
141
142
|
}
|
|
142
143
|
hasNext() {
|
|
143
|
-
return this.cursor
|
|
144
|
+
return this.cursor < this.rawArgs.length;
|
|
144
145
|
}
|
|
145
146
|
peek() {
|
|
146
147
|
const value = this.rawArgs[this.cursor];
|
|
@@ -153,7 +154,7 @@ class Lexer {
|
|
|
153
154
|
const value = that.rawArgs[that.cursor];
|
|
154
155
|
that.cursor += 1;
|
|
155
156
|
return {
|
|
156
|
-
value: value ? new Token(value) : void 0,
|
|
157
|
+
value: value !== void 0 ? new Token(value) : void 0,
|
|
157
158
|
done: that.cursor > that.rawArgs.length
|
|
158
159
|
};
|
|
159
160
|
}
|
|
@@ -340,13 +341,13 @@ const initContextOptions = (options, context) => {
|
|
|
340
341
|
};
|
|
341
342
|
|
|
342
343
|
function makeCommand(format, config, root, container) {
|
|
343
|
-
let cursor = root;
|
|
344
344
|
const args = [];
|
|
345
345
|
const options = [];
|
|
346
346
|
const command = {
|
|
347
347
|
callback: void 0,
|
|
348
348
|
format,
|
|
349
349
|
description: config.description ?? "",
|
|
350
|
+
_default: false,
|
|
350
351
|
_arguments: args,
|
|
351
352
|
_options: options,
|
|
352
353
|
option(format2, _config, _config2 = {}) {
|
|
@@ -355,6 +356,21 @@ function makeCommand(format, config, root, container) {
|
|
|
355
356
|
options.push(option);
|
|
356
357
|
return command;
|
|
357
358
|
},
|
|
359
|
+
alias(format2) {
|
|
360
|
+
const aliasArgs = [];
|
|
361
|
+
const node2 = makeNode(aliasArgs);
|
|
362
|
+
function* g() {
|
|
363
|
+
for (const f of format2.split(" ")) {
|
|
364
|
+
yield { type: "const", name: f };
|
|
365
|
+
}
|
|
366
|
+
for (const a of args.filter((a2) => a2.type !== "const")) {
|
|
367
|
+
yield a;
|
|
368
|
+
}
|
|
369
|
+
return void 0;
|
|
370
|
+
}
|
|
371
|
+
insertTreeNode(aliasArgs, node2, g());
|
|
372
|
+
return command;
|
|
373
|
+
},
|
|
358
374
|
action(fn) {
|
|
359
375
|
command.callback = async (parsed) => {
|
|
360
376
|
await container.preCommand(command, parsed);
|
|
@@ -367,78 +383,45 @@ function makeCommand(format, config, root, container) {
|
|
|
367
383
|
};
|
|
368
384
|
}
|
|
369
385
|
};
|
|
370
|
-
const node =
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
386
|
+
const node = makeNode(args);
|
|
387
|
+
insertTreeNode(args, node, parseCommandFormat(format));
|
|
388
|
+
return command;
|
|
389
|
+
function makeNode(args2) {
|
|
390
|
+
return makeTreeNode({
|
|
391
|
+
command,
|
|
392
|
+
init(context) {
|
|
393
|
+
initContextOptions(options, context);
|
|
394
|
+
},
|
|
395
|
+
finish(context) {
|
|
396
|
+
const rest = context.result["--"];
|
|
397
|
+
for (let i = 0; i < args2.length; i++) {
|
|
398
|
+
if (args2[i].type === "const") {
|
|
399
|
+
if (rest[i] !== args2[i].name) {
|
|
400
|
+
throw new ParseError(`Sub-command ${args2[i].name} mismatch`);
|
|
401
|
+
}
|
|
402
|
+
} else if (args2[i].type === "require") {
|
|
403
|
+
if (i >= rest.length) {
|
|
404
|
+
throw new ParseError(
|
|
405
|
+
`You must provide require argument ${args2[i].name}`
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
context.result.arguments.push(rest[i]);
|
|
409
|
+
} else if (args2[i].type === "optional") {
|
|
410
|
+
context.result.arguments.push(rest[i]);
|
|
411
|
+
} else if (args2[i].type === "rest") {
|
|
412
|
+
context.result.arguments.push(rest.splice(i));
|
|
387
413
|
}
|
|
388
|
-
context.result.arguments.push(rest[i]);
|
|
389
|
-
} else if (args[i].type === "optional") {
|
|
390
|
-
context.result.arguments.push(rest[i]);
|
|
391
|
-
} else if (args[i].type === "rest") {
|
|
392
|
-
context.result.arguments.push(rest.splice(i));
|
|
393
414
|
}
|
|
415
|
+
context.result["--"] = rest.splice(args2.length);
|
|
394
416
|
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
if (
|
|
402
|
-
|
|
403
|
-
throw new BreadcError(
|
|
404
|
-
`Required arguments should be placed before optional or rest arguments`
|
|
405
|
-
);
|
|
406
|
-
}
|
|
407
|
-
const start = i;
|
|
408
|
-
while (i < format.length && format[i] !== ">") {
|
|
409
|
-
i++;
|
|
410
|
-
}
|
|
411
|
-
const name = format.slice(start + 1, i);
|
|
412
|
-
state = 1;
|
|
413
|
-
args.push({ type: "require", name });
|
|
414
|
-
} else if (format[i] === "[") {
|
|
415
|
-
if (state !== 0 && state !== 1) {
|
|
416
|
-
throw new BreadcError(
|
|
417
|
-
`There is at most one optional or rest arguments`
|
|
418
|
-
);
|
|
419
|
-
}
|
|
420
|
-
const start = i;
|
|
421
|
-
while (i < format.length && format[i] !== "]") {
|
|
422
|
-
i++;
|
|
423
|
-
}
|
|
424
|
-
const name = format.slice(start + 1, i);
|
|
425
|
-
state = 2;
|
|
426
|
-
if (name.startsWith("...")) {
|
|
427
|
-
args.push({ type: "rest", name });
|
|
428
|
-
} else {
|
|
429
|
-
args.push({ type: "optional", name });
|
|
430
|
-
}
|
|
431
|
-
} else if (format[i] !== " ") {
|
|
432
|
-
if (state !== 0) {
|
|
433
|
-
throw new BreadcError(
|
|
434
|
-
`Sub-command should be placed at the beginning`
|
|
435
|
-
);
|
|
436
|
-
}
|
|
437
|
-
const start = i;
|
|
438
|
-
while (i < format.length && format[i] !== " ") {
|
|
439
|
-
i++;
|
|
440
|
-
}
|
|
441
|
-
const name = format.slice(start, i);
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
function insertTreeNode(args2, node2, parsed) {
|
|
420
|
+
let cursor = root;
|
|
421
|
+
for (const arg of parsed) {
|
|
422
|
+
args2.push(arg);
|
|
423
|
+
if (arg.type === "const") {
|
|
424
|
+
const name = arg.name;
|
|
442
425
|
if (cursor.children.has(name)) {
|
|
443
426
|
cursor = cursor.children.get(name);
|
|
444
427
|
} else {
|
|
@@ -461,24 +444,70 @@ function makeCommand(format, config, root, container) {
|
|
|
461
444
|
cursor.children.set(name, internalNode);
|
|
462
445
|
cursor = internalNode;
|
|
463
446
|
}
|
|
464
|
-
state = 0;
|
|
465
|
-
args.push({ type: "const", name });
|
|
466
447
|
}
|
|
467
448
|
}
|
|
468
449
|
cursor.command = command;
|
|
469
450
|
if (cursor !== root) {
|
|
470
451
|
for (const [key, value] of cursor.children) {
|
|
471
|
-
|
|
452
|
+
node2.children.set(key, value);
|
|
472
453
|
}
|
|
473
|
-
cursor.children =
|
|
474
|
-
cursor.next =
|
|
475
|
-
cursor.init =
|
|
476
|
-
cursor.finish =
|
|
454
|
+
cursor.children = node2.children;
|
|
455
|
+
cursor.next = node2.next;
|
|
456
|
+
cursor.init = node2.init;
|
|
457
|
+
cursor.finish = node2.finish;
|
|
477
458
|
} else {
|
|
478
|
-
|
|
459
|
+
command._default = true;
|
|
460
|
+
cursor.finish = node2.finish;
|
|
479
461
|
}
|
|
480
462
|
}
|
|
481
|
-
|
|
463
|
+
}
|
|
464
|
+
function* parseCommandFormat(format) {
|
|
465
|
+
let state = 0;
|
|
466
|
+
for (let i = 0; i < format.length; i++) {
|
|
467
|
+
if (format[i] === "<") {
|
|
468
|
+
if (state !== 0 && state !== 1) {
|
|
469
|
+
throw new BreadcError(
|
|
470
|
+
`Required arguments should be placed before optional or rest arguments`
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
const start = i;
|
|
474
|
+
while (i < format.length && format[i] !== ">") {
|
|
475
|
+
i++;
|
|
476
|
+
}
|
|
477
|
+
const name = format.slice(start + 1, i);
|
|
478
|
+
state = 1;
|
|
479
|
+
yield { type: "require", name };
|
|
480
|
+
} else if (format[i] === "[") {
|
|
481
|
+
if (state !== 0 && state !== 1) {
|
|
482
|
+
throw new BreadcError(
|
|
483
|
+
`There is at most one optional or rest arguments`
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
const start = i;
|
|
487
|
+
while (i < format.length && format[i] !== "]") {
|
|
488
|
+
i++;
|
|
489
|
+
}
|
|
490
|
+
const name = format.slice(start + 1, i);
|
|
491
|
+
state = 2;
|
|
492
|
+
if (name.startsWith("...")) {
|
|
493
|
+
yield { type: "rest", name };
|
|
494
|
+
} else {
|
|
495
|
+
yield { type: "optional", name };
|
|
496
|
+
}
|
|
497
|
+
} else if (format[i] !== " ") {
|
|
498
|
+
if (state !== 0) {
|
|
499
|
+
throw new BreadcError(`Sub-command should be placed at the beginning`);
|
|
500
|
+
}
|
|
501
|
+
const start = i;
|
|
502
|
+
while (i < format.length && format[i] !== " ") {
|
|
503
|
+
i++;
|
|
504
|
+
}
|
|
505
|
+
const name = format.slice(start, i);
|
|
506
|
+
state = 0;
|
|
507
|
+
yield { type: "const", name };
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
return void 0;
|
|
482
511
|
}
|
|
483
512
|
function makeVersionCommand(name, config) {
|
|
484
513
|
const command = {
|
|
@@ -491,11 +520,12 @@ function makeVersionCommand(name, config) {
|
|
|
491
520
|
description: "Print version",
|
|
492
521
|
_arguments: [],
|
|
493
522
|
_options: [],
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
523
|
+
// @ts-ignore
|
|
524
|
+
option: void 0,
|
|
525
|
+
// @ts-ignore
|
|
526
|
+
alias: void 0,
|
|
527
|
+
// @ts-ignore
|
|
528
|
+
action: void 0
|
|
499
529
|
};
|
|
500
530
|
const node = makeTreeNode({
|
|
501
531
|
command,
|
|
@@ -517,7 +547,7 @@ function makeVersionCommand(name, config) {
|
|
|
517
547
|
};
|
|
518
548
|
return option;
|
|
519
549
|
}
|
|
520
|
-
function makeHelpCommand(name, config) {
|
|
550
|
+
function makeHelpCommand(name, config, allCommands) {
|
|
521
551
|
function expandMessage(message) {
|
|
522
552
|
const result = [];
|
|
523
553
|
for (const row of message) {
|
|
@@ -556,6 +586,7 @@ function makeHelpCommand(name, config) {
|
|
|
556
586
|
}
|
|
557
587
|
return commands;
|
|
558
588
|
}
|
|
589
|
+
const usage = allCommands.length === 0 ? `[OPTIONS]` : allCommands.length === 1 ? `[OPTIONS] ${allCommands[0].format}` : allCommands.some((c) => c._default) ? `[OPTIONS] [COMMAND]` : `[OPTIONS] <COMMAND>`;
|
|
559
590
|
const command = {
|
|
560
591
|
async callback(parsed) {
|
|
561
592
|
const context = parsed.options.__context__;
|
|
@@ -569,6 +600,8 @@ function makeHelpCommand(name, config) {
|
|
|
569
600
|
return void 0;
|
|
570
601
|
}
|
|
571
602
|
},
|
|
603
|
+
"",
|
|
604
|
+
`${color.bold(color.underline("Usage:"))} ${color.bold(name)} ${usage}`,
|
|
572
605
|
() => {
|
|
573
606
|
const cmds = expandCommands(cursor);
|
|
574
607
|
if (cmds.length > 0) {
|
|
@@ -600,11 +633,12 @@ function makeHelpCommand(name, config) {
|
|
|
600
633
|
description: "Print help",
|
|
601
634
|
_arguments: [],
|
|
602
635
|
_options: [],
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
636
|
+
// @ts-ignore
|
|
637
|
+
option: void 0,
|
|
638
|
+
// @ts-ignore
|
|
639
|
+
alias: void 0,
|
|
640
|
+
// @ts-ignore
|
|
641
|
+
action: void 0
|
|
608
642
|
};
|
|
609
643
|
const node = makeTreeNode({
|
|
610
644
|
command,
|
|
@@ -631,6 +665,7 @@ function makeHelpCommand(name, config) {
|
|
|
631
665
|
|
|
632
666
|
function breadc(name, config = {}) {
|
|
633
667
|
let defaultCommand = void 0;
|
|
668
|
+
const allCommands = [];
|
|
634
669
|
const globalOptions = [];
|
|
635
670
|
const container = makePluginContainer(config.plugins);
|
|
636
671
|
const root = makeTreeNode({
|
|
@@ -640,7 +675,10 @@ function breadc(name, config = {}) {
|
|
|
640
675
|
initContextOptions(defaultCommand._options, context);
|
|
641
676
|
}
|
|
642
677
|
initContextOptions(
|
|
643
|
-
[
|
|
678
|
+
[
|
|
679
|
+
makeHelpCommand(name, config, allCommands),
|
|
680
|
+
makeVersionCommand(name, config)
|
|
681
|
+
],
|
|
644
682
|
context
|
|
645
683
|
);
|
|
646
684
|
},
|
|
@@ -657,9 +695,10 @@ function breadc(name, config = {}) {
|
|
|
657
695
|
command(text, _config = {}) {
|
|
658
696
|
const config2 = typeof _config === "string" ? { description: _config } : _config;
|
|
659
697
|
const command = makeCommand(text, config2, root, container);
|
|
660
|
-
if (command.
|
|
698
|
+
if (command._default) {
|
|
661
699
|
defaultCommand = command;
|
|
662
700
|
}
|
|
701
|
+
allCommands.push(command);
|
|
663
702
|
return command;
|
|
664
703
|
},
|
|
665
704
|
parse(args) {
|
package/dist/index.d.ts
CHANGED
|
@@ -104,10 +104,12 @@ interface Command<F extends string = string, AT extends any[] = ExtractCommand<F
|
|
|
104
104
|
callback?: (result: ParseResult) => Promise<any>;
|
|
105
105
|
format: F;
|
|
106
106
|
description: string;
|
|
107
|
+
_default: boolean;
|
|
107
108
|
_arguments: Argument[];
|
|
108
109
|
_options: Option[];
|
|
109
110
|
option<OF extends string = string, OT extends string | boolean = ExtractOptionType<OF>, OR extends any = ExtractOptionType<OF>>(format: OF, description?: string, option?: OptionOption<OT, OR>): Command<F, AT, CommandOption & ExtractOption<OF, OR>, GlobalOption>;
|
|
110
111
|
option<OF extends string = string, OT extends string | boolean = ExtractOptionType<OF>, OR extends any = ExtractOptionType<OF>>(format: OF, option?: OptionOption<OT, OR>): Command<F, AT, CommandOption & ExtractOption<OF, OR>, GlobalOption>;
|
|
112
|
+
alias(format: string): Command<F, AT, CommandOption, GlobalOption>;
|
|
111
113
|
action(fn: ActionFn<AT, CommandOption & GlobalOption>): void;
|
|
112
114
|
}
|
|
113
115
|
interface CommandOption {
|
package/dist/index.mjs
CHANGED
|
@@ -124,6 +124,7 @@ class Token {
|
|
|
124
124
|
return this._type = "string";
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
|
+
/* c8 ignore next 1 */
|
|
127
128
|
}
|
|
128
129
|
class Lexer {
|
|
129
130
|
constructor(rawArgs) {
|
|
@@ -136,7 +137,7 @@ class Lexer {
|
|
|
136
137
|
return value ? new Token(value) : void 0;
|
|
137
138
|
}
|
|
138
139
|
hasNext() {
|
|
139
|
-
return this.cursor
|
|
140
|
+
return this.cursor < this.rawArgs.length;
|
|
140
141
|
}
|
|
141
142
|
peek() {
|
|
142
143
|
const value = this.rawArgs[this.cursor];
|
|
@@ -149,7 +150,7 @@ class Lexer {
|
|
|
149
150
|
const value = that.rawArgs[that.cursor];
|
|
150
151
|
that.cursor += 1;
|
|
151
152
|
return {
|
|
152
|
-
value: value ? new Token(value) : void 0,
|
|
153
|
+
value: value !== void 0 ? new Token(value) : void 0,
|
|
153
154
|
done: that.cursor > that.rawArgs.length
|
|
154
155
|
};
|
|
155
156
|
}
|
|
@@ -336,13 +337,13 @@ const initContextOptions = (options, context) => {
|
|
|
336
337
|
};
|
|
337
338
|
|
|
338
339
|
function makeCommand(format, config, root, container) {
|
|
339
|
-
let cursor = root;
|
|
340
340
|
const args = [];
|
|
341
341
|
const options = [];
|
|
342
342
|
const command = {
|
|
343
343
|
callback: void 0,
|
|
344
344
|
format,
|
|
345
345
|
description: config.description ?? "",
|
|
346
|
+
_default: false,
|
|
346
347
|
_arguments: args,
|
|
347
348
|
_options: options,
|
|
348
349
|
option(format2, _config, _config2 = {}) {
|
|
@@ -351,6 +352,21 @@ function makeCommand(format, config, root, container) {
|
|
|
351
352
|
options.push(option);
|
|
352
353
|
return command;
|
|
353
354
|
},
|
|
355
|
+
alias(format2) {
|
|
356
|
+
const aliasArgs = [];
|
|
357
|
+
const node2 = makeNode(aliasArgs);
|
|
358
|
+
function* g() {
|
|
359
|
+
for (const f of format2.split(" ")) {
|
|
360
|
+
yield { type: "const", name: f };
|
|
361
|
+
}
|
|
362
|
+
for (const a of args.filter((a2) => a2.type !== "const")) {
|
|
363
|
+
yield a;
|
|
364
|
+
}
|
|
365
|
+
return void 0;
|
|
366
|
+
}
|
|
367
|
+
insertTreeNode(aliasArgs, node2, g());
|
|
368
|
+
return command;
|
|
369
|
+
},
|
|
354
370
|
action(fn) {
|
|
355
371
|
command.callback = async (parsed) => {
|
|
356
372
|
await container.preCommand(command, parsed);
|
|
@@ -363,78 +379,45 @@ function makeCommand(format, config, root, container) {
|
|
|
363
379
|
};
|
|
364
380
|
}
|
|
365
381
|
};
|
|
366
|
-
const node =
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
382
|
+
const node = makeNode(args);
|
|
383
|
+
insertTreeNode(args, node, parseCommandFormat(format));
|
|
384
|
+
return command;
|
|
385
|
+
function makeNode(args2) {
|
|
386
|
+
return makeTreeNode({
|
|
387
|
+
command,
|
|
388
|
+
init(context) {
|
|
389
|
+
initContextOptions(options, context);
|
|
390
|
+
},
|
|
391
|
+
finish(context) {
|
|
392
|
+
const rest = context.result["--"];
|
|
393
|
+
for (let i = 0; i < args2.length; i++) {
|
|
394
|
+
if (args2[i].type === "const") {
|
|
395
|
+
if (rest[i] !== args2[i].name) {
|
|
396
|
+
throw new ParseError(`Sub-command ${args2[i].name} mismatch`);
|
|
397
|
+
}
|
|
398
|
+
} else if (args2[i].type === "require") {
|
|
399
|
+
if (i >= rest.length) {
|
|
400
|
+
throw new ParseError(
|
|
401
|
+
`You must provide require argument ${args2[i].name}`
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
context.result.arguments.push(rest[i]);
|
|
405
|
+
} else if (args2[i].type === "optional") {
|
|
406
|
+
context.result.arguments.push(rest[i]);
|
|
407
|
+
} else if (args2[i].type === "rest") {
|
|
408
|
+
context.result.arguments.push(rest.splice(i));
|
|
383
409
|
}
|
|
384
|
-
context.result.arguments.push(rest[i]);
|
|
385
|
-
} else if (args[i].type === "optional") {
|
|
386
|
-
context.result.arguments.push(rest[i]);
|
|
387
|
-
} else if (args[i].type === "rest") {
|
|
388
|
-
context.result.arguments.push(rest.splice(i));
|
|
389
410
|
}
|
|
411
|
+
context.result["--"] = rest.splice(args2.length);
|
|
390
412
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
if (
|
|
398
|
-
|
|
399
|
-
throw new BreadcError(
|
|
400
|
-
`Required arguments should be placed before optional or rest arguments`
|
|
401
|
-
);
|
|
402
|
-
}
|
|
403
|
-
const start = i;
|
|
404
|
-
while (i < format.length && format[i] !== ">") {
|
|
405
|
-
i++;
|
|
406
|
-
}
|
|
407
|
-
const name = format.slice(start + 1, i);
|
|
408
|
-
state = 1;
|
|
409
|
-
args.push({ type: "require", name });
|
|
410
|
-
} else if (format[i] === "[") {
|
|
411
|
-
if (state !== 0 && state !== 1) {
|
|
412
|
-
throw new BreadcError(
|
|
413
|
-
`There is at most one optional or rest arguments`
|
|
414
|
-
);
|
|
415
|
-
}
|
|
416
|
-
const start = i;
|
|
417
|
-
while (i < format.length && format[i] !== "]") {
|
|
418
|
-
i++;
|
|
419
|
-
}
|
|
420
|
-
const name = format.slice(start + 1, i);
|
|
421
|
-
state = 2;
|
|
422
|
-
if (name.startsWith("...")) {
|
|
423
|
-
args.push({ type: "rest", name });
|
|
424
|
-
} else {
|
|
425
|
-
args.push({ type: "optional", name });
|
|
426
|
-
}
|
|
427
|
-
} else if (format[i] !== " ") {
|
|
428
|
-
if (state !== 0) {
|
|
429
|
-
throw new BreadcError(
|
|
430
|
-
`Sub-command should be placed at the beginning`
|
|
431
|
-
);
|
|
432
|
-
}
|
|
433
|
-
const start = i;
|
|
434
|
-
while (i < format.length && format[i] !== " ") {
|
|
435
|
-
i++;
|
|
436
|
-
}
|
|
437
|
-
const name = format.slice(start, i);
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
function insertTreeNode(args2, node2, parsed) {
|
|
416
|
+
let cursor = root;
|
|
417
|
+
for (const arg of parsed) {
|
|
418
|
+
args2.push(arg);
|
|
419
|
+
if (arg.type === "const") {
|
|
420
|
+
const name = arg.name;
|
|
438
421
|
if (cursor.children.has(name)) {
|
|
439
422
|
cursor = cursor.children.get(name);
|
|
440
423
|
} else {
|
|
@@ -457,24 +440,70 @@ function makeCommand(format, config, root, container) {
|
|
|
457
440
|
cursor.children.set(name, internalNode);
|
|
458
441
|
cursor = internalNode;
|
|
459
442
|
}
|
|
460
|
-
state = 0;
|
|
461
|
-
args.push({ type: "const", name });
|
|
462
443
|
}
|
|
463
444
|
}
|
|
464
445
|
cursor.command = command;
|
|
465
446
|
if (cursor !== root) {
|
|
466
447
|
for (const [key, value] of cursor.children) {
|
|
467
|
-
|
|
448
|
+
node2.children.set(key, value);
|
|
468
449
|
}
|
|
469
|
-
cursor.children =
|
|
470
|
-
cursor.next =
|
|
471
|
-
cursor.init =
|
|
472
|
-
cursor.finish =
|
|
450
|
+
cursor.children = node2.children;
|
|
451
|
+
cursor.next = node2.next;
|
|
452
|
+
cursor.init = node2.init;
|
|
453
|
+
cursor.finish = node2.finish;
|
|
473
454
|
} else {
|
|
474
|
-
|
|
455
|
+
command._default = true;
|
|
456
|
+
cursor.finish = node2.finish;
|
|
475
457
|
}
|
|
476
458
|
}
|
|
477
|
-
|
|
459
|
+
}
|
|
460
|
+
function* parseCommandFormat(format) {
|
|
461
|
+
let state = 0;
|
|
462
|
+
for (let i = 0; i < format.length; i++) {
|
|
463
|
+
if (format[i] === "<") {
|
|
464
|
+
if (state !== 0 && state !== 1) {
|
|
465
|
+
throw new BreadcError(
|
|
466
|
+
`Required arguments should be placed before optional or rest arguments`
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
const start = i;
|
|
470
|
+
while (i < format.length && format[i] !== ">") {
|
|
471
|
+
i++;
|
|
472
|
+
}
|
|
473
|
+
const name = format.slice(start + 1, i);
|
|
474
|
+
state = 1;
|
|
475
|
+
yield { type: "require", name };
|
|
476
|
+
} else if (format[i] === "[") {
|
|
477
|
+
if (state !== 0 && state !== 1) {
|
|
478
|
+
throw new BreadcError(
|
|
479
|
+
`There is at most one optional or rest arguments`
|
|
480
|
+
);
|
|
481
|
+
}
|
|
482
|
+
const start = i;
|
|
483
|
+
while (i < format.length && format[i] !== "]") {
|
|
484
|
+
i++;
|
|
485
|
+
}
|
|
486
|
+
const name = format.slice(start + 1, i);
|
|
487
|
+
state = 2;
|
|
488
|
+
if (name.startsWith("...")) {
|
|
489
|
+
yield { type: "rest", name };
|
|
490
|
+
} else {
|
|
491
|
+
yield { type: "optional", name };
|
|
492
|
+
}
|
|
493
|
+
} else if (format[i] !== " ") {
|
|
494
|
+
if (state !== 0) {
|
|
495
|
+
throw new BreadcError(`Sub-command should be placed at the beginning`);
|
|
496
|
+
}
|
|
497
|
+
const start = i;
|
|
498
|
+
while (i < format.length && format[i] !== " ") {
|
|
499
|
+
i++;
|
|
500
|
+
}
|
|
501
|
+
const name = format.slice(start, i);
|
|
502
|
+
state = 0;
|
|
503
|
+
yield { type: "const", name };
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
return void 0;
|
|
478
507
|
}
|
|
479
508
|
function makeVersionCommand(name, config) {
|
|
480
509
|
const command = {
|
|
@@ -487,11 +516,12 @@ function makeVersionCommand(name, config) {
|
|
|
487
516
|
description: "Print version",
|
|
488
517
|
_arguments: [],
|
|
489
518
|
_options: [],
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
519
|
+
// @ts-ignore
|
|
520
|
+
option: void 0,
|
|
521
|
+
// @ts-ignore
|
|
522
|
+
alias: void 0,
|
|
523
|
+
// @ts-ignore
|
|
524
|
+
action: void 0
|
|
495
525
|
};
|
|
496
526
|
const node = makeTreeNode({
|
|
497
527
|
command,
|
|
@@ -513,7 +543,7 @@ function makeVersionCommand(name, config) {
|
|
|
513
543
|
};
|
|
514
544
|
return option;
|
|
515
545
|
}
|
|
516
|
-
function makeHelpCommand(name, config) {
|
|
546
|
+
function makeHelpCommand(name, config, allCommands) {
|
|
517
547
|
function expandMessage(message) {
|
|
518
548
|
const result = [];
|
|
519
549
|
for (const row of message) {
|
|
@@ -552,6 +582,7 @@ function makeHelpCommand(name, config) {
|
|
|
552
582
|
}
|
|
553
583
|
return commands;
|
|
554
584
|
}
|
|
585
|
+
const usage = allCommands.length === 0 ? `[OPTIONS]` : allCommands.length === 1 ? `[OPTIONS] ${allCommands[0].format}` : allCommands.some((c) => c._default) ? `[OPTIONS] [COMMAND]` : `[OPTIONS] <COMMAND>`;
|
|
555
586
|
const command = {
|
|
556
587
|
async callback(parsed) {
|
|
557
588
|
const context = parsed.options.__context__;
|
|
@@ -565,6 +596,8 @@ function makeHelpCommand(name, config) {
|
|
|
565
596
|
return void 0;
|
|
566
597
|
}
|
|
567
598
|
},
|
|
599
|
+
"",
|
|
600
|
+
`${bold(underline("Usage:"))} ${bold(name)} ${usage}`,
|
|
568
601
|
() => {
|
|
569
602
|
const cmds = expandCommands(cursor);
|
|
570
603
|
if (cmds.length > 0) {
|
|
@@ -596,11 +629,12 @@ function makeHelpCommand(name, config) {
|
|
|
596
629
|
description: "Print help",
|
|
597
630
|
_arguments: [],
|
|
598
631
|
_options: [],
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
632
|
+
// @ts-ignore
|
|
633
|
+
option: void 0,
|
|
634
|
+
// @ts-ignore
|
|
635
|
+
alias: void 0,
|
|
636
|
+
// @ts-ignore
|
|
637
|
+
action: void 0
|
|
604
638
|
};
|
|
605
639
|
const node = makeTreeNode({
|
|
606
640
|
command,
|
|
@@ -627,6 +661,7 @@ function makeHelpCommand(name, config) {
|
|
|
627
661
|
|
|
628
662
|
function breadc(name, config = {}) {
|
|
629
663
|
let defaultCommand = void 0;
|
|
664
|
+
const allCommands = [];
|
|
630
665
|
const globalOptions = [];
|
|
631
666
|
const container = makePluginContainer(config.plugins);
|
|
632
667
|
const root = makeTreeNode({
|
|
@@ -636,7 +671,10 @@ function breadc(name, config = {}) {
|
|
|
636
671
|
initContextOptions(defaultCommand._options, context);
|
|
637
672
|
}
|
|
638
673
|
initContextOptions(
|
|
639
|
-
[
|
|
674
|
+
[
|
|
675
|
+
makeHelpCommand(name, config, allCommands),
|
|
676
|
+
makeVersionCommand(name, config)
|
|
677
|
+
],
|
|
640
678
|
context
|
|
641
679
|
);
|
|
642
680
|
},
|
|
@@ -653,9 +691,10 @@ function breadc(name, config = {}) {
|
|
|
653
691
|
command(text, _config = {}) {
|
|
654
692
|
const config2 = typeof _config === "string" ? { description: _config } : _config;
|
|
655
693
|
const command = makeCommand(text, config2, root, container);
|
|
656
|
-
if (command.
|
|
694
|
+
if (command._default) {
|
|
657
695
|
defaultCommand = command;
|
|
658
696
|
}
|
|
697
|
+
allCommands.push(command);
|
|
659
698
|
return command;
|
|
660
699
|
},
|
|
661
700
|
parse(args) {
|
package/package.json
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "breadc",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.4",
|
|
4
4
|
"description": "Yet another Command Line Application Framework with fully strong TypeScript support",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"breadc",
|
|
7
7
|
"cli",
|
|
8
8
|
"framework",
|
|
9
9
|
"command-line",
|
|
10
|
-
"minimist",
|
|
11
10
|
"typescript"
|
|
12
11
|
],
|
|
13
12
|
"homepage": "https://github.com/yjl9903/Breadc#readme",
|
|
@@ -35,7 +34,7 @@
|
|
|
35
34
|
"dist"
|
|
36
35
|
],
|
|
37
36
|
"dependencies": {
|
|
38
|
-
"@breadc/color": "0.8.
|
|
37
|
+
"@breadc/color": "0.8.4"
|
|
39
38
|
},
|
|
40
39
|
"devDependencies": {
|
|
41
40
|
"@types/node": "^18.11.18",
|