maoda-commander-tt 0.0.27 → 0.0.29

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 CHANGED
@@ -5,9 +5,9 @@
5
5
  ## 特性
6
6
 
7
7
  - **面向对象架构** — 所有命令继承 `BaseCommand<TOptions>`,统一生命周期管理
8
- - **Disposable 体系** — 继承自 bedrock `Disposable` 基类,自动管理资源释放
9
- - **事件系统** — 基于 bedrock `Emitter` 提供 `onBeforeExecute` / `onAfterExecute` 等生命周期钩子
10
- - **结构化错误处理** — 使用 `ILvErrorOr<T>` 代替 throw/reject,错误码可追溯
8
+ - **Disposable 体系** — 继承自 rockbed `Disposable` 基类,自动管理资源释放
9
+ - **事件系统** — 基于 rockbed `Emitter` 提供 `onBeforeExecute` / `onAfterExecute` 等生命周期钩子
10
+ - **结构化错误处理** — 使用 `Result<T>` 代替 throw/reject,错误码可追溯
11
11
  - **TypeScript 严格模式** — 全量 strict,类型安全
12
12
  - **开发热调试** — 基于 tsx 直接运行 TS,支持 `--inspect` 调试
13
13
 
@@ -25,11 +25,10 @@ template-commander/
25
25
  │ │ ├── hello/ # 示例命令组
26
26
  │ │ ├── pippit/ # pippit 命令组
27
27
  │ │ └── git/ # 新增 git 命令组
28
- │ └── bedrock/ # 基础设施层
29
- │ ├── dispose/ # Disposable 资源管理
30
- │ ├── event/ # 事件发射器
31
- │ ├── error/ # 结构化错误 (ILvErrorOr)
32
- │ └── ...
28
+ │ └── bedrock/ # 本地补充基础设施
29
+ │ ├── config/ # 本地配置读写
30
+ │ ├── pkg/ # package.json 查找
31
+ │ └── uuid/ # UUID 工具
33
32
  ├── package.json
34
33
  └── tsconfig.json
35
34
  ```
@@ -66,7 +65,7 @@ import type { Command } from 'commander';
66
65
  import { BaseCommand } from '../core/base-command.js';
67
66
  import type { ICommandActionContext } from '../core/base-command.js';
68
67
  import type { ICommandMeta } from '../core/command-types.js';
69
- import type { ILvErrorOr } from '../bedrock/error/index.js';
68
+ import type { Result } from 'rockbed/error';
70
69
 
71
70
  interface IMyOptions {
72
71
  verbose: boolean;
@@ -89,7 +88,7 @@ export class MyCommand extends BaseCommand<IMyOptions> {
89
88
  cmd.option('--verbose', '详细输出', false);
90
89
  }
91
90
 
92
- protected async _execute(ctx: ICommandActionContext<IMyOptions>): Promise<ILvErrorOr<void>> {
91
+ protected async _execute(ctx: ICommandActionContext<IMyOptions>): Promise<Result<void>> {
93
92
  const target = ctx.args[0] as string;
94
93
 
95
94
  if (ctx.options.verbose) {
@@ -123,7 +122,7 @@ app.registerCommand(new MyCommand());
123
122
  | 方法 | 说明 |
124
123
  |---|---|
125
124
  | `_meta()` | 返回命令名、描述、别名 |
126
- | `_execute(ctx)` | 命令核心逻辑,返回 `ILvErrorOr<void>` |
125
+ | `_execute(ctx)` | 命令核心逻辑,返回 `Result<void>` |
127
126
  | `_configureOptions(cmd)` | (可选) 配置 commander 选项 |
128
127
  | `_configureArguments(cmd)` | (可选) 配置 commander 参数 |
129
128
  | `getExample()` | 根据已注册的参数和选项自动生成命令执行示例 |
@@ -141,7 +140,7 @@ cmd.onAfterExecute((result) => {
141
140
 
142
141
  ### 错误处理
143
142
 
144
- 使用 `ILvErrorOr<T>` 而非 throw:
143
+ 使用 `Result<T>` 而非 throw:
145
144
 
146
145
  ```typescript
147
146
  // 成功
@@ -150,9 +149,10 @@ return this._makeOk();
150
149
  // 失败 (错误码 + 消息)
151
150
  return this._makeError(1001, '文件不存在');
152
151
 
153
- // 也可使用 bedrock 预定义错误
154
- import { invalidArgumentError } from '../bedrock/error/index.js';
155
- return invalidArgumentError('参数 name 不能为空');
152
+ // 也可定义可复用错误
153
+ import { defineError } from 'rockbed/error';
154
+ const missingNameError = defineError(1002, '参数 name 不能为空');
155
+ return missingNameError();
156
156
  ```
157
157
 
158
158
  ## Scripts
@@ -0,0 +1,367 @@
1
+ // src/core/cli-app.ts
2
+ import { Command } from "commander";
3
+ import { Disposable } from "rockbed/dispose";
4
+ import { Emitter } from "rockbed/event";
5
+ import { ok, err } from "rockbed/error";
6
+ var CliApp = class extends Disposable {
7
+ constructor(_options) {
8
+ super();
9
+ this._options = _options;
10
+ this._program = new Command();
11
+ 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");
12
+ }
13
+ _program;
14
+ _commands = [];
15
+ _onBeforeRun = this._register(new Emitter());
16
+ _onAfterRun = this._register(new Emitter());
17
+ onBeforeRun = this._onBeforeRun.event;
18
+ onAfterRun = this._onAfterRun.event;
19
+ get program() {
20
+ return this._program;
21
+ }
22
+ registerCommand(cmd, options = {}) {
23
+ this._commands.push({
24
+ command: cmd,
25
+ hidden: options.hidden ?? false
26
+ });
27
+ this._register(cmd);
28
+ this._program.addCommand(
29
+ cmd.command,
30
+ options.hidden ? { hidden: true } : void 0
31
+ );
32
+ }
33
+ async run(argv) {
34
+ const args = argv ?? process.argv;
35
+ this._onBeforeRun.fire(args);
36
+ try {
37
+ if (this._isDoubleHelp(args)) {
38
+ this.outputHelp(true);
39
+ this._onAfterRun.fire();
40
+ return ok();
41
+ }
42
+ await this._program.parseAsync(args);
43
+ this._onAfterRun.fire();
44
+ return ok();
45
+ } catch (caughtError) {
46
+ const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
47
+ return err(1, `CLI execution failed: ${message}`);
48
+ }
49
+ }
50
+ dispose() {
51
+ this._commands.length = 0;
52
+ super.dispose();
53
+ }
54
+ outputHelp(includeHidden = false) {
55
+ process.stdout.write(this.helpInformation(includeHidden));
56
+ }
57
+ helpInformation(includeHidden = false) {
58
+ if (!includeHidden) {
59
+ return this._program.helpInformation();
60
+ }
61
+ const hiddenCommands = this._commands.filter((entry) => entry.hidden).map((entry) => entry.command.command);
62
+ const previousHiddenStates = hiddenCommands.map((command) => {
63
+ const rawCommand = command;
64
+ const previousHidden = rawCommand._hidden;
65
+ rawCommand._hidden = false;
66
+ return previousHidden;
67
+ });
68
+ try {
69
+ return this._program.helpInformation();
70
+ } finally {
71
+ hiddenCommands.forEach((command, index) => {
72
+ const rawCommand = command;
73
+ rawCommand._hidden = previousHiddenStates[index];
74
+ });
75
+ }
76
+ }
77
+ _isDoubleHelp(argv) {
78
+ const userArgs = argv.slice(2);
79
+ return userArgs.length > 0 && userArgs[0] === "-hh";
80
+ }
81
+ };
82
+
83
+ // src/core/base-command.ts
84
+ import { Command as Command2 } from "commander";
85
+ import { Disposable as Disposable2 } from "rockbed/dispose";
86
+ import { Emitter as Emitter2 } from "rockbed/event";
87
+ import { ok as ok2, err as err2 } from "rockbed/error";
88
+ import { makeSuccessResponse, makeErrorResponse } from "rockbed/response";
89
+
90
+ // src/core/command-example.ts
91
+ function _getCommandPath(command) {
92
+ const names = [];
93
+ for (let current = command; current; current = current.parent) {
94
+ names.unshift(current.name());
95
+ }
96
+ return names;
97
+ }
98
+ function _getRepresentativeValue(name, defaultValue, choices) {
99
+ if (defaultValue !== void 0) {
100
+ return String(defaultValue);
101
+ }
102
+ if (choices && choices.length > 0) {
103
+ return choices[0];
104
+ }
105
+ return name;
106
+ }
107
+ function _formatArgument(argument) {
108
+ const name = argument.name();
109
+ const token = _getRepresentativeValue(name, argument.defaultValue, argument.argChoices);
110
+ const hasConcreteValue = argument.defaultValue !== void 0 || argument.argChoices !== void 0 && argument.argChoices.length > 0;
111
+ if (hasConcreteValue) {
112
+ return argument.variadic ? `${token}...` : token;
113
+ }
114
+ if (argument.required) {
115
+ return `<${argument.variadic ? `${token}...` : token}>`;
116
+ }
117
+ return `[${argument.variadic ? `${token}...` : token}]`;
118
+ }
119
+ function _getOptionFlag(option) {
120
+ return option.short ?? option.long ?? option.flags.split(",")[0].trim();
121
+ }
122
+ function _isNegatedBooleanOption(option) {
123
+ return option.flags.split(",").map((flag) => flag.trim()).some((flag) => flag.startsWith("--no-") && !flag.includes("<") && !flag.includes("["));
124
+ }
125
+ function _isHiddenHelpOption(option) {
126
+ return option.hidden || option.flags.includes("--help");
127
+ }
128
+ function _formatOption(option) {
129
+ if (_isHiddenHelpOption(option)) {
130
+ return null;
131
+ }
132
+ const flag = _getOptionFlag(option);
133
+ if (option.isBoolean() || _isNegatedBooleanOption(option)) {
134
+ if (!option.mandatory && option.defaultValue === false) {
135
+ return null;
136
+ }
137
+ return flag;
138
+ }
139
+ const value = _getRepresentativeValue(
140
+ option.attributeName(),
141
+ option.defaultValue,
142
+ option.argChoices
143
+ );
144
+ const hasConcreteValue = option.defaultValue !== void 0 || option.argChoices !== void 0 && option.argChoices.length > 0;
145
+ if (!option.mandatory && option.defaultValue !== void 0) {
146
+ return null;
147
+ }
148
+ if (hasConcreteValue) {
149
+ return `${flag} ${value}`;
150
+ }
151
+ return `${flag} ${option.required ? value : `[${value}]`}`;
152
+ }
153
+ function makeCommandExample(command) {
154
+ const parts = _getCommandPath(command);
155
+ const optionParts = command.options.map((option) => _formatOption(option)).filter((part) => part !== null);
156
+ const argumentParts = command.registeredArguments.map(
157
+ (argument) => _formatArgument(argument)
158
+ );
159
+ return [...parts, ...optionParts, ...argumentParts].join(" ").replace(/\s+/g, " ").trim();
160
+ }
161
+
162
+ // src/core/base-command.ts
163
+ var BaseCommand = class extends Disposable2 {
164
+ _command;
165
+ _onBeforeExecute = this._register(new Emitter2());
166
+ _onAfterExecute = this._register(
167
+ new Emitter2()
168
+ );
169
+ onBeforeExecute = this._onBeforeExecute.event;
170
+ onAfterExecute = this._onAfterExecute.event;
171
+ constructor() {
172
+ super();
173
+ const meta = this._meta();
174
+ this._command = new Command2(meta.name);
175
+ this._command.description(meta.description);
176
+ if (meta.aliases) {
177
+ this._command.aliases(meta.aliases);
178
+ }
179
+ this._configureOptions(this._command);
180
+ this._configureArguments(this._command);
181
+ this._command.addHelpText("after", () => {
182
+ return `
183
+ \u6267\u884C\u6848\u4F8B:
184
+ ${this.getExample()}
185
+ `;
186
+ });
187
+ this._command.action(async (...rawArgs) => {
188
+ const ctx = this._parseActionArgs(rawArgs);
189
+ this._onBeforeExecute.fire();
190
+ let result;
191
+ try {
192
+ result = await this._execute(ctx);
193
+ } catch (caughtError) {
194
+ const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
195
+ result = err2(1, `Command "${meta.name}" failed: ${message}`);
196
+ }
197
+ this._onAfterExecute.fire(result);
198
+ if (!result.ok) {
199
+ process.stderr.write(`Error [${result.code}]: ${result.msg}
200
+ `);
201
+ process.exitCode = 1;
202
+ }
203
+ });
204
+ }
205
+ get command() {
206
+ return this._command;
207
+ }
208
+ /**
209
+ * 返回该命令的执行示例,供外部展示或调试使用。
210
+ */
211
+ getExample() {
212
+ return makeCommandExample(this._command);
213
+ }
214
+ _configureOptions(_cmd) {
215
+ }
216
+ _configureArguments(_cmd) {
217
+ }
218
+ _makeOk() {
219
+ return ok2();
220
+ }
221
+ _makeError(code, msg) {
222
+ return err2(code, msg);
223
+ }
224
+ /**
225
+ * 向 stdout 输出一行文本(最终用户可见的输出)
226
+ */
227
+ _output(text) {
228
+ process.stdout.write(text + "\n");
229
+ }
230
+ /**
231
+ * 向 stderr 输出调试 / 诊断信息(不会混入最终输出)
232
+ */
233
+ _debug(text) {
234
+ process.stderr.write(`[debug] ${text}
235
+ `);
236
+ }
237
+ /**
238
+ * 以 JSON 字符串形式输出成功结果到 stdout
239
+ */
240
+ _outputJsonOk(data) {
241
+ process.stdout.write(
242
+ JSON.stringify(makeSuccessResponse(data), null, 2) + "\n"
243
+ );
244
+ }
245
+ /**
246
+ * 以 JSON 字符串形式输出错误结果到 stdout
247
+ */
248
+ _outputJsonError(code, msg) {
249
+ process.stdout.write(
250
+ JSON.stringify(makeErrorResponse(code, msg), null, 2) + "\n"
251
+ );
252
+ }
253
+ _parseActionArgs(rawArgs) {
254
+ const command = rawArgs[rawArgs.length - 1];
255
+ const options = rawArgs[rawArgs.length - 2];
256
+ const args = rawArgs.slice(0, rawArgs.length - 2);
257
+ return { args, options, command };
258
+ }
259
+ };
260
+
261
+ // src/core/base-subcommand-host.ts
262
+ import { Command as Command3 } from "commander";
263
+ import { Disposable as Disposable3 } from "rockbed/dispose";
264
+ import { Emitter as Emitter3 } from "rockbed/event";
265
+ import { ok as ok3, err as err3 } from "rockbed/error";
266
+ import { makeSuccessResponse as makeSuccessResponse2, makeErrorResponse as makeErrorResponse2 } from "rockbed/response";
267
+ var BaseSubcommandHost = class extends Disposable3 {
268
+ _command;
269
+ _subcommands = [];
270
+ _onBeforeExecute = this._register(new Emitter3());
271
+ _onAfterExecute = this._register(
272
+ new Emitter3()
273
+ );
274
+ onBeforeExecute = this._onBeforeExecute.event;
275
+ onAfterExecute = this._onAfterExecute.event;
276
+ constructor() {
277
+ super();
278
+ const meta = this._meta();
279
+ this._command = new Command3(meta.name);
280
+ this._command.description(meta.description);
281
+ if (meta.aliases) {
282
+ this._command.aliases(meta.aliases);
283
+ }
284
+ this._configureOptions(this._command);
285
+ this._configureArguments(this._command);
286
+ this._registerSubcommands();
287
+ this._command.action(async (...rawArgs) => {
288
+ const ctx = this._parseActionArgs(rawArgs);
289
+ this._onBeforeExecute.fire();
290
+ let result;
291
+ try {
292
+ result = await this._executeFallback(ctx);
293
+ } catch (caughtError) {
294
+ const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
295
+ result = err3(1, `Command "${meta.name}" failed: ${message}`);
296
+ }
297
+ this._onAfterExecute.fire(result);
298
+ if (!result.ok) {
299
+ process.stderr.write(`Error [${result.code}]: ${result.msg}
300
+ `);
301
+ process.exitCode = 1;
302
+ }
303
+ });
304
+ }
305
+ get command() {
306
+ return this._command;
307
+ }
308
+ /**
309
+ * 返回该命令宿主的执行示例,供外部展示或调试使用。
310
+ */
311
+ getExample() {
312
+ return makeCommandExample(this._command);
313
+ }
314
+ /**
315
+ * 当用户没有指定子命令时的默认行为。
316
+ * 默认显示帮助信息,子类可覆盖。
317
+ */
318
+ _executeFallback(_ctx) {
319
+ this._command.outputHelp();
320
+ return Promise.resolve(ok3());
321
+ }
322
+ _configureOptions(_cmd) {
323
+ }
324
+ _configureArguments(_cmd) {
325
+ }
326
+ _addSubcommand(cmd) {
327
+ this._subcommands.push(cmd);
328
+ this._register(cmd);
329
+ this._command.addCommand(cmd.command);
330
+ }
331
+ _makeOk() {
332
+ return ok3();
333
+ }
334
+ _makeError(code, msg) {
335
+ return err3(code, msg);
336
+ }
337
+ _output(text) {
338
+ process.stdout.write(text + "\n");
339
+ }
340
+ _debug(text) {
341
+ process.stderr.write(`[debug] ${text}
342
+ `);
343
+ }
344
+ _outputJsonOk(data) {
345
+ process.stdout.write(JSON.stringify(makeSuccessResponse2(data)) + "\n");
346
+ }
347
+ _outputJsonError(code, msg) {
348
+ process.stdout.write(JSON.stringify(makeErrorResponse2(code, msg)) + "\n");
349
+ }
350
+ dispose() {
351
+ this._subcommands.length = 0;
352
+ super.dispose();
353
+ }
354
+ _parseActionArgs(rawArgs) {
355
+ const command = rawArgs[rawArgs.length - 1];
356
+ const options = rawArgs[rawArgs.length - 2];
357
+ const args = rawArgs.slice(0, rawArgs.length - 2);
358
+ return { args, options, command };
359
+ }
360
+ };
361
+
362
+ export {
363
+ CliApp,
364
+ BaseCommand,
365
+ BaseSubcommandHost
366
+ };
367
+ //# sourceMappingURL=chunk-S2SVYY3T.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/cli-app.ts","../src/core/base-command.ts","../src/core/command-example.ts","../src/core/base-subcommand-host.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { Disposable } from 'rockbed/dispose';\nimport { Emitter } from 'rockbed/event';\nimport type { Event } from 'rockbed/event';\nimport type { Result } from 'rockbed/error';\nimport { ok, err } from 'rockbed/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<Result<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 ok();\n }\n\n await this._program.parseAsync(args);\n this._onAfterRun.fire();\n return ok();\n } catch (caughtError) {\n const message =\n caughtError instanceof Error ? caughtError.message : String(caughtError);\n return err(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","import { Command } from \"commander\";\nimport { Disposable } from 'rockbed/dispose';\nimport { Emitter } from 'rockbed/event';\nimport type { Event } from 'rockbed/event';\nimport type { Result } from 'rockbed/error';\nimport { ok, err } from 'rockbed/error';\nimport { makeSuccessResponse, makeErrorResponse } from 'rockbed/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<[Result<void>]>(),\n );\n\n public readonly onBeforeExecute: Event<[]> = this._onBeforeExecute.event;\n public readonly onAfterExecute: Event<[Result<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: Result<void>;\n try {\n result = await this._execute(ctx);\n } catch (caughtError) {\n const message = caughtError instanceof Error ? caughtError.message : String(caughtError);\n result = err(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<Result<void>>;\n\n protected _configureOptions(_cmd: Command): void {}\n\n protected _configureArguments(_cmd: Command): void {}\n\n protected _makeOk(): Result<void> {\n return ok();\n }\n\n protected _makeError(code: number, msg: string): Result<void> {\n return err(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","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 _isNegatedBooleanOption(option: Option): boolean {\n return option.flags\n .split(\",\")\n .map((flag) => flag.trim())\n .some((flag) => flag.startsWith(\"--no-\") && !flag.includes(\"<\") && !flag.includes(\"[\"));\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() || _isNegatedBooleanOption(option)) {\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 'rockbed/dispose';\nimport { Emitter } from 'rockbed/event';\nimport type { Event } from 'rockbed/event';\nimport type { Result } from 'rockbed/error';\nimport { ok, err } from 'rockbed/error';\nimport { makeSuccessResponse, makeErrorResponse } from 'rockbed/response';\nimport { makeCommandExample } from \"./command-example\";\nimport type { ICommandMeta } from \"./command-types\";\nimport type { ICommandActionContext } from \"./base-command\";\nimport type { IRegistrableCommand } from \"./command-types\";\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 private readonly _subcommands: IRegistrableCommand[] = [];\n\n private readonly _onBeforeExecute = this._register(new Emitter<[]>());\n private readonly _onAfterExecute = this._register(\n new Emitter<[Result<void>]>(),\n );\n\n public readonly onBeforeExecute: Event<[]> = this._onBeforeExecute.event;\n public readonly onAfterExecute: Event<[Result<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._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: Result<void>;\n try {\n result = await this._executeFallback(ctx);\n } catch (caughtError) {\n const message =\n caughtError instanceof Error ? caughtError.message : String(caughtError);\n result = err(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<Result<void>> {\n this._command.outputHelp();\n return Promise.resolve(ok());\n }\n\n protected _configureOptions(_cmd: Command): void {}\n\n protected _configureArguments(_cmd: Command): void {}\n\n protected _addSubcommand(cmd: IRegistrableCommand): void {\n this._subcommands.push(cmd);\n this._register(cmd);\n this._command.addCommand(cmd.command);\n }\n\n protected _makeOk(): Result<void> {\n return ok();\n }\n\n protected _makeError(code: number, msg: string): Result<void> {\n return err(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":"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","names":["Command","Disposable","Emitter","ok","err","Disposable","Emitter","Command","err","ok","Command","Disposable","Emitter","ok","err","makeSuccessResponse","makeErrorResponse","Disposable","Emitter","Command","err","ok","makeSuccessResponse","makeErrorResponse"]}
package/dist/index.d.ts CHANGED
@@ -1,53 +1,7 @@
1
1
  import { Command } from 'commander';
2
-
3
- interface IDisposable {
4
- dispose: () => void;
5
- }
6
-
7
- declare class DisposableStore implements IDisposable {
8
- static DISABLE_DISPOSED_WARNING: boolean;
9
- private readonly _toDispose;
10
- private _isDisposed;
11
- constructor();
12
- get isDisposed(): boolean;
13
- dispose(): void;
14
- clear(): void;
15
- add<T extends IDisposable>(o: T): T;
16
- }
17
-
18
- declare abstract class Disposable implements IDisposable {
19
- protected readonly _store: DisposableStore;
20
- constructor();
21
- dispose(): void;
22
- protected _register<T extends IDisposable>(o: T): T;
23
- }
24
-
25
- interface Event<T extends any[]> {
26
- (listener: (...args: T) => any, thisArgs?: any): IDisposable;
27
- }
28
-
29
- type ILvErrorRef = ILvErrorOr<never>;
30
- interface ILvRealErrorRef {
31
- readonly ok: false;
32
- readonly code: number;
33
- readonly msg: string;
34
- readonly cause?: ILvErrorRef | Error;
35
- readonly toString: () => string;
36
- readonly pair: () => [ILvRealErrorRef, null];
37
- readonly errorInfo?: unknown;
38
- }
39
- interface ILvValueRef<T> {
40
- readonly ok: true;
41
- readonly code: 0;
42
- readonly msg: '';
43
- readonly cause?: undefined;
44
- readonly value: T;
45
- readonly toString: () => string;
46
- readonly pair: () => [null, T];
47
- }
48
- type ILvErrorOr<T> = (ILvRealErrorRef | ILvValueRef<T>) & {
49
- readonly pair: () => [null, T] | [ILvRealErrorRef, null];
50
- };
2
+ import { IDisposable, Disposable } from 'rockbed/dispose';
3
+ import { Event } from 'rockbed/event';
4
+ import { Result } from 'rockbed/error';
51
5
 
52
6
  interface ICommandMeta {
53
7
  readonly name: string;
@@ -81,7 +35,7 @@ declare class CliApp extends Disposable {
81
35
  constructor(_options: ICliAppOptions);
82
36
  get program(): Command;
83
37
  registerCommand(cmd: IRegistrableCommand, options?: IRegisterCommandOptions): void;
84
- run(argv?: string[]): Promise<ILvErrorOr<void>>;
38
+ run(argv?: string[]): Promise<Result<void>>;
85
39
  dispose(): void;
86
40
  outputHelp(includeHidden?: boolean): void;
87
41
  helpInformation(includeHidden?: boolean): string;
@@ -98,7 +52,7 @@ declare abstract class BaseCommand<TOptions = Record<string, unknown>> extends D
98
52
  private readonly _onBeforeExecute;
99
53
  private readonly _onAfterExecute;
100
54
  readonly onBeforeExecute: Event<[]>;
101
- readonly onAfterExecute: Event<[ILvErrorOr<void>]>;
55
+ readonly onAfterExecute: Event<[Result<void>]>;
102
56
  constructor();
103
57
  get command(): Command;
104
58
  /**
@@ -106,11 +60,11 @@ declare abstract class BaseCommand<TOptions = Record<string, unknown>> extends D
106
60
  */
107
61
  getExample(): string;
108
62
  protected abstract _meta(): ICommandMeta;
109
- protected abstract _execute(ctx: ICommandActionContext<TOptions>): Promise<ILvErrorOr<void>>;
63
+ protected abstract _execute(ctx: ICommandActionContext<TOptions>): Promise<Result<void>>;
110
64
  protected _configureOptions(_cmd: Command): void;
111
65
  protected _configureArguments(_cmd: Command): void;
112
- protected _makeOk(): ILvErrorOr<void>;
113
- protected _makeError(code: number, msg: string): ILvErrorOr<void>;
66
+ protected _makeOk(): Result<void>;
67
+ protected _makeError(code: number, msg: string): Result<void>;
114
68
  /**
115
69
  * 向 stdout 输出一行文本(最终用户可见的输出)
116
70
  */
@@ -145,7 +99,7 @@ declare abstract class BaseSubcommandHost extends Disposable {
145
99
  private readonly _onBeforeExecute;
146
100
  private readonly _onAfterExecute;
147
101
  readonly onBeforeExecute: Event<[]>;
148
- readonly onAfterExecute: Event<[ILvErrorOr<void>]>;
102
+ readonly onAfterExecute: Event<[Result<void>]>;
149
103
  constructor();
150
104
  get command(): Command;
151
105
  /**
@@ -161,11 +115,12 @@ declare abstract class BaseSubcommandHost extends Disposable {
161
115
  * 当用户没有指定子命令时的默认行为。
162
116
  * 默认显示帮助信息,子类可覆盖。
163
117
  */
164
- protected _executeFallback(_ctx: ICommandActionContext): Promise<ILvErrorOr<void>>;
118
+ protected _executeFallback(_ctx: ICommandActionContext): Promise<Result<void>>;
165
119
  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>;
120
+ protected _configureArguments(_cmd: Command): void;
121
+ protected _addSubcommand(cmd: IRegistrableCommand): void;
122
+ protected _makeOk(): Result<void>;
123
+ protected _makeError(code: number, msg: string): Result<void>;
169
124
  protected _output(text: string): void;
170
125
  protected _debug(text: string): void;
171
126
  protected _outputJsonOk<T>(data: T): void;
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  BaseCommand,
3
3
  BaseSubcommandHost,
4
4
  CliApp
5
- } from "./chunk-K7B7LABE.js";
5
+ } from "./chunk-S2SVYY3T.js";
6
6
  export {
7
7
  BaseCommand,
8
8
  BaseSubcommandHost,