maoda-commander-tt 0.0.3 → 0.0.5
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 -0
- package/dist/{chunk-PWVGB2ON.js → chunk-4BGIPPGC.js} +286 -8
- package/dist/chunk-4BGIPPGC.js.map +1 -0
- package/dist/index.d.ts +95 -18
- package/dist/index.js +3 -1
- package/dist/main.js +1058 -13
- package/dist/main.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-PWVGB2ON.js.map +0 -1
package/README.md
CHANGED
|
@@ -122,6 +122,7 @@ app.registerCommand(new MyCommand());
|
|
|
122
122
|
| `_execute(ctx)` | 命令核心逻辑,返回 `ILvErrorOr<void>` |
|
|
123
123
|
| `_configureOptions(cmd)` | (可选) 配置 commander 选项 |
|
|
124
124
|
| `_configureArguments(cmd)` | (可选) 配置 commander 参数 |
|
|
125
|
+
| `getExample()` | 根据已注册的参数和选项自动生成命令执行示例 |
|
|
125
126
|
|
|
126
127
|
### 生命周期事件
|
|
127
128
|
|
|
@@ -378,6 +378,19 @@ function makeOk() {
|
|
|
378
378
|
// 跳过类型检测
|
|
379
379
|
};
|
|
380
380
|
}
|
|
381
|
+
function makeOkWith(value) {
|
|
382
|
+
return {
|
|
383
|
+
ok: true,
|
|
384
|
+
value,
|
|
385
|
+
pair() {
|
|
386
|
+
return [null, value];
|
|
387
|
+
},
|
|
388
|
+
code: 0,
|
|
389
|
+
msg: "",
|
|
390
|
+
...{ [lvErrorRefSymbol]: true }
|
|
391
|
+
// 跳过类型检测
|
|
392
|
+
};
|
|
393
|
+
}
|
|
381
394
|
function printCause(cause) {
|
|
382
395
|
if (cause === void 0) {
|
|
383
396
|
return "";
|
|
@@ -461,7 +474,6 @@ var CliApp = class extends Disposable {
|
|
|
461
474
|
this._program.name(_options.name).version(_options.version, "-v, --version", "\u8F93\u51FA\u7248\u672C\u53F7").description(_options.description).helpOption("-h, --help", "\u663E\u793A\u5E2E\u52A9\u4FE1\u606F").addHelpCommand("help [command]", "\u663E\u793A\u6307\u5B9A\u547D\u4EE4\u7684\u5E2E\u52A9\u4FE1\u606F");
|
|
462
475
|
}
|
|
463
476
|
_program;
|
|
464
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
465
477
|
_commands = [];
|
|
466
478
|
_onBeforeRun = this._register(new Emitter());
|
|
467
479
|
_onAfterRun = this._register(new Emitter());
|
|
@@ -470,16 +482,26 @@ var CliApp = class extends Disposable {
|
|
|
470
482
|
get program() {
|
|
471
483
|
return this._program;
|
|
472
484
|
}
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
485
|
+
registerCommand(cmd, options = {}) {
|
|
486
|
+
this._commands.push({
|
|
487
|
+
command: cmd,
|
|
488
|
+
hidden: options.hidden ?? false
|
|
489
|
+
});
|
|
476
490
|
this._register(cmd);
|
|
477
|
-
this._program.addCommand(
|
|
491
|
+
this._program.addCommand(
|
|
492
|
+
cmd.command,
|
|
493
|
+
options.hidden ? { hidden: true } : void 0
|
|
494
|
+
);
|
|
478
495
|
}
|
|
479
496
|
async run(argv) {
|
|
480
497
|
const args = argv ?? process.argv;
|
|
481
498
|
this._onBeforeRun.fire(args);
|
|
482
499
|
try {
|
|
500
|
+
if (this._isDoubleHelp(args)) {
|
|
501
|
+
this.outputHelp(true);
|
|
502
|
+
this._onAfterRun.fire();
|
|
503
|
+
return makeOk();
|
|
504
|
+
}
|
|
483
505
|
await this._program.parseAsync(args);
|
|
484
506
|
this._onAfterRun.fire();
|
|
485
507
|
return makeOk();
|
|
@@ -492,14 +514,129 @@ var CliApp = class extends Disposable {
|
|
|
492
514
|
this._commands.length = 0;
|
|
493
515
|
super.dispose();
|
|
494
516
|
}
|
|
517
|
+
outputHelp(includeHidden = false) {
|
|
518
|
+
process.stdout.write(this.helpInformation(includeHidden));
|
|
519
|
+
}
|
|
520
|
+
helpInformation(includeHidden = false) {
|
|
521
|
+
if (!includeHidden) {
|
|
522
|
+
return this._program.helpInformation();
|
|
523
|
+
}
|
|
524
|
+
const hiddenCommands = this._commands.filter((entry) => entry.hidden).map((entry) => entry.command.command);
|
|
525
|
+
const previousHiddenStates = hiddenCommands.map((command) => {
|
|
526
|
+
const rawCommand = command;
|
|
527
|
+
const previousHidden = rawCommand._hidden;
|
|
528
|
+
rawCommand._hidden = false;
|
|
529
|
+
return previousHidden;
|
|
530
|
+
});
|
|
531
|
+
try {
|
|
532
|
+
return this._program.helpInformation();
|
|
533
|
+
} finally {
|
|
534
|
+
hiddenCommands.forEach((command, index) => {
|
|
535
|
+
const rawCommand = command;
|
|
536
|
+
rawCommand._hidden = previousHiddenStates[index];
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
_isDoubleHelp(argv) {
|
|
541
|
+
const userArgs = argv.slice(2);
|
|
542
|
+
return userArgs.length > 0 && userArgs[0] === "-hh";
|
|
543
|
+
}
|
|
495
544
|
};
|
|
496
545
|
|
|
497
546
|
// src/core/base-command.ts
|
|
498
547
|
import { Command as Command2 } from "commander";
|
|
548
|
+
|
|
549
|
+
// src/bedrock/response/response.ts
|
|
550
|
+
function makeSuccessResponse(data) {
|
|
551
|
+
return {
|
|
552
|
+
code: 0,
|
|
553
|
+
data,
|
|
554
|
+
msg: "success"
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
function makeErrorResponse(code, msg) {
|
|
558
|
+
return {
|
|
559
|
+
code,
|
|
560
|
+
msg
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// src/core/command-example.ts
|
|
565
|
+
function _getCommandPath(command) {
|
|
566
|
+
const names = [];
|
|
567
|
+
for (let current = command; current; current = current.parent) {
|
|
568
|
+
names.unshift(current.name());
|
|
569
|
+
}
|
|
570
|
+
return names;
|
|
571
|
+
}
|
|
572
|
+
function _getRepresentativeValue(name, defaultValue, choices) {
|
|
573
|
+
if (defaultValue !== void 0) {
|
|
574
|
+
return String(defaultValue);
|
|
575
|
+
}
|
|
576
|
+
if (choices && choices.length > 0) {
|
|
577
|
+
return choices[0];
|
|
578
|
+
}
|
|
579
|
+
return name;
|
|
580
|
+
}
|
|
581
|
+
function _formatArgument(argument) {
|
|
582
|
+
const name = argument.name();
|
|
583
|
+
const token = _getRepresentativeValue(name, argument.defaultValue, argument.argChoices);
|
|
584
|
+
const hasConcreteValue = argument.defaultValue !== void 0 || argument.argChoices !== void 0 && argument.argChoices.length > 0;
|
|
585
|
+
if (hasConcreteValue) {
|
|
586
|
+
return argument.variadic ? `${token}...` : token;
|
|
587
|
+
}
|
|
588
|
+
if (argument.required) {
|
|
589
|
+
return `<${argument.variadic ? `${token}...` : token}>`;
|
|
590
|
+
}
|
|
591
|
+
return `[${argument.variadic ? `${token}...` : token}]`;
|
|
592
|
+
}
|
|
593
|
+
function _getOptionFlag(option) {
|
|
594
|
+
return option.short ?? option.long ?? option.flags.split(",")[0].trim();
|
|
595
|
+
}
|
|
596
|
+
function _isHiddenHelpOption(option) {
|
|
597
|
+
return option.hidden || option.flags.includes("--help");
|
|
598
|
+
}
|
|
599
|
+
function _formatOption(option) {
|
|
600
|
+
if (_isHiddenHelpOption(option)) {
|
|
601
|
+
return null;
|
|
602
|
+
}
|
|
603
|
+
const flag = _getOptionFlag(option);
|
|
604
|
+
if (option.isBoolean()) {
|
|
605
|
+
if (!option.mandatory && option.defaultValue === false) {
|
|
606
|
+
return null;
|
|
607
|
+
}
|
|
608
|
+
return flag;
|
|
609
|
+
}
|
|
610
|
+
const value = _getRepresentativeValue(
|
|
611
|
+
option.attributeName(),
|
|
612
|
+
option.defaultValue,
|
|
613
|
+
option.argChoices
|
|
614
|
+
);
|
|
615
|
+
const hasConcreteValue = option.defaultValue !== void 0 || option.argChoices !== void 0 && option.argChoices.length > 0;
|
|
616
|
+
if (!option.mandatory && option.defaultValue !== void 0) {
|
|
617
|
+
return null;
|
|
618
|
+
}
|
|
619
|
+
if (hasConcreteValue) {
|
|
620
|
+
return `${flag} ${value}`;
|
|
621
|
+
}
|
|
622
|
+
return `${flag} ${option.required ? value : `[${value}]`}`;
|
|
623
|
+
}
|
|
624
|
+
function makeCommandExample(command) {
|
|
625
|
+
const parts = _getCommandPath(command);
|
|
626
|
+
const optionParts = command.options.map((option) => _formatOption(option)).filter((part) => part !== null);
|
|
627
|
+
const argumentParts = command.registeredArguments.map(
|
|
628
|
+
(argument) => _formatArgument(argument)
|
|
629
|
+
);
|
|
630
|
+
return [...parts, ...optionParts, ...argumentParts].join(" ").replace(/\s+/g, " ").trim();
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// src/core/base-command.ts
|
|
499
634
|
var BaseCommand = class extends Disposable {
|
|
500
635
|
_command;
|
|
501
636
|
_onBeforeExecute = this._register(new Emitter());
|
|
502
|
-
_onAfterExecute = this._register(
|
|
637
|
+
_onAfterExecute = this._register(
|
|
638
|
+
new Emitter()
|
|
639
|
+
);
|
|
503
640
|
onBeforeExecute = this._onBeforeExecute.event;
|
|
504
641
|
onAfterExecute = this._onAfterExecute.event;
|
|
505
642
|
constructor() {
|
|
@@ -512,6 +649,12 @@ var BaseCommand = class extends Disposable {
|
|
|
512
649
|
}
|
|
513
650
|
this._configureOptions(this._command);
|
|
514
651
|
this._configureArguments(this._command);
|
|
652
|
+
this._command.addHelpText("after", () => {
|
|
653
|
+
return `
|
|
654
|
+
\u6267\u884C\u6848\u4F8B:
|
|
655
|
+
${this.getExample()}
|
|
656
|
+
`;
|
|
657
|
+
});
|
|
515
658
|
this._command.action(async (...rawArgs) => {
|
|
516
659
|
const ctx = this._parseActionArgs(rawArgs);
|
|
517
660
|
this._onBeforeExecute.fire();
|
|
@@ -533,6 +676,12 @@ var BaseCommand = class extends Disposable {
|
|
|
533
676
|
get command() {
|
|
534
677
|
return this._command;
|
|
535
678
|
}
|
|
679
|
+
/**
|
|
680
|
+
* 返回该命令的执行示例,供外部展示或调试使用。
|
|
681
|
+
*/
|
|
682
|
+
getExample() {
|
|
683
|
+
return makeCommandExample(this._command);
|
|
684
|
+
}
|
|
536
685
|
_configureOptions(_cmd) {
|
|
537
686
|
}
|
|
538
687
|
_configureArguments(_cmd) {
|
|
@@ -543,6 +692,131 @@ var BaseCommand = class extends Disposable {
|
|
|
543
692
|
_makeError(code, msg) {
|
|
544
693
|
return makeError(code, msg);
|
|
545
694
|
}
|
|
695
|
+
/**
|
|
696
|
+
* 向 stdout 输出一行文本(最终用户可见的输出)
|
|
697
|
+
*/
|
|
698
|
+
_output(text) {
|
|
699
|
+
process.stdout.write(text + "\n");
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* 向 stderr 输出调试 / 诊断信息(不会混入最终输出)
|
|
703
|
+
*/
|
|
704
|
+
_debug(text) {
|
|
705
|
+
process.stderr.write(`[debug] ${text}
|
|
706
|
+
`);
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* 以 JSON 字符串形式输出成功结果到 stdout
|
|
710
|
+
*/
|
|
711
|
+
_outputJsonOk(data) {
|
|
712
|
+
process.stdout.write(
|
|
713
|
+
JSON.stringify(makeSuccessResponse(data), null, 2) + "\n"
|
|
714
|
+
);
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* 以 JSON 字符串形式输出错误结果到 stdout
|
|
718
|
+
*/
|
|
719
|
+
_outputJsonError(code, msg) {
|
|
720
|
+
process.stdout.write(
|
|
721
|
+
JSON.stringify(makeErrorResponse(code, msg), null, 2) + "\n"
|
|
722
|
+
);
|
|
723
|
+
}
|
|
724
|
+
_parseActionArgs(rawArgs) {
|
|
725
|
+
const command = rawArgs[rawArgs.length - 1];
|
|
726
|
+
const options = rawArgs[rawArgs.length - 2];
|
|
727
|
+
const args = rawArgs.slice(0, rawArgs.length - 2);
|
|
728
|
+
return { args, options, command };
|
|
729
|
+
}
|
|
730
|
+
};
|
|
731
|
+
|
|
732
|
+
// src/core/base-subcommand-host.ts
|
|
733
|
+
import { Command as Command3 } from "commander";
|
|
734
|
+
var BaseSubcommandHost = class extends Disposable {
|
|
735
|
+
_command;
|
|
736
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
737
|
+
_subcommands = [];
|
|
738
|
+
_onBeforeExecute = this._register(new Emitter());
|
|
739
|
+
_onAfterExecute = this._register(
|
|
740
|
+
new Emitter()
|
|
741
|
+
);
|
|
742
|
+
onBeforeExecute = this._onBeforeExecute.event;
|
|
743
|
+
onAfterExecute = this._onAfterExecute.event;
|
|
744
|
+
constructor() {
|
|
745
|
+
super();
|
|
746
|
+
const meta = this._meta();
|
|
747
|
+
this._command = new Command3(meta.name);
|
|
748
|
+
this._command.description(meta.description);
|
|
749
|
+
if (meta.aliases) {
|
|
750
|
+
this._command.aliases(meta.aliases);
|
|
751
|
+
}
|
|
752
|
+
this._configureOptions(this._command);
|
|
753
|
+
this._registerSubcommands();
|
|
754
|
+
this._command.action(async (...rawArgs) => {
|
|
755
|
+
const ctx = this._parseActionArgs(rawArgs);
|
|
756
|
+
this._onBeforeExecute.fire();
|
|
757
|
+
let result;
|
|
758
|
+
try {
|
|
759
|
+
result = await this._executeFallback(ctx);
|
|
760
|
+
} catch (err) {
|
|
761
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
762
|
+
result = makeError(1, `Command "${meta.name}" failed: ${message}`);
|
|
763
|
+
}
|
|
764
|
+
this._onAfterExecute.fire(result);
|
|
765
|
+
if (!result.ok) {
|
|
766
|
+
process.stderr.write(`Error [${result.code}]: ${result.msg}
|
|
767
|
+
`);
|
|
768
|
+
process.exitCode = 1;
|
|
769
|
+
}
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
get command() {
|
|
773
|
+
return this._command;
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* 返回该命令宿主的执行示例,供外部展示或调试使用。
|
|
777
|
+
*/
|
|
778
|
+
getExample() {
|
|
779
|
+
return makeCommandExample(this._command);
|
|
780
|
+
}
|
|
781
|
+
/**
|
|
782
|
+
* 当用户没有指定子命令时的默认行为。
|
|
783
|
+
* 默认显示帮助信息,子类可覆盖。
|
|
784
|
+
*/
|
|
785
|
+
_executeFallback(_ctx) {
|
|
786
|
+
this._command.outputHelp();
|
|
787
|
+
return Promise.resolve(makeOk());
|
|
788
|
+
}
|
|
789
|
+
_configureOptions(_cmd) {
|
|
790
|
+
}
|
|
791
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
792
|
+
_addSubcommand(cmd) {
|
|
793
|
+
this._subcommands.push(cmd);
|
|
794
|
+
this._register(cmd);
|
|
795
|
+
this._command.addCommand(cmd.command);
|
|
796
|
+
}
|
|
797
|
+
_makeOk() {
|
|
798
|
+
return makeOk();
|
|
799
|
+
}
|
|
800
|
+
_makeError(code, msg) {
|
|
801
|
+
return makeError(code, msg);
|
|
802
|
+
}
|
|
803
|
+
_output(text) {
|
|
804
|
+
process.stdout.write(text + "\n");
|
|
805
|
+
}
|
|
806
|
+
_debug(text) {
|
|
807
|
+
process.stderr.write(`[debug] ${text}
|
|
808
|
+
`);
|
|
809
|
+
}
|
|
810
|
+
_outputJsonOk(data) {
|
|
811
|
+
process.stdout.write(JSON.stringify(makeSuccessResponse(data)) + "\n");
|
|
812
|
+
}
|
|
813
|
+
_outputJsonError(code, msg) {
|
|
814
|
+
process.stdout.write(JSON.stringify(makeErrorResponse(code, msg)) + "\n");
|
|
815
|
+
}
|
|
816
|
+
dispose() {
|
|
817
|
+
this._subcommands.length = 0;
|
|
818
|
+
super.dispose();
|
|
819
|
+
}
|
|
546
820
|
_parseActionArgs(rawArgs) {
|
|
547
821
|
const command = rawArgs[rawArgs.length - 1];
|
|
548
822
|
const options = rawArgs[rawArgs.length - 2];
|
|
@@ -552,7 +826,11 @@ var BaseCommand = class extends Disposable {
|
|
|
552
826
|
};
|
|
553
827
|
|
|
554
828
|
export {
|
|
829
|
+
makeOkWith,
|
|
830
|
+
makeError,
|
|
831
|
+
lvErrorConst,
|
|
555
832
|
CliApp,
|
|
556
|
-
BaseCommand
|
|
833
|
+
BaseCommand,
|
|
834
|
+
BaseSubcommandHost
|
|
557
835
|
};
|
|
558
|
-
//# sourceMappingURL=chunk-
|
|
836
|
+
//# sourceMappingURL=chunk-4BGIPPGC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/cli-app.ts","../src/bedrock/dispose/dispose-base.ts","../src/bedrock/dispose/logger.ts","../src/bedrock/dispose/tracker.ts","../src/bedrock/dispose/disposable-store.ts","../src/bedrock/dispose/disposable-t.ts","../src/bedrock/dispose/disposable-utils.ts","../src/bedrock/structure/linked-list.ts","../src/bedrock/dispose/disposable-linked-list.ts","../src/bedrock/event/error-handler.ts","../src/bedrock/event/emitter.ts","../src/bedrock/error/error-t.ts","../src/bedrock/error/error-const.ts","../src/bedrock/error/error-code.ts","../src/core/base-command.ts","../src/bedrock/response/response.ts","../src/core/command-example.ts","../src/core/base-subcommand-host.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { Disposable } from '../bedrock/dispose';\nimport { Emitter } from '../bedrock/event';\nimport type { Event } from '../bedrock/event';\nimport type { ILvErrorOr } from '../bedrock/error';\nimport { makeOk, makeError } from '../bedrock/error';\nimport type { IRegistrableCommand } from './command-types';\n\nexport interface IRegisterCommandOptions {\n readonly hidden?: boolean;\n}\n\ninterface IRegisteredCommand {\n readonly command: IRegistrableCommand;\n readonly hidden: boolean;\n}\n\nexport interface ICliAppOptions {\n readonly name: string;\n readonly version: string;\n readonly description: string;\n}\n\nexport class CliApp extends Disposable {\n private readonly _program: Command;\n private readonly _commands: IRegisteredCommand[] = [];\n\n private readonly _onBeforeRun = this._register(new Emitter<[string[]]>());\n private readonly _onAfterRun = this._register(new Emitter<[]>());\n\n public readonly onBeforeRun: Event<[string[]]> = this._onBeforeRun.event;\n public readonly onAfterRun: Event<[]> = this._onAfterRun.event;\n\n constructor(private readonly _options: ICliAppOptions) {\n super();\n this._program = new Command();\n this._program\n .name(_options.name)\n .version(_options.version, '-v, --version', '输出版本号')\n .description(_options.description)\n .helpOption('-h, --help', '显示帮助信息')\n .addHelpCommand('help [command]', '显示指定命令的帮助信息');\n }\n\n public get program(): Command {\n return this._program;\n }\n\n public registerCommand(\n cmd: IRegistrableCommand,\n options: IRegisterCommandOptions = {},\n ): void {\n this._commands.push({\n command: cmd,\n hidden: options.hidden ?? false,\n });\n this._register(cmd);\n this._program.addCommand(\n cmd.command,\n options.hidden ? { hidden: true } : undefined,\n );\n }\n\n public async run(argv?: string[]): Promise<ILvErrorOr<void>> {\n const args = argv ?? process.argv;\n this._onBeforeRun.fire(args);\n\n try {\n if (this._isDoubleHelp(args)) {\n this.outputHelp(true);\n this._onAfterRun.fire();\n return makeOk();\n }\n\n await this._program.parseAsync(args);\n this._onAfterRun.fire();\n return makeOk();\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return makeError(1, `CLI execution failed: ${message}`);\n }\n }\n\n public override dispose(): void {\n this._commands.length = 0;\n super.dispose();\n }\n\n public outputHelp(includeHidden = false): void {\n process.stdout.write(this.helpInformation(includeHidden));\n }\n\n public helpInformation(includeHidden = false): string {\n if (!includeHidden) {\n return this._program.helpInformation();\n }\n\n const hiddenCommands = this._commands\n .filter((entry) => entry.hidden)\n .map((entry) => entry.command.command);\n const previousHiddenStates = hiddenCommands.map((command) => {\n const rawCommand = command as unknown as { _hidden?: boolean };\n const previousHidden = rawCommand._hidden;\n rawCommand._hidden = false;\n return previousHidden;\n });\n\n try {\n return this._program.helpInformation();\n } finally {\n hiddenCommands.forEach((command, index) => {\n const rawCommand = command as unknown as { _hidden?: boolean };\n rawCommand._hidden = previousHiddenStates[index];\n });\n }\n }\n\n private _isDoubleHelp(argv: string[]): boolean {\n const userArgs = argv.slice(2);\n return userArgs.length > 0 && userArgs[0] === '-hh';\n }\n}\n","//\n// Disposable特征约束\n//\nexport interface IDisposable {\n dispose: () => void;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-function\nexport const EmptyDispose = Object.freeze<IDisposable>({ dispose() {} });\n","import type { IDisposable } from './dispose-base';\n\nlet disposableLogger: IDisposableLogger | null = null;\n\nexport interface IDisposableLogger {\n branch: (from: string, to: string) => void;\n end: () => void;\n}\n\nfunction setDisposableLogger(logger: IDisposableLogger | null): void {\n disposableLogger = logger;\n}\n\nfunction makeDefaultLogger() {\n return new (class implements IDisposableLogger {\n private readonly _dep: [string, string][] = [];\n\n branch(from: string, to: string): void {\n this._dep.push([from, to]);\n }\n\n end(): void {\n // console.log(this._dep);\n }\n })();\n}\n\n// 辅助能力 dispose触发时记录\nexport function BRANCH_DISPOSE(from: string, to: string) {\n disposableLogger?.branch(from, to);\n}\n\nexport function disposeWithLog<T extends IDisposable>(\n x: T,\n logger: IDisposableLogger = makeDefaultLogger(),\n) {\n setDisposableLogger(logger);\n x.dispose();\n logger.end();\n setDisposableLogger(null);\n}\n","import type { IDisposable } from './dispose-base';\nimport { EmptyDispose } from './dispose-base';\n\nexport interface IDisposableTracker {\n trackDisposable: (disposable: IDisposable) => void;\n\n setParent: (child: IDisposable, parent: IDisposable | null) => void;\n\n markAsDisposed: (disposable: IDisposable) => void;\n\n markAsSingleton: (disposable: IDisposable) => void;\n}\n\nlet disposableTracker: IDisposableTracker | null = null;\n\nfunction makeDefaultTracker() {\n const __is_disposable_tracked__ = '__is_disposable_tracked__';\n return new (class implements IDisposableTracker {\n trackDisposable(x: IDisposable): void {\n const stack = new Error('Potentially leaked disposable').stack!;\n setTimeout(() => {\n if (!(x as any)[__is_disposable_tracked__]) {\n // console.log(stack);\n }\n }, 3000);\n }\n\n setParent(child: IDisposable, parent: IDisposable | null): void {\n if (child && child !== EmptyDispose) {\n try {\n (child as any)[__is_disposable_tracked__] = true;\n } catch {\n // noop\n }\n }\n }\n\n markAsDisposed(disposable: IDisposable): void {\n if (disposable && disposable !== EmptyDispose) {\n try {\n (disposable as any)[__is_disposable_tracked__] = true;\n } catch {\n // noop\n }\n }\n }\n\n markAsSingleton(disposable: IDisposable): void {}\n })();\n}\n\nfunction setDisposableTracker(tracker: IDisposableTracker | null): void {\n disposableTracker = tracker;\n}\n\nexport function enableTrack(tracker: IDisposableTracker = makeDefaultTracker()) {\n setDisposableTracker(tracker);\n}\n\nexport function disableTrack() {\n setDisposableTracker(null);\n}\n\n// 辅助能力 跟踪disposable\nexport function TRACK_DISPOSABLE<T extends IDisposable>(x: T): T {\n disposableTracker?.trackDisposable(x);\n return x;\n}\n\n// 辅助能力 标记disposable成功\nexport function MARK_AS_DISPOSED<T extends IDisposable>(x: T): void {\n disposableTracker?.markAsDisposed(x);\n}\n\n// 辅助能力 标记disposable关系\nexport function SET_PARENT_OF_DISPOSABLE(child: IDisposable, parent: IDisposable | null): void {\n disposableTracker?.setParent(child, parent);\n}\n","import type { IDisposable } from './dispose-base';\nimport { BRANCH_DISPOSE } from './logger';\nimport { MARK_AS_DISPOSED, SET_PARENT_OF_DISPOSABLE, TRACK_DISPOSABLE } from './tracker';\n\nexport class DisposableStore implements IDisposable {\n static DISABLE_DISPOSED_WARNING = false;\n\n private readonly _toDispose = new Set<IDisposable>();\n private _isDisposed = false;\n\n constructor() {\n TRACK_DISPOSABLE(this);\n }\n\n get isDisposed(): boolean {\n return this._isDisposed;\n }\n\n dispose(): void {\n if (this._isDisposed) {\n // 不应该出现重复dispose\n /* eslint-disable no-console */\n console.warn(new Error('DisposableStore has disposed.').stack);\n return;\n }\n\n MARK_AS_DISPOSED(this);\n this._isDisposed = true;\n this.clear();\n }\n\n clear(): void {\n if (this._toDispose.size === 0) {\n return;\n }\n\n for (const disposable of this._toDispose) {\n BRANCH_DISPOSE(this.constructor.name, disposable.constructor.name);\n }\n\n try {\n // TODO(vorshen): 考虑异常情况\n for (const disposable of this._toDispose) {\n disposable.dispose();\n }\n } finally {\n this._toDispose.clear();\n }\n }\n\n add<T extends IDisposable>(o: T): T {\n if (!o) {\n return o;\n }\n if ((o as unknown as DisposableStore) === this) {\n throw new Error('Cannot register a disposable on itself.');\n }\n\n SET_PARENT_OF_DISPOSABLE(o, this);\n if (this._isDisposed) {\n if (!DisposableStore.DISABLE_DISPOSED_WARNING) {\n /* eslint-disable no-console */\n console.warn(\n new Error(\n 'Trying to add a disposable to a DisposableStore that has already been disposed of. The added object will be leaked!',\n ).stack,\n );\n }\n } else {\n this._toDispose.add(o);\n }\n\n return o;\n }\n}\n","import { DisposableStore } from './disposable-store';\nimport type { IDisposable } from './dispose-base';\nimport { BRANCH_DISPOSE } from './logger';\nimport { MARK_AS_DISPOSED, SET_PARENT_OF_DISPOSABLE, TRACK_DISPOSABLE } from './tracker';\n\n//\n// Disposable基类\n//\n// 自动添加DisposableStore,提供默认的dispose和register方法\n//\nexport abstract class Disposable implements IDisposable {\n protected readonly _store = new DisposableStore();\n\n constructor() {\n TRACK_DISPOSABLE(this);\n SET_PARENT_OF_DISPOSABLE(this._store, this);\n }\n\n // 销毁该节点和所有的子节点\n dispose(): void {\n MARK_AS_DISPOSED(this);\n BRANCH_DISPOSE(this.constructor.name, this._store.constructor.name);\n\n this._store.dispose();\n }\n\n // 挂载子节点\n protected _register<T extends IDisposable>(o: T): T {\n if ((o as unknown as Disposable) === this) {\n throw new Error('Cannot register a disposable on itself!');\n }\n return this._store.add(o);\n }\n}\n\nexport class MutableDisposable<T extends IDisposable> implements IDisposable {\n private _value?: T;\n private _isDisposed = false;\n\n constructor(value?: T) {\n TRACK_DISPOSABLE(this);\n this.value = value;\n }\n\n get value(): T | undefined {\n return this._isDisposed ? undefined : this._value;\n }\n\n set value(value: T | undefined) {\n if (this._isDisposed || value === this._value) {\n return;\n }\n\n this._value?.dispose();\n if (value) {\n SET_PARENT_OF_DISPOSABLE(value, this);\n }\n this._value = value;\n }\n\n clear(): void {\n this.value = undefined;\n }\n\n dispose(): void {\n this._isDisposed = true;\n MARK_AS_DISPOSED(this);\n this._value?.dispose();\n this._value = undefined;\n }\n\n release(): T | undefined {\n const oldValue = this._value;\n this._value = undefined;\n if (oldValue) {\n SET_PARENT_OF_DISPOSABLE(oldValue, null);\n }\n return oldValue;\n }\n}\n\nexport class SafeDisposable<T extends IDisposable> implements IDisposable {\n private _value: T | null = null;\n\n constructor(value: T) {\n this._value = value;\n TRACK_DISPOSABLE(this);\n }\n\n isEmpty() {\n return this._value === null;\n }\n\n dispose() {\n if (!this._value) {\n return;\n }\n this._value.dispose();\n this._value = null;\n MARK_AS_DISPOSED(this);\n }\n}\n","import { SafeDisposable } from './disposable-t';\nimport { EmptyDispose } from './dispose-base';\n\nexport function makeSafeDisposable(fn: (...args: any) => any) {\n const disposable = new SafeDisposable({\n dispose: fn,\n });\n return disposable;\n}\n\nexport function makeEmptyDisposable() {\n return EmptyDispose;\n}\n","class Node<T> {\n element: T;\n prev: Node<T> | undefined;\n next: Node<T> | undefined;\n\n constructor(element: T) {\n this.element = element;\n }\n}\n\nexport class LinkedList<T> {\n protected _first: Node<T> | undefined;\n protected _last: Node<T> | undefined;\n private _size: number = 0;\n\n get size(): number {\n return this._size;\n }\n\n isEmpty(): boolean {\n return this._first === undefined;\n }\n\n unshift(value: T): void {\n const newNode = new Node(value);\n if (!this._first) {\n this._first = newNode;\n this._last = newNode;\n } else {\n newNode.next = this._first;\n this._first.prev = newNode;\n this._first = newNode;\n }\n this._size++;\n }\n\n push(value: T): void {\n const newNode = new Node(value);\n if (!this._last) {\n this._first = newNode;\n this._last = newNode;\n } else {\n newNode.prev = this._last;\n this._last.next = newNode;\n this._last = newNode;\n }\n this._size++;\n }\n\n shift(): T | undefined {\n if (!this._first) {\n return undefined;\n }\n const element = this._first.element;\n this._remove(this._first);\n return element;\n }\n\n pop(): T | undefined {\n if (!this._last) {\n return undefined;\n }\n const element = this._last.element;\n this._remove(this._last);\n return element;\n }\n\n protected _remove(node: Node<T>): void {\n if (node.prev) {\n node.prev.next = node.next;\n } else {\n this._first = node.next;\n }\n if (node.next) {\n node.next.prev = node.prev;\n } else {\n this._last = node.prev;\n }\n this._size--;\n }\n\n clear(): void {\n let node = this._first;\n while (node) {\n const next = node.next;\n node.prev = undefined;\n node.next = undefined;\n node = next;\n }\n this._first = undefined;\n this._last = undefined;\n this._size = 0;\n }\n\n *[Symbol.iterator](): Iterator<T> {\n let node = this._first;\n while (node) {\n yield node.element;\n node = node.next;\n }\n }\n}\n","import { LinkedList } from '../structure/linked-list';\n\nexport class DisposableLinkedList<T> extends LinkedList<T> {\n unshiftAndGetDisposableNode(value: T): () => void {\n this.unshift(value);\n\n const node = this._first!;\n let hasRemoved = false;\n return (): void => {\n if (!hasRemoved) {\n hasRemoved = true;\n super._remove(node);\n }\n };\n }\n\n pushAndGetDisposableNode(value: T): () => void {\n this.push(value);\n\n const node = this._last!;\n let hasRemoved = false;\n return (): void => {\n if (!hasRemoved) {\n hasRemoved = true;\n super._remove(node);\n }\n };\n }\n}\n","/**\n * 针对未捕获的错误,异步抛出,不阻塞事件响应主流程\n * 默认模式\n */\nexport function asyncUnexpectedErrorHandler(e: any): undefined {\n setTimeout(() => {\n throw e;\n }, 0);\n}\n\n/**\n * 针对未捕获的错误,同步抛出,阻塞事件响应主流程\n */\nexport function syncUnexpectedError(e: any): undefined {\n throw e;\n}\n\n/**\n * 针对未捕获的错误,静默掉,不进行处理\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-function\nexport function ignoreUnexpectedError(e: any): undefined {}\n","/* eslint-disable @typescript-eslint/no-redundant-type-constituents */\nimport { DisposableLinkedList, makeSafeDisposable } from '../dispose';\nimport type { IDisposable } from '../dispose';\nimport { asyncUnexpectedErrorHandler } from './error-handler';\n\nexport interface EmitterOptions {\n onAddListener?: (...args: any) => any;\n onRemoveListener?: (...args: any) => any;\n onListenerError?: (e: any) => void;\n}\n\n//\n// 事件监听中的回调实体\n//\nclass Listener<TArgs extends any[]> {\n private readonly _callback: (...args: TArgs) => void;\n private readonly _callbackThis: any | undefined;\n\n constructor(callback: (...args: TArgs) => void, callbackThis: any | undefined) {\n this._callback = callback;\n this._callbackThis = callbackThis;\n }\n\n invoke(...args: TArgs): void {\n this._callback.call(this._callbackThis, ...args);\n }\n}\n\n//\n// 存放在EventDeliveryQueue中的元素\n//\nclass EventDeliveryQueueElement<TArgs extends any[]> {\n readonly emitter: Emitter<TArgs>;\n readonly listener: Listener<TArgs>;\n readonly event: TArgs;\n constructor(emitter: Emitter<TArgs>, listener: Listener<TArgs>, event: TArgs) {\n this.emitter = emitter;\n this.listener = listener;\n this.event = event;\n }\n}\n\nexport class EventDeliveryQueue {\n protected _queue = new DisposableLinkedList<EventDeliveryQueueElement<any>>();\n\n constructor(\n private readonly _onListenerError: (e: unknown) => void = asyncUnexpectedErrorHandler,\n ) {}\n\n get size(): number {\n return this._queue.size;\n }\n\n push<TArgs extends any[]>(\n emitter: Emitter<TArgs>,\n listener: Listener<TArgs>,\n event: TArgs,\n ): void {\n this._queue.push(new EventDeliveryQueueElement(emitter, listener, event));\n }\n\n clear<TArgs extends any[]>(emitter: Emitter<TArgs>): void {\n const newQueue = new DisposableLinkedList<EventDeliveryQueueElement<TArgs>>();\n for (const element of this._queue) {\n if (element.emitter !== emitter) {\n newQueue.push(element);\n }\n }\n this._queue = newQueue;\n }\n\n deliver(): void {\n while (this._queue.size > 0) {\n const element = this._queue.shift()!;\n try {\n element.listener.invoke(...element.event);\n } catch (e) {\n this._onListenerError(e);\n }\n }\n }\n}\n\nexport interface Event<T extends any[]> {\n (listener: (...args: T) => any, thisArgs?: any): IDisposable;\n}\n\nexport class Emitter<TArgs extends any[]> {\n protected _listeners?: DisposableLinkedList<Listener<TArgs>>;\n private readonly _options?: EmitterOptions;\n private _disposed = false;\n private _event?: Event<TArgs>;\n private _deliveryQueue?: EventDeliveryQueue;\n\n constructor(options?: EmitterOptions) {\n this._options = options;\n }\n\n get event(): Event<TArgs> {\n if (this._event) {\n return this._event;\n }\n\n this._event = (callback: (...args: TArgs) => any, thisArgs?: any): IDisposable => {\n if (!this._listeners) {\n this._listeners = new DisposableLinkedList();\n }\n\n const listener = new Listener(callback, thisArgs);\n const removeListener = this._listeners.pushAndGetDisposableNode(listener);\n\n if (this._options?.onAddListener) {\n this._options.onAddListener(this, callback, thisArgs);\n }\n\n // 生成可销毁函数返回\n const result = () => {\n if (!this._disposed) {\n removeListener();\n if (this._options?.onRemoveListener) {\n this._options.onRemoveListener(this, callback, thisArgs);\n }\n }\n };\n\n return makeSafeDisposable(result);\n };\n\n return this._event;\n }\n\n dispose(): void {\n if (this._disposed) {\n return;\n }\n this._disposed = true;\n this._listeners?.clear();\n this._deliveryQueue?.clear(this);\n }\n\n fire(...event: TArgs): void {\n if (!this._listeners) {\n return;\n }\n this._deliveryQueue ??= new EventDeliveryQueue(this._options?.onListenerError);\n\n for (const listener of this._listeners) {\n this._deliveryQueue.push(this, listener, event);\n }\n this._deliveryQueue.deliver();\n }\n}\n","import type { ILvErrorRef, ILvErrorOr, ILvRealErrorRef } from './error-base';\n\n//\n// Error类\n//\n// 用户给函数签名明确错误\n// function foo(): ILvErrorRef\n// return makeOk(); // 如果没有错误\n// return makeError(code, msg); // 指定错误码和携带消息\n//\n// const SomeError = LvErrorConst(code, msg); // 更推荐用LvErrorConst生成\n// return SomeError();\n//\n\nconst lvErrorRefSymbol = Symbol('lvErrorRef');\n\nexport function makeOk(): ILvErrorOr<never> {\n return {\n ok: true,\n value: null!,\n pair() {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return [null, null!] as any;\n },\n code: 0,\n msg: '',\n ...{ [lvErrorRefSymbol]: true }, // 跳过类型检测\n };\n}\n\nexport function makeOkWith<T>(value: T): ILvErrorOr<T> {\n return {\n ok: true,\n value,\n pair() {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return [null, value] as any;\n },\n code: 0,\n msg: '',\n ...{ [lvErrorRefSymbol]: true }, // 跳过类型检测\n };\n}\n\nfunction printCause(cause: ILvErrorRef | Error | undefined): string {\n if (cause === undefined) {\n return '';\n } else if (cause instanceof Error) {\n return `\\ncaused by [jsError]${cause.name}-${cause.message}`;\n } else {\n return `\\ncaused by [${cause.code}]${cause.msg}${cause.ok ? '' : printCause(cause.cause)}`;\n }\n}\n\nfunction internalMakeError(\n code: number,\n msg: string,\n cause?: ILvErrorRef | Error,\n errorInfo?: unknown,\n) {\n const errorRef: ILvRealErrorRef = {\n ok: false,\n code,\n msg,\n cause,\n errorInfo,\n toString() {\n return `[${code}]${msg}.${cause ? printCause(cause) : ''}`;\n },\n pair() {\n return [errorRef, null];\n },\n ...{ [lvErrorRefSymbol]: true }, // 跳过类型检测\n };\n return errorRef;\n}\n\nexport function makeError(code: number, msg: string, errorInfo?: unknown): ILvRealErrorRef {\n return internalMakeError(code, msg, undefined, errorInfo);\n}\n\nexport function makeErrorBy(\n code: number,\n msg: string,\n cause: ILvErrorRef | Error,\n errorInfo?: unknown,\n): ILvRealErrorRef {\n return internalMakeError(code, msg, cause, errorInfo);\n}\n\nexport function isLvErrorRef(val: unknown): val is ILvErrorRef {\n return typeof val === 'object' && val !== null && lvErrorRefSymbol in val;\n}\n","import { makeError, makeErrorBy } from './error-t';\n\n//\n// Error编译时错误对象\n//\nexport function lvErrorConst(code: number, msg: string) {\n return (rewrite?: string | Error) => {\n if (!rewrite) {\n return makeError(code, msg);\n }\n if (typeof rewrite === 'string') {\n return makeError(code, rewrite);\n }\n return makeErrorBy(code, rewrite.message, rewrite);\n };\n}\n","import { lvErrorConst } from './error-const';\n\n/**\n * 提供了通用的错误码(+1至+256)\n *\n * 注意:这里只是提供了通用的错误码,方便服务使用,但并不是要求服务一定使用如下的错误码来表明某种错误\n */\nexport enum GenericError {\n Ok = 0,\n Cancelled = 1, // 操作被取消\n TimedOut = 2, // 操作超时\n PermissionDenied = 3, // 无权限\n AlreadyExists = 4, // 已经存在(文件/记录等)\n NotSupported = 5, // 操作不支持\n ResourceUnavailable = 6, // 资源不可用\n OutOfRange = 7, // (参数/结果等)发生越界\n InvalidArgument = 8, // 无效参数\n NetworkFailed = 9, // 网络失败\n Interrupted = 10, // 操作被中断(捕获异常转为错误)\n ResultNil = 11, // 结果不存在(null or undefined转为错误)\n}\n\n/**\n * 通用错误码所对应的编译时常量对象(ErrorConst)\n */\nexport const cancelledError = lvErrorConst(GenericError.Cancelled, 'operation(s) cancelled.');\nexport const timeoutError = lvErrorConst(GenericError.TimedOut, 'operation(s) timed out.');\nexport const permissionDeniedError = lvErrorConst(\n GenericError.PermissionDenied,\n 'permission denied.',\n);\nexport const alreadyExistsError = lvErrorConst(GenericError.AlreadyExists, 'already exists.');\nexport const notSupportedError = lvErrorConst(\n GenericError.NotSupported,\n 'operation(s) not supported.',\n);\nexport const resourceUnavailableError = lvErrorConst(\n GenericError.ResourceUnavailable,\n 'resource is unavailable.',\n);\nexport const outOfRangeError = lvErrorConst(GenericError.OutOfRange, 'out of range.');\nexport const invalidArgumentError = lvErrorConst(\n GenericError.InvalidArgument,\n 'invalid arguments.',\n);\nexport const networkFailedError = lvErrorConst(GenericError.NetworkFailed, 'network failed.');\nexport const interruptedError = lvErrorConst(GenericError.Interrupted, 'interrupted.');\nexport const resultNilError = lvErrorConst(GenericError.ResultNil, 'result is nil.');\n","import { Command } from \"commander\";\nimport { Disposable } from \"../bedrock/dispose\";\nimport { Emitter } from \"../bedrock/event\";\nimport type { Event } from \"../bedrock/event\";\nimport type { ILvErrorOr } from \"../bedrock/error\";\nimport { makeOk, makeError } from \"../bedrock/error\";\nimport { makeSuccessResponse, makeErrorResponse } from \"../bedrock/response\";\nimport { makeCommandExample } from \"./command-example\";\nimport type { ICommandMeta } from \"./command-types\";\n\nexport interface ICommandActionContext<TOptions = Record<string, unknown>> {\n readonly args: unknown[];\n readonly options: TOptions;\n readonly command: Command;\n}\n\nexport abstract class BaseCommand<\n TOptions = Record<string, unknown>,\n> extends Disposable {\n private readonly _command: Command;\n private readonly _onBeforeExecute = this._register(new Emitter<[]>());\n private readonly _onAfterExecute = this._register(\n new Emitter<[ILvErrorOr<void>]>(),\n );\n\n public readonly onBeforeExecute: Event<[]> = this._onBeforeExecute.event;\n public readonly onAfterExecute: Event<[ILvErrorOr<void>]> =\n this._onAfterExecute.event;\n\n constructor() {\n super();\n const meta = this._meta();\n this._command = new Command(meta.name);\n this._command.description(meta.description);\n\n if (meta.aliases) {\n this._command.aliases(meta.aliases);\n }\n\n this._configureOptions(this._command);\n this._configureArguments(this._command);\n this._command.addHelpText(\"after\", () => {\n return `\\n执行案例:\\n ${this.getExample()}\\n`;\n });\n\n this._command.action(async (...rawArgs: unknown[]) => {\n const ctx = this._parseActionArgs(rawArgs);\n this._onBeforeExecute.fire();\n\n let result: ILvErrorOr<void>;\n try {\n result = await this._execute(ctx);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n result = makeError(1, `Command \"${meta.name}\" failed: ${message}`);\n }\n this._onAfterExecute.fire(result);\n\n if (!result.ok) {\n process.stderr.write(`Error [${result.code}]: ${result.msg}\\n`);\n process.exitCode = 1;\n }\n });\n }\n\n public get command(): Command {\n return this._command;\n }\n\n /**\n * 返回该命令的执行示例,供外部展示或调试使用。\n */\n public getExample(): string {\n return makeCommandExample(this._command);\n }\n\n protected abstract _meta(): ICommandMeta;\n\n protected abstract _execute(\n ctx: ICommandActionContext<TOptions>,\n ): Promise<ILvErrorOr<void>>;\n\n protected _configureOptions(_cmd: Command): void {}\n\n protected _configureArguments(_cmd: Command): void {}\n\n protected _makeOk(): ILvErrorOr<void> {\n return makeOk();\n }\n\n protected _makeError(code: number, msg: string): ILvErrorOr<void> {\n return makeError(code, msg);\n }\n\n /**\n * 向 stdout 输出一行文本(最终用户可见的输出)\n */\n protected _output(text: string): void {\n process.stdout.write(text + \"\\n\");\n }\n\n /**\n * 向 stderr 输出调试 / 诊断信息(不会混入最终输出)\n */\n protected _debug(text: string): void {\n process.stderr.write(`[debug] ${text}\\n`);\n }\n\n /**\n * 以 JSON 字符串形式输出成功结果到 stdout\n */\n protected _outputJsonOk<T>(data: T): void {\n process.stdout.write(\n JSON.stringify(makeSuccessResponse(data), null, 2) + \"\\n\",\n );\n }\n\n /**\n * 以 JSON 字符串形式输出错误结果到 stdout\n */\n protected _outputJsonError(code: number, msg: string): void {\n process.stdout.write(\n JSON.stringify(makeErrorResponse(code, msg), null, 2) + \"\\n\",\n );\n }\n\n private _parseActionArgs(\n rawArgs: unknown[],\n ): ICommandActionContext<TOptions> {\n const command = rawArgs[rawArgs.length - 1] as Command;\n const options = rawArgs[rawArgs.length - 2] as TOptions;\n const args = rawArgs.slice(0, rawArgs.length - 2);\n return { args, options, command };\n }\n}\n","export interface ISuccessResponse<T = any> {\n code: 0;\n data: T;\n msg: string;\n}\n\nexport interface IErrorResponse {\n code: Exclude<number, 0>;\n msg: string;\n}\n\nexport type IResponse<T = any> = ISuccessResponse<T> | IErrorResponse;\n\nexport function makeSuccessResponse<T = any>(data: T): ISuccessResponse<T> {\n return {\n code: 0,\n data,\n msg: 'success',\n };\n}\n\nexport function makeErrorResponse(code: number, msg: string) {\n return {\n code,\n msg,\n };\n}\n","import type { Argument, Command, Option } from \"commander\";\n\nfunction _getCommandPath(command: Command): string[] {\n const names: string[] = [];\n for (let current: Command | null = command; current; current = current.parent) {\n names.unshift(current.name());\n }\n return names;\n}\n\nfunction _getRepresentativeValue(\n name: string,\n defaultValue: unknown,\n choices: readonly string[] | undefined,\n): string {\n if (defaultValue !== undefined) {\n return String(defaultValue);\n }\n\n if (choices && choices.length > 0) {\n return choices[0];\n }\n\n return name;\n}\n\nfunction _formatArgument(argument: Argument): string {\n const name = argument.name();\n const token = _getRepresentativeValue(name, argument.defaultValue, argument.argChoices);\n const hasConcreteValue =\n argument.defaultValue !== undefined ||\n (argument.argChoices !== undefined && argument.argChoices.length > 0);\n\n if (hasConcreteValue) {\n return argument.variadic ? `${token}...` : token;\n }\n\n if (argument.required) {\n return `<${argument.variadic ? `${token}...` : token}>`;\n }\n\n return `[${argument.variadic ? `${token}...` : token}]`;\n}\n\nfunction _getOptionFlag(option: Option): string {\n return option.short ?? option.long ?? option.flags.split(\",\")[0].trim();\n}\n\nfunction _isHiddenHelpOption(option: Option): boolean {\n return option.hidden || option.flags.includes(\"--help\");\n}\n\nfunction _formatOption(option: Option): string | null {\n if (_isHiddenHelpOption(option)) {\n return null;\n }\n\n const flag = _getOptionFlag(option);\n if (option.isBoolean()) {\n if (!option.mandatory && option.defaultValue === false) {\n return null;\n }\n\n return flag;\n }\n\n const value = _getRepresentativeValue(\n option.attributeName(),\n option.defaultValue,\n option.argChoices,\n );\n const hasConcreteValue =\n option.defaultValue !== undefined ||\n (option.argChoices !== undefined && option.argChoices.length > 0);\n\n if (!option.mandatory && option.defaultValue !== undefined) {\n return null;\n }\n\n if (hasConcreteValue) {\n return `${flag} ${value}`;\n }\n\n return `${flag} ${option.required ? value : `[${value}]`}`;\n}\n\n/**\n * 根据命令本身的注册配置生成一条执行示例。\n */\nexport function makeCommandExample(command: Command): string {\n const parts = _getCommandPath(command);\n const optionParts = command.options\n .map((option) => _formatOption(option))\n .filter((part): part is string => part !== null);\n const argumentParts = command.registeredArguments.map((argument) =>\n _formatArgument(argument),\n );\n\n return [...parts, ...optionParts, ...argumentParts].join(\" \").replace(/\\s+/g, \" \").trim();\n}\n","import { Command } from \"commander\";\nimport { Disposable } from \"../bedrock/dispose\";\nimport { Emitter } from \"../bedrock/event\";\nimport type { Event } from \"../bedrock/event\";\nimport type { ILvErrorOr } from \"../bedrock/error\";\nimport { makeOk, makeError } from \"../bedrock/error\";\nimport { makeSuccessResponse, makeErrorResponse } from \"../bedrock/response\";\nimport { makeCommandExample } from \"./command-example\";\nimport type { ICommandMeta } from \"./command-types\";\nimport type { BaseCommand, ICommandActionContext } from \"./base-command\";\n\n/**\n * 带子命令的命令宿主基类。\n *\n * 用于 `mycli hello greet` / `mycli hello info` 这类场景:\n * - hello 本身是一个 command group(SubcommandHost)\n * - greet / info 是它下面注册的子命令(BaseCommand)\n *\n * 也支持宿主自身直接处理(不带子命令时)的 fallback 逻辑。\n */\nexport abstract class BaseSubcommandHost extends Disposable {\n private readonly _command: Command;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private readonly _subcommands: BaseCommand<any>[] = [];\n\n private readonly _onBeforeExecute = this._register(new Emitter<[]>());\n private readonly _onAfterExecute = this._register(\n new Emitter<[ILvErrorOr<void>]>(),\n );\n\n public readonly onBeforeExecute: Event<[]> = this._onBeforeExecute.event;\n public readonly onAfterExecute: Event<[ILvErrorOr<void>]> =\n this._onAfterExecute.event;\n\n constructor() {\n super();\n const meta = this._meta();\n this._command = new Command(meta.name);\n this._command.description(meta.description);\n\n if (meta.aliases) {\n this._command.aliases(meta.aliases);\n }\n\n this._configureOptions(this._command);\n this._registerSubcommands();\n // 仅在子命令场景,展示执行案例\n // this._command.addHelpText('after', () => {\n // return `\\n执行案例:\\n ${this.getExample()}\\n`;\n // });\n\n this._command.action(async (...rawArgs: unknown[]) => {\n const ctx = this._parseActionArgs(rawArgs);\n this._onBeforeExecute.fire();\n\n let result: ILvErrorOr<void>;\n try {\n result = await this._executeFallback(ctx);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n result = makeError(1, `Command \"${meta.name}\" failed: ${message}`);\n }\n this._onAfterExecute.fire(result);\n\n if (!result.ok) {\n process.stderr.write(`Error [${result.code}]: ${result.msg}\\n`);\n process.exitCode = 1;\n }\n });\n }\n\n public get command(): Command {\n return this._command;\n }\n\n /**\n * 返回该命令宿主的执行示例,供外部展示或调试使用。\n */\n public getExample(): string {\n return makeCommandExample(this._command);\n }\n\n protected abstract _meta(): ICommandMeta;\n\n /**\n * 子类在此方法中调用 _addSubcommand 注册子命令\n */\n protected abstract _registerSubcommands(): void;\n\n /**\n * 当用户没有指定子命令时的默认行为。\n * 默认显示帮助信息,子类可覆盖。\n */\n protected _executeFallback(\n _ctx: ICommandActionContext,\n ): Promise<ILvErrorOr<void>> {\n this._command.outputHelp();\n return Promise.resolve(makeOk());\n }\n\n protected _configureOptions(_cmd: Command): void {}\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n protected _addSubcommand(cmd: BaseCommand<any>): void {\n this._subcommands.push(cmd);\n this._register(cmd);\n this._command.addCommand(cmd.command);\n }\n\n protected _makeOk(): ILvErrorOr<void> {\n return makeOk();\n }\n\n protected _makeError(code: number, msg: string): ILvErrorOr<void> {\n return makeError(code, msg);\n }\n\n protected _output(text: string): void {\n process.stdout.write(text + \"\\n\");\n }\n\n protected _debug(text: string): void {\n process.stderr.write(`[debug] ${text}\\n`);\n }\n\n protected _outputJsonOk<T>(data: T): void {\n process.stdout.write(JSON.stringify(makeSuccessResponse(data)) + \"\\n\");\n }\n\n protected _outputJsonError(code: number, msg: string): void {\n process.stdout.write(JSON.stringify(makeErrorResponse(code, msg)) + \"\\n\");\n }\n\n public override dispose(): void {\n this._subcommands.length = 0;\n super.dispose();\n }\n\n private _parseActionArgs(rawArgs: unknown[]): ICommandActionContext {\n const command = rawArgs[rawArgs.length - 1] as Command;\n const options = rawArgs[rawArgs.length - 2] as Record<string, unknown>;\n const args = rawArgs.slice(0, rawArgs.length - 2);\n return { args, options, command };\n }\n}\n"],"mappings":";AAAA,SAAS,eAAe;;;ACQjB,IAAM,eAAe,OAAO,OAAoB,EAAE,UAAU;AAAC,EAAE,CAAC;;;ACNvE,IAAI,mBAA6C;AA0B1C,SAAS,eAAe,MAAc,IAAY;AACvD,oBAAkB,OAAO,MAAM,EAAE;AACnC;;;ACjBA,IAAI,oBAA+C;AAmD5C,SAAS,iBAAwC,GAAS;AAC/D,qBAAmB,gBAAgB,CAAC;AACpC,SAAO;AACT;AAGO,SAAS,iBAAwC,GAAY;AAClE,qBAAmB,eAAe,CAAC;AACrC;AAGO,SAAS,yBAAyB,OAAoB,QAAkC;AAC7F,qBAAmB,UAAU,OAAO,MAAM;AAC5C;;;ACzEO,IAAM,kBAAN,MAAM,iBAAuC;AAAA,EAClD,OAAO,2BAA2B;AAAA,EAEjB,aAAa,oBAAI,IAAiB;AAAA,EAC3C,cAAc;AAAA,EAEtB,cAAc;AACZ,qBAAiB,IAAI;AAAA,EACvB;AAAA,EAEA,IAAI,aAAsB;AACxB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,UAAgB;AACd,QAAI,KAAK,aAAa;AAGpB,cAAQ,KAAK,IAAI,MAAM,+BAA+B,EAAE,KAAK;AAC7D;AAAA,IACF;AAEA,qBAAiB,IAAI;AACrB,SAAK,cAAc;AACnB,SAAK,MAAM;AAAA,EACb;AAAA,EAEA,QAAc;AACZ,QAAI,KAAK,WAAW,SAAS,GAAG;AAC9B;AAAA,IACF;AAEA,eAAW,cAAc,KAAK,YAAY;AACxC,qBAAe,KAAK,YAAY,MAAM,WAAW,YAAY,IAAI;AAAA,IACnE;AAEA,QAAI;AAEF,iBAAW,cAAc,KAAK,YAAY;AACxC,mBAAW,QAAQ;AAAA,MACrB;AAAA,IACF,UAAE;AACA,WAAK,WAAW,MAAM;AAAA,IACxB;AAAA,EACF;AAAA,EAEA,IAA2B,GAAS;AAClC,QAAI,CAAC,GAAG;AACN,aAAO;AAAA,IACT;AACA,QAAK,MAAqC,MAAM;AAC9C,YAAM,IAAI,MAAM,yCAAyC;AAAA,IAC3D;AAEA,6BAAyB,GAAG,IAAI;AAChC,QAAI,KAAK,aAAa;AACpB,UAAI,CAAC,iBAAgB,0BAA0B;AAE7C,gBAAQ;AAAA,UACN,IAAI;AAAA,YACF;AAAA,UACF,EAAE;AAAA,QACJ;AAAA,MACF;AAAA,IACF,OAAO;AACL,WAAK,WAAW,IAAI,CAAC;AAAA,IACvB;AAEA,WAAO;AAAA,EACT;AACF;;;AChEO,IAAe,aAAf,MAAiD;AAAA,EACnC,SAAS,IAAI,gBAAgB;AAAA,EAEhD,cAAc;AACZ,qBAAiB,IAAI;AACrB,6BAAyB,KAAK,QAAQ,IAAI;AAAA,EAC5C;AAAA;AAAA,EAGA,UAAgB;AACd,qBAAiB,IAAI;AACrB,mBAAe,KAAK,YAAY,MAAM,KAAK,OAAO,YAAY,IAAI;AAElE,SAAK,OAAO,QAAQ;AAAA,EACtB;AAAA;AAAA,EAGU,UAAiC,GAAS;AAClD,QAAK,MAAgC,MAAM;AACzC,YAAM,IAAI,MAAM,yCAAyC;AAAA,IAC3D;AACA,WAAO,KAAK,OAAO,IAAI,CAAC;AAAA,EAC1B;AACF;AAgDO,IAAM,iBAAN,MAAmE;AAAA,EAChE,SAAmB;AAAA,EAE3B,YAAY,OAAU;AACpB,SAAK,SAAS;AACd,qBAAiB,IAAI;AAAA,EACvB;AAAA,EAEA,UAAU;AACR,WAAO,KAAK,WAAW;AAAA,EACzB;AAAA,EAEA,UAAU;AACR,QAAI,CAAC,KAAK,QAAQ;AAChB;AAAA,IACF;AACA,SAAK,OAAO,QAAQ;AACpB,SAAK,SAAS;AACd,qBAAiB,IAAI;AAAA,EACvB;AACF;;;AClGO,SAAS,mBAAmB,IAA2B;AAC5D,QAAM,aAAa,IAAI,eAAe;AAAA,IACpC,SAAS;AAAA,EACX,CAAC;AACD,SAAO;AACT;;;ACRA,IAAM,OAAN,MAAc;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YAAY,SAAY;AACtB,SAAK,UAAU;AAAA,EACjB;AACF;AAEO,IAAM,aAAN,MAAoB;AAAA,EACf;AAAA,EACA;AAAA,EACF,QAAgB;AAAA,EAExB,IAAI,OAAe;AACjB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,UAAmB;AACjB,WAAO,KAAK,WAAW;AAAA,EACzB;AAAA,EAEA,QAAQ,OAAgB;AACtB,UAAM,UAAU,IAAI,KAAK,KAAK;AAC9B,QAAI,CAAC,KAAK,QAAQ;AAChB,WAAK,SAAS;AACd,WAAK,QAAQ;AAAA,IACf,OAAO;AACL,cAAQ,OAAO,KAAK;AACpB,WAAK,OAAO,OAAO;AACnB,WAAK,SAAS;AAAA,IAChB;AACA,SAAK;AAAA,EACP;AAAA,EAEA,KAAK,OAAgB;AACnB,UAAM,UAAU,IAAI,KAAK,KAAK;AAC9B,QAAI,CAAC,KAAK,OAAO;AACf,WAAK,SAAS;AACd,WAAK,QAAQ;AAAA,IACf,OAAO;AACL,cAAQ,OAAO,KAAK;AACpB,WAAK,MAAM,OAAO;AAClB,WAAK,QAAQ;AAAA,IACf;AACA,SAAK;AAAA,EACP;AAAA,EAEA,QAAuB;AACrB,QAAI,CAAC,KAAK,QAAQ;AAChB,aAAO;AAAA,IACT;AACA,UAAM,UAAU,KAAK,OAAO;AAC5B,SAAK,QAAQ,KAAK,MAAM;AACxB,WAAO;AAAA,EACT;AAAA,EAEA,MAAqB;AACnB,QAAI,CAAC,KAAK,OAAO;AACf,aAAO;AAAA,IACT;AACA,UAAM,UAAU,KAAK,MAAM;AAC3B,SAAK,QAAQ,KAAK,KAAK;AACvB,WAAO;AAAA,EACT;AAAA,EAEU,QAAQ,MAAqB;AACrC,QAAI,KAAK,MAAM;AACb,WAAK,KAAK,OAAO,KAAK;AAAA,IACxB,OAAO;AACL,WAAK,SAAS,KAAK;AAAA,IACrB;AACA,QAAI,KAAK,MAAM;AACb,WAAK,KAAK,OAAO,KAAK;AAAA,IACxB,OAAO;AACL,WAAK,QAAQ,KAAK;AAAA,IACpB;AACA,SAAK;AAAA,EACP;AAAA,EAEA,QAAc;AACZ,QAAI,OAAO,KAAK;AAChB,WAAO,MAAM;AACX,YAAM,OAAO,KAAK;AAClB,WAAK,OAAO;AACZ,WAAK,OAAO;AACZ,aAAO;AAAA,IACT;AACA,SAAK,SAAS;AACd,SAAK,QAAQ;AACb,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,EAAE,OAAO,QAAQ,IAAiB;AAChC,QAAI,OAAO,KAAK;AAChB,WAAO,MAAM;AACX,YAAM,KAAK;AACX,aAAO,KAAK;AAAA,IACd;AAAA,EACF;AACF;;;ACnGO,IAAM,uBAAN,cAAsC,WAAc;AAAA,EACzD,4BAA4B,OAAsB;AAChD,SAAK,QAAQ,KAAK;AAElB,UAAM,OAAO,KAAK;AAClB,QAAI,aAAa;AACjB,WAAO,MAAY;AACjB,UAAI,CAAC,YAAY;AACf,qBAAa;AACb,cAAM,QAAQ,IAAI;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AAAA,EAEA,yBAAyB,OAAsB;AAC7C,SAAK,KAAK,KAAK;AAEf,UAAM,OAAO,KAAK;AAClB,QAAI,aAAa;AACjB,WAAO,MAAY;AACjB,UAAI,CAAC,YAAY;AACf,qBAAa;AACb,cAAM,QAAQ,IAAI;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AACF;;;ACxBO,SAAS,4BAA4B,GAAmB;AAC7D,aAAW,MAAM;AACf,UAAM;AAAA,EACR,GAAG,CAAC;AACN;;;ACMA,IAAM,WAAN,MAAoC;AAAA,EACjB;AAAA,EACA;AAAA,EAEjB,YAAY,UAAoC,cAA+B;AAC7E,SAAK,YAAY;AACjB,SAAK,gBAAgB;AAAA,EACvB;AAAA,EAEA,UAAU,MAAmB;AAC3B,SAAK,UAAU,KAAK,KAAK,eAAe,GAAG,IAAI;AAAA,EACjD;AACF;AAKA,IAAM,4BAAN,MAAqD;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EACT,YAAY,SAAyB,UAA2B,OAAc;AAC5E,SAAK,UAAU;AACf,SAAK,WAAW;AAChB,SAAK,QAAQ;AAAA,EACf;AACF;AAEO,IAAM,qBAAN,MAAyB;AAAA,EAG9B,YACmB,mBAAyC,6BAC1D;AADiB;AAAA,EAChB;AAAA,EAJO,SAAS,IAAI,qBAAqD;AAAA,EAM5E,IAAI,OAAe;AACjB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA,EAEA,KACE,SACA,UACA,OACM;AACN,SAAK,OAAO,KAAK,IAAI,0BAA0B,SAAS,UAAU,KAAK,CAAC;AAAA,EAC1E;AAAA,EAEA,MAA2B,SAA+B;AACxD,UAAM,WAAW,IAAI,qBAAuD;AAC5E,eAAW,WAAW,KAAK,QAAQ;AACjC,UAAI,QAAQ,YAAY,SAAS;AAC/B,iBAAS,KAAK,OAAO;AAAA,MACvB;AAAA,IACF;AACA,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,UAAgB;AACd,WAAO,KAAK,OAAO,OAAO,GAAG;AAC3B,YAAM,UAAU,KAAK,OAAO,MAAM;AAClC,UAAI;AACF,gBAAQ,SAAS,OAAO,GAAG,QAAQ,KAAK;AAAA,MAC1C,SAAS,GAAG;AACV,aAAK,iBAAiB,CAAC;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AACF;AAMO,IAAM,UAAN,MAAmC;AAAA,EAC9B;AAAA,EACO;AAAA,EACT,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EAER,YAAY,SAA0B;AACpC,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,IAAI,QAAsB;AACxB,QAAI,KAAK,QAAQ;AACf,aAAO,KAAK;AAAA,IACd;AAEA,SAAK,SAAS,CAAC,UAAmC,aAAgC;AAChF,UAAI,CAAC,KAAK,YAAY;AACpB,aAAK,aAAa,IAAI,qBAAqB;AAAA,MAC7C;AAEA,YAAM,WAAW,IAAI,SAAS,UAAU,QAAQ;AAChD,YAAM,iBAAiB,KAAK,WAAW,yBAAyB,QAAQ;AAExE,UAAI,KAAK,UAAU,eAAe;AAChC,aAAK,SAAS,cAAc,MAAM,UAAU,QAAQ;AAAA,MACtD;AAGA,YAAM,SAAS,MAAM;AACnB,YAAI,CAAC,KAAK,WAAW;AACnB,yBAAe;AACf,cAAI,KAAK,UAAU,kBAAkB;AACnC,iBAAK,SAAS,iBAAiB,MAAM,UAAU,QAAQ;AAAA,UACzD;AAAA,QACF;AAAA,MACF;AAEA,aAAO,mBAAmB,MAAM;AAAA,IAClC;AAEA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,UAAgB;AACd,QAAI,KAAK,WAAW;AAClB;AAAA,IACF;AACA,SAAK,YAAY;AACjB,SAAK,YAAY,MAAM;AACvB,SAAK,gBAAgB,MAAM,IAAI;AAAA,EACjC;AAAA,EAEA,QAAQ,OAAoB;AAC1B,QAAI,CAAC,KAAK,YAAY;AACpB;AAAA,IACF;AACA,SAAK,mBAAmB,IAAI,mBAAmB,KAAK,UAAU,eAAe;AAE7E,eAAW,YAAY,KAAK,YAAY;AACtC,WAAK,eAAe,KAAK,MAAM,UAAU,KAAK;AAAA,IAChD;AACA,SAAK,eAAe,QAAQ;AAAA,EAC9B;AACF;;;ACzIA,IAAM,mBAAmB,uBAAO,YAAY;AAErC,SAAS,SAA4B;AAC1C,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAEL,aAAO,CAAC,MAAM,IAAK;AAAA,IACrB;AAAA,IACA,MAAM;AAAA,IACN,KAAK;AAAA,IACL,GAAG,EAAE,CAAC,gBAAgB,GAAG,KAAK;AAAA;AAAA,EAChC;AACF;AAEO,SAAS,WAAc,OAAyB;AACrD,SAAO;AAAA,IACL,IAAI;AAAA,IACJ;AAAA,IACA,OAAO;AAEL,aAAO,CAAC,MAAM,KAAK;AAAA,IACrB;AAAA,IACA,MAAM;AAAA,IACN,KAAK;AAAA,IACL,GAAG,EAAE,CAAC,gBAAgB,GAAG,KAAK;AAAA;AAAA,EAChC;AACF;AAEA,SAAS,WAAW,OAAgD;AAClE,MAAI,UAAU,QAAW;AACvB,WAAO;AAAA,EACT,WAAW,iBAAiB,OAAO;AACjC,WAAO;AAAA,qBAAwB,MAAM,IAAI,IAAI,MAAM,OAAO;AAAA,EAC5D,OAAO;AACL,WAAO;AAAA,aAAgB,MAAM,IAAI,IAAI,MAAM,GAAG,GAAG,MAAM,KAAK,KAAK,WAAW,MAAM,KAAK,CAAC;AAAA,EAC1F;AACF;AAEA,SAAS,kBACP,MACA,KACA,OACA,WACA;AACA,QAAM,WAA4B;AAAA,IAChC,IAAI;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AACT,aAAO,IAAI,IAAI,IAAI,GAAG,IAAI,QAAQ,WAAW,KAAK,IAAI,EAAE;AAAA,IAC1D;AAAA,IACA,OAAO;AACL,aAAO,CAAC,UAAU,IAAI;AAAA,IACxB;AAAA,IACA,GAAG,EAAE,CAAC,gBAAgB,GAAG,KAAK;AAAA;AAAA,EAChC;AACA,SAAO;AACT;AAEO,SAAS,UAAU,MAAc,KAAa,WAAsC;AACzF,SAAO,kBAAkB,MAAM,KAAK,QAAW,SAAS;AAC1D;AAEO,SAAS,YACd,MACA,KACA,OACA,WACiB;AACjB,SAAO,kBAAkB,MAAM,KAAK,OAAO,SAAS;AACtD;;;ACnFO,SAAS,aAAa,MAAc,KAAa;AACtD,SAAO,CAAC,YAA6B;AACnC,QAAI,CAAC,SAAS;AACZ,aAAO,UAAU,MAAM,GAAG;AAAA,IAC5B;AACA,QAAI,OAAO,YAAY,UAAU;AAC/B,aAAO,UAAU,MAAM,OAAO;AAAA,IAChC;AACA,WAAO,YAAY,MAAM,QAAQ,SAAS,OAAO;AAAA,EACnD;AACF;;;ACUO,IAAM,iBAAiB,aAAa,mBAAwB,yBAAyB;AACrF,IAAM,eAAe,aAAa,kBAAuB,yBAAyB;AAClF,IAAM,wBAAwB;AAAA,EACnC;AAAA,EACA;AACF;AACO,IAAM,qBAAqB,aAAa,uBAA4B,iBAAiB;AACrF,IAAM,oBAAoB;AAAA,EAC/B;AAAA,EACA;AACF;AACO,IAAM,2BAA2B;AAAA,EACtC;AAAA,EACA;AACF;AACO,IAAM,kBAAkB,aAAa,oBAAyB,eAAe;AAC7E,IAAM,uBAAuB;AAAA,EAClC;AAAA,EACA;AACF;AACO,IAAM,qBAAqB,aAAa,uBAA4B,iBAAiB;AACrF,IAAM,mBAAmB,aAAa,sBAA0B,cAAc;AAC9E,IAAM,iBAAiB,aAAa,oBAAwB,gBAAgB;;;AbxB5E,IAAM,SAAN,cAAqB,WAAW;AAAA,EAUrC,YAA6B,UAA0B;AACrD,UAAM;AADqB;AAE3B,SAAK,WAAW,IAAI,QAAQ;AAC5B,SAAK,SACF,KAAK,SAAS,IAAI,EAClB,QAAQ,SAAS,SAAS,iBAAiB,gCAAO,EAClD,YAAY,SAAS,WAAW,EAChC,WAAW,cAAc,sCAAQ,EACjC,eAAe,kBAAkB,oEAAa;AAAA,EACnD;AAAA,EAlBiB;AAAA,EACA,YAAkC,CAAC;AAAA,EAEnC,eAAe,KAAK,UAAU,IAAI,QAAoB,CAAC;AAAA,EACvD,cAAc,KAAK,UAAU,IAAI,QAAY,CAAC;AAAA,EAE/C,cAAiC,KAAK,aAAa;AAAA,EACnD,aAAwB,KAAK,YAAY;AAAA,EAazD,IAAW,UAAmB;AAC5B,WAAO,KAAK;AAAA,EACd;AAAA,EAEO,gBACL,KACA,UAAmC,CAAC,GAC9B;AACN,SAAK,UAAU,KAAK;AAAA,MAClB,SAAS;AAAA,MACT,QAAQ,QAAQ,UAAU;AAAA,IAC5B,CAAC;AACD,SAAK,UAAU,GAAG;AAClB,SAAK,SAAS;AAAA,MACZ,IAAI;AAAA,MACJ,QAAQ,SAAS,EAAE,QAAQ,KAAK,IAAI;AAAA,IACtC;AAAA,EACF;AAAA,EAEA,MAAa,IAAI,MAA4C;AAC3D,UAAM,OAAO,QAAQ,QAAQ;AAC7B,SAAK,aAAa,KAAK,IAAI;AAE3B,QAAI;AACF,UAAI,KAAK,cAAc,IAAI,GAAG;AAC5B,aAAK,WAAW,IAAI;AACpB,aAAK,YAAY,KAAK;AACtB,eAAO,OAAO;AAAA,MAChB;AAEA,YAAM,KAAK,SAAS,WAAW,IAAI;AACnC,WAAK,YAAY,KAAK;AACtB,aAAO,OAAO;AAAA,IAChB,SAAS,KAAK;AACZ,YAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,aAAO,UAAU,GAAG,yBAAyB,OAAO,EAAE;AAAA,IACxD;AAAA,EACF;AAAA,EAEgB,UAAgB;AAC9B,SAAK,UAAU,SAAS;AACxB,UAAM,QAAQ;AAAA,EAChB;AAAA,EAEO,WAAW,gBAAgB,OAAa;AAC7C,YAAQ,OAAO,MAAM,KAAK,gBAAgB,aAAa,CAAC;AAAA,EAC1D;AAAA,EAEO,gBAAgB,gBAAgB,OAAe;AACpD,QAAI,CAAC,eAAe;AAClB,aAAO,KAAK,SAAS,gBAAgB;AAAA,IACvC;AAEA,UAAM,iBAAiB,KAAK,UACzB,OAAO,CAAC,UAAU,MAAM,MAAM,EAC9B,IAAI,CAAC,UAAU,MAAM,QAAQ,OAAO;AACvC,UAAM,uBAAuB,eAAe,IAAI,CAAC,YAAY;AAC3D,YAAM,aAAa;AACnB,YAAM,iBAAiB,WAAW;AAClC,iBAAW,UAAU;AACrB,aAAO;AAAA,IACT,CAAC;AAED,QAAI;AACF,aAAO,KAAK,SAAS,gBAAgB;AAAA,IACvC,UAAE;AACA,qBAAe,QAAQ,CAAC,SAAS,UAAU;AACzC,cAAM,aAAa;AACnB,mBAAW,UAAU,qBAAqB,KAAK;AAAA,MACjD,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,cAAc,MAAyB;AAC7C,UAAM,WAAW,KAAK,MAAM,CAAC;AAC7B,WAAO,SAAS,SAAS,KAAK,SAAS,CAAC,MAAM;AAAA,EAChD;AACF;;;AczHA,SAAS,WAAAA,gBAAe;;;ACajB,SAAS,oBAA6B,MAA8B;AACzE,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA,KAAK;AAAA,EACP;AACF;AAEO,SAAS,kBAAkB,MAAc,KAAa;AAC3D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;;;ACxBA,SAAS,gBAAgB,SAA4B;AACnD,QAAM,QAAkB,CAAC;AACzB,WAAS,UAA0B,SAAS,SAAS,UAAU,QAAQ,QAAQ;AAC7E,UAAM,QAAQ,QAAQ,KAAK,CAAC;AAAA,EAC9B;AACA,SAAO;AACT;AAEA,SAAS,wBACP,MACA,cACA,SACQ;AACR,MAAI,iBAAiB,QAAW;AAC9B,WAAO,OAAO,YAAY;AAAA,EAC5B;AAEA,MAAI,WAAW,QAAQ,SAAS,GAAG;AACjC,WAAO,QAAQ,CAAC;AAAA,EAClB;AAEA,SAAO;AACT;AAEA,SAAS,gBAAgB,UAA4B;AACnD,QAAM,OAAO,SAAS,KAAK;AAC3B,QAAM,QAAQ,wBAAwB,MAAM,SAAS,cAAc,SAAS,UAAU;AACtF,QAAM,mBACJ,SAAS,iBAAiB,UACzB,SAAS,eAAe,UAAa,SAAS,WAAW,SAAS;AAErE,MAAI,kBAAkB;AACpB,WAAO,SAAS,WAAW,GAAG,KAAK,QAAQ;AAAA,EAC7C;AAEA,MAAI,SAAS,UAAU;AACrB,WAAO,IAAI,SAAS,WAAW,GAAG,KAAK,QAAQ,KAAK;AAAA,EACtD;AAEA,SAAO,IAAI,SAAS,WAAW,GAAG,KAAK,QAAQ,KAAK;AACtD;AAEA,SAAS,eAAe,QAAwB;AAC9C,SAAO,OAAO,SAAS,OAAO,QAAQ,OAAO,MAAM,MAAM,GAAG,EAAE,CAAC,EAAE,KAAK;AACxE;AAEA,SAAS,oBAAoB,QAAyB;AACpD,SAAO,OAAO,UAAU,OAAO,MAAM,SAAS,QAAQ;AACxD;AAEA,SAAS,cAAc,QAA+B;AACpD,MAAI,oBAAoB,MAAM,GAAG;AAC/B,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,eAAe,MAAM;AAClC,MAAI,OAAO,UAAU,GAAG;AACtB,QAAI,CAAC,OAAO,aAAa,OAAO,iBAAiB,OAAO;AACtD,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ;AAAA,IACZ,OAAO,cAAc;AAAA,IACrB,OAAO;AAAA,IACP,OAAO;AAAA,EACT;AACA,QAAM,mBACJ,OAAO,iBAAiB,UACvB,OAAO,eAAe,UAAa,OAAO,WAAW,SAAS;AAEjE,MAAI,CAAC,OAAO,aAAa,OAAO,iBAAiB,QAAW;AAC1D,WAAO;AAAA,EACT;AAEA,MAAI,kBAAkB;AACpB,WAAO,GAAG,IAAI,IAAI,KAAK;AAAA,EACzB;AAEA,SAAO,GAAG,IAAI,IAAI,OAAO,WAAW,QAAQ,IAAI,KAAK,GAAG;AAC1D;AAKO,SAAS,mBAAmB,SAA0B;AAC3D,QAAM,QAAQ,gBAAgB,OAAO;AACrC,QAAM,cAAc,QAAQ,QACzB,IAAI,CAAC,WAAW,cAAc,MAAM,CAAC,EACrC,OAAO,CAAC,SAAyB,SAAS,IAAI;AACjD,QAAM,gBAAgB,QAAQ,oBAAoB;AAAA,IAAI,CAAC,aACrD,gBAAgB,QAAQ;AAAA,EAC1B;AAEA,SAAO,CAAC,GAAG,OAAO,GAAG,aAAa,GAAG,aAAa,EAAE,KAAK,GAAG,EAAE,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAC1F;;;AFnFO,IAAe,cAAf,cAEG,WAAW;AAAA,EACF;AAAA,EACA,mBAAmB,KAAK,UAAU,IAAI,QAAY,CAAC;AAAA,EACnD,kBAAkB,KAAK;AAAA,IACtC,IAAI,QAA4B;AAAA,EAClC;AAAA,EAEgB,kBAA6B,KAAK,iBAAiB;AAAA,EACnD,iBACd,KAAK,gBAAgB;AAAA,EAEvB,cAAc;AACZ,UAAM;AACN,UAAM,OAAO,KAAK,MAAM;AACxB,SAAK,WAAW,IAAIC,SAAQ,KAAK,IAAI;AACrC,SAAK,SAAS,YAAY,KAAK,WAAW;AAE1C,QAAI,KAAK,SAAS;AAChB,WAAK,SAAS,QAAQ,KAAK,OAAO;AAAA,IACpC;AAEA,SAAK,kBAAkB,KAAK,QAAQ;AACpC,SAAK,oBAAoB,KAAK,QAAQ;AACtC,SAAK,SAAS,YAAY,SAAS,MAAM;AACvC,aAAO;AAAA;AAAA,IAAc,KAAK,WAAW,CAAC;AAAA;AAAA,IACxC,CAAC;AAED,SAAK,SAAS,OAAO,UAAU,YAAuB;AACpD,YAAM,MAAM,KAAK,iBAAiB,OAAO;AACzC,WAAK,iBAAiB,KAAK;AAE3B,UAAI;AACJ,UAAI;AACF,iBAAS,MAAM,KAAK,SAAS,GAAG;AAAA,MAClC,SAAS,KAAK;AACZ,cAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,iBAAS,UAAU,GAAG,YAAY,KAAK,IAAI,aAAa,OAAO,EAAE;AAAA,MACnE;AACA,WAAK,gBAAgB,KAAK,MAAM;AAEhC,UAAI,CAAC,OAAO,IAAI;AACd,gBAAQ,OAAO,MAAM,UAAU,OAAO,IAAI,MAAM,OAAO,GAAG;AAAA,CAAI;AAC9D,gBAAQ,WAAW;AAAA,MACrB;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,IAAW,UAAmB;AAC5B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKO,aAAqB;AAC1B,WAAO,mBAAmB,KAAK,QAAQ;AAAA,EACzC;AAAA,EAQU,kBAAkB,MAAqB;AAAA,EAAC;AAAA,EAExC,oBAAoB,MAAqB;AAAA,EAAC;AAAA,EAE1C,UAA4B;AACpC,WAAO,OAAO;AAAA,EAChB;AAAA,EAEU,WAAW,MAAc,KAA+B;AAChE,WAAO,UAAU,MAAM,GAAG;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKU,QAAQ,MAAoB;AACpC,YAAQ,OAAO,MAAM,OAAO,IAAI;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKU,OAAO,MAAoB;AACnC,YAAQ,OAAO,MAAM,WAAW,IAAI;AAAA,CAAI;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKU,cAAiB,MAAe;AACxC,YAAQ,OAAO;AAAA,MACb,KAAK,UAAU,oBAAoB,IAAI,GAAG,MAAM,CAAC,IAAI;AAAA,IACvD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKU,iBAAiB,MAAc,KAAmB;AAC1D,YAAQ,OAAO;AAAA,MACb,KAAK,UAAU,kBAAkB,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI;AAAA,IAC1D;AAAA,EACF;AAAA,EAEQ,iBACN,SACiC;AACjC,UAAM,UAAU,QAAQ,QAAQ,SAAS,CAAC;AAC1C,UAAM,UAAU,QAAQ,QAAQ,SAAS,CAAC;AAC1C,UAAM,OAAO,QAAQ,MAAM,GAAG,QAAQ,SAAS,CAAC;AAChD,WAAO,EAAE,MAAM,SAAS,QAAQ;AAAA,EAClC;AACF;;;AGtIA,SAAS,WAAAC,gBAAe;AAoBjB,IAAe,qBAAf,cAA0C,WAAW;AAAA,EACzC;AAAA;AAAA,EAEA,eAAmC,CAAC;AAAA,EAEpC,mBAAmB,KAAK,UAAU,IAAI,QAAY,CAAC;AAAA,EACnD,kBAAkB,KAAK;AAAA,IACtC,IAAI,QAA4B;AAAA,EAClC;AAAA,EAEgB,kBAA6B,KAAK,iBAAiB;AAAA,EACnD,iBACd,KAAK,gBAAgB;AAAA,EAEvB,cAAc;AACZ,UAAM;AACN,UAAM,OAAO,KAAK,MAAM;AACxB,SAAK,WAAW,IAAIC,SAAQ,KAAK,IAAI;AACrC,SAAK,SAAS,YAAY,KAAK,WAAW;AAE1C,QAAI,KAAK,SAAS;AAChB,WAAK,SAAS,QAAQ,KAAK,OAAO;AAAA,IACpC;AAEA,SAAK,kBAAkB,KAAK,QAAQ;AACpC,SAAK,qBAAqB;AAM1B,SAAK,SAAS,OAAO,UAAU,YAAuB;AACpD,YAAM,MAAM,KAAK,iBAAiB,OAAO;AACzC,WAAK,iBAAiB,KAAK;AAE3B,UAAI;AACJ,UAAI;AACF,iBAAS,MAAM,KAAK,iBAAiB,GAAG;AAAA,MAC1C,SAAS,KAAK;AACZ,cAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,iBAAS,UAAU,GAAG,YAAY,KAAK,IAAI,aAAa,OAAO,EAAE;AAAA,MACnE;AACA,WAAK,gBAAgB,KAAK,MAAM;AAEhC,UAAI,CAAC,OAAO,IAAI;AACd,gBAAQ,OAAO,MAAM,UAAU,OAAO,IAAI,MAAM,OAAO,GAAG;AAAA,CAAI;AAC9D,gBAAQ,WAAW;AAAA,MACrB;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,IAAW,UAAmB;AAC5B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKO,aAAqB;AAC1B,WAAO,mBAAmB,KAAK,QAAQ;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA,EAaU,iBACR,MAC2B;AAC3B,SAAK,SAAS,WAAW;AACzB,WAAO,QAAQ,QAAQ,OAAO,CAAC;AAAA,EACjC;AAAA,EAEU,kBAAkB,MAAqB;AAAA,EAAC;AAAA;AAAA,EAGxC,eAAe,KAA6B;AACpD,SAAK,aAAa,KAAK,GAAG;AAC1B,SAAK,UAAU,GAAG;AAClB,SAAK,SAAS,WAAW,IAAI,OAAO;AAAA,EACtC;AAAA,EAEU,UAA4B;AACpC,WAAO,OAAO;AAAA,EAChB;AAAA,EAEU,WAAW,MAAc,KAA+B;AAChE,WAAO,UAAU,MAAM,GAAG;AAAA,EAC5B;AAAA,EAEU,QAAQ,MAAoB;AACpC,YAAQ,OAAO,MAAM,OAAO,IAAI;AAAA,EAClC;AAAA,EAEU,OAAO,MAAoB;AACnC,YAAQ,OAAO,MAAM,WAAW,IAAI;AAAA,CAAI;AAAA,EAC1C;AAAA,EAEU,cAAiB,MAAe;AACxC,YAAQ,OAAO,MAAM,KAAK,UAAU,oBAAoB,IAAI,CAAC,IAAI,IAAI;AAAA,EACvE;AAAA,EAEU,iBAAiB,MAAc,KAAmB;AAC1D,YAAQ,OAAO,MAAM,KAAK,UAAU,kBAAkB,MAAM,GAAG,CAAC,IAAI,IAAI;AAAA,EAC1E;AAAA,EAEgB,UAAgB;AAC9B,SAAK,aAAa,SAAS;AAC3B,UAAM,QAAQ;AAAA,EAChB;AAAA,EAEQ,iBAAiB,SAA2C;AAClE,UAAM,UAAU,QAAQ,QAAQ,SAAS,CAAC;AAC1C,UAAM,UAAU,QAAQ,QAAQ,SAAS,CAAC;AAC1C,UAAM,OAAO,QAAQ,MAAM,GAAG,QAAQ,SAAS,CAAC;AAChD,WAAO,EAAE,MAAM,SAAS,QAAQ;AAAA,EAClC;AACF;","names":["Command","Command","Command","Command"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -54,6 +54,39 @@ interface ICommandMeta {
|
|
|
54
54
|
readonly description: string;
|
|
55
55
|
readonly aliases?: string[];
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* BaseCommand 和 BaseSubcommandHost 的公共约束,
|
|
59
|
+
* 用于 CliApp.registerCommand 统一接受两种类型。
|
|
60
|
+
*/
|
|
61
|
+
interface IRegistrableCommand extends IDisposable {
|
|
62
|
+
readonly command: Command;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
interface IRegisterCommandOptions {
|
|
66
|
+
readonly hidden?: boolean;
|
|
67
|
+
}
|
|
68
|
+
interface ICliAppOptions {
|
|
69
|
+
readonly name: string;
|
|
70
|
+
readonly version: string;
|
|
71
|
+
readonly description: string;
|
|
72
|
+
}
|
|
73
|
+
declare class CliApp extends Disposable {
|
|
74
|
+
private readonly _options;
|
|
75
|
+
private readonly _program;
|
|
76
|
+
private readonly _commands;
|
|
77
|
+
private readonly _onBeforeRun;
|
|
78
|
+
private readonly _onAfterRun;
|
|
79
|
+
readonly onBeforeRun: Event<[string[]]>;
|
|
80
|
+
readonly onAfterRun: Event<[]>;
|
|
81
|
+
constructor(_options: ICliAppOptions);
|
|
82
|
+
get program(): Command;
|
|
83
|
+
registerCommand(cmd: IRegistrableCommand, options?: IRegisterCommandOptions): void;
|
|
84
|
+
run(argv?: string[]): Promise<ILvErrorOr<void>>;
|
|
85
|
+
dispose(): void;
|
|
86
|
+
outputHelp(includeHidden?: boolean): void;
|
|
87
|
+
helpInformation(includeHidden?: boolean): string;
|
|
88
|
+
private _isDoubleHelp;
|
|
89
|
+
}
|
|
57
90
|
|
|
58
91
|
interface ICommandActionContext<TOptions = Record<string, unknown>> {
|
|
59
92
|
readonly args: unknown[];
|
|
@@ -68,33 +101,77 @@ declare abstract class BaseCommand<TOptions = Record<string, unknown>> extends D
|
|
|
68
101
|
readonly onAfterExecute: Event<[ILvErrorOr<void>]>;
|
|
69
102
|
constructor();
|
|
70
103
|
get command(): Command;
|
|
104
|
+
/**
|
|
105
|
+
* 返回该命令的执行示例,供外部展示或调试使用。
|
|
106
|
+
*/
|
|
107
|
+
getExample(): string;
|
|
71
108
|
protected abstract _meta(): ICommandMeta;
|
|
72
109
|
protected abstract _execute(ctx: ICommandActionContext<TOptions>): Promise<ILvErrorOr<void>>;
|
|
73
110
|
protected _configureOptions(_cmd: Command): void;
|
|
74
111
|
protected _configureArguments(_cmd: Command): void;
|
|
75
112
|
protected _makeOk(): ILvErrorOr<void>;
|
|
76
113
|
protected _makeError(code: number, msg: string): ILvErrorOr<void>;
|
|
114
|
+
/**
|
|
115
|
+
* 向 stdout 输出一行文本(最终用户可见的输出)
|
|
116
|
+
*/
|
|
117
|
+
protected _output(text: string): void;
|
|
118
|
+
/**
|
|
119
|
+
* 向 stderr 输出调试 / 诊断信息(不会混入最终输出)
|
|
120
|
+
*/
|
|
121
|
+
protected _debug(text: string): void;
|
|
122
|
+
/**
|
|
123
|
+
* 以 JSON 字符串形式输出成功结果到 stdout
|
|
124
|
+
*/
|
|
125
|
+
protected _outputJsonOk<T>(data: T): void;
|
|
126
|
+
/**
|
|
127
|
+
* 以 JSON 字符串形式输出错误结果到 stdout
|
|
128
|
+
*/
|
|
129
|
+
protected _outputJsonError(code: number, msg: string): void;
|
|
77
130
|
private _parseActionArgs;
|
|
78
131
|
}
|
|
79
132
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
private readonly
|
|
91
|
-
readonly
|
|
92
|
-
readonly
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
133
|
+
/**
|
|
134
|
+
* 带子命令的命令宿主基类。
|
|
135
|
+
*
|
|
136
|
+
* 用于 `mycli hello greet` / `mycli hello info` 这类场景:
|
|
137
|
+
* - hello 本身是一个 command group(SubcommandHost)
|
|
138
|
+
* - greet / info 是它下面注册的子命令(BaseCommand)
|
|
139
|
+
*
|
|
140
|
+
* 也支持宿主自身直接处理(不带子命令时)的 fallback 逻辑。
|
|
141
|
+
*/
|
|
142
|
+
declare abstract class BaseSubcommandHost extends Disposable {
|
|
143
|
+
private readonly _command;
|
|
144
|
+
private readonly _subcommands;
|
|
145
|
+
private readonly _onBeforeExecute;
|
|
146
|
+
private readonly _onAfterExecute;
|
|
147
|
+
readonly onBeforeExecute: Event<[]>;
|
|
148
|
+
readonly onAfterExecute: Event<[ILvErrorOr<void>]>;
|
|
149
|
+
constructor();
|
|
150
|
+
get command(): Command;
|
|
151
|
+
/**
|
|
152
|
+
* 返回该命令宿主的执行示例,供外部展示或调试使用。
|
|
153
|
+
*/
|
|
154
|
+
getExample(): string;
|
|
155
|
+
protected abstract _meta(): ICommandMeta;
|
|
156
|
+
/**
|
|
157
|
+
* 子类在此方法中调用 _addSubcommand 注册子命令
|
|
158
|
+
*/
|
|
159
|
+
protected abstract _registerSubcommands(): void;
|
|
160
|
+
/**
|
|
161
|
+
* 当用户没有指定子命令时的默认行为。
|
|
162
|
+
* 默认显示帮助信息,子类可覆盖。
|
|
163
|
+
*/
|
|
164
|
+
protected _executeFallback(_ctx: ICommandActionContext): Promise<ILvErrorOr<void>>;
|
|
165
|
+
protected _configureOptions(_cmd: Command): void;
|
|
166
|
+
protected _addSubcommand(cmd: BaseCommand<any>): void;
|
|
167
|
+
protected _makeOk(): ILvErrorOr<void>;
|
|
168
|
+
protected _makeError(code: number, msg: string): ILvErrorOr<void>;
|
|
169
|
+
protected _output(text: string): void;
|
|
170
|
+
protected _debug(text: string): void;
|
|
171
|
+
protected _outputJsonOk<T>(data: T): void;
|
|
172
|
+
protected _outputJsonError(code: number, msg: string): void;
|
|
97
173
|
dispose(): void;
|
|
174
|
+
private _parseActionArgs;
|
|
98
175
|
}
|
|
99
176
|
|
|
100
|
-
export { BaseCommand, CliApp, type ICliAppOptions, type ICommandActionContext, type ICommandMeta };
|
|
177
|
+
export { BaseCommand, BaseSubcommandHost, CliApp, type ICliAppOptions, type ICommandActionContext, type ICommandMeta, type IRegistrableCommand };
|