mixcli 3.0.9 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { LiteEvent } from 'flex-tools/events/liteEvent';
2
2
  import { Option, Command } from 'commander';
3
3
  import { PromptObject } from 'prompts';
4
- import * as flex_tools_types_asyncFunction from 'flex-tools/types/asyncFunction';
4
+ import * as flex_tools__ from 'flex-tools/*';
5
5
 
6
6
  type PromptType = "text" | "password" | "invisible" | "number" | "confirm" | "list" | "toggle" | "select" | "multiselect" | "autocomplete" | "date" | "autocompleteMultiselect";
7
7
  type PromptParam = 'auto' | boolean | PromptType | PromptObject;
@@ -81,6 +81,7 @@ interface MixedOptionParams extends IPromptableOptions {
81
81
  };
82
82
  }
83
83
  declare class MixOption extends Option implements IPromptable {
84
+ __MIX_OPTION__: boolean;
84
85
  prompt?: PromptManager;
85
86
  promptChoices?: PromptChoice[];
86
87
  private _validate?;
@@ -137,6 +138,7 @@ type EnhanceAction = ({ args, options, value, command, }: {
137
138
  }) => void | Promise<any>;
138
139
  declare const BREAK: unique symbol;
139
140
  declare class MixCommand extends Command {
141
+ __MIX_COMMAND__: boolean;
140
142
  private _beforeHooks;
141
143
  private _afterHooks;
142
144
  private _customPrompts;
@@ -253,6 +255,7 @@ interface MixCliOptions {
253
255
  cliDir?: string;
254
256
  context?: Record<string, any>;
255
257
  prompt?: 'auto' | boolean;
258
+ ignoreError?: boolean;
256
259
  }
257
260
  type MixCliCommand = (cli: MixCli) => MixCommand | MixCommand[] | void;
258
261
  type MixCliEvents = "register";
@@ -382,10 +385,10 @@ declare function isEnablePrompts(): boolean;
382
385
  * @param args
383
386
  */
384
387
  declare function outputDebug(message: string, ...args: any[]): void;
385
- declare const fileExists: flex_tools_types_asyncFunction.AsyncFunction;
386
- declare const readFile: flex_tools_types_asyncFunction.AsyncFunction;
387
- declare const writeFile: flex_tools_types_asyncFunction.AsyncFunction;
388
- declare const mkdir: flex_tools_types_asyncFunction.AsyncFunction;
388
+ declare const fileExists: flex_tools__.AsyncFunction;
389
+ declare const readFile: flex_tools__.AsyncFunction;
390
+ declare const writeFile: flex_tools__.AsyncFunction;
391
+ declare const mkdir: flex_tools__.AsyncFunction;
389
392
  /**
390
393
  * 基于artTemplate模板生成文件
391
394
  *
@@ -410,4 +413,4 @@ declare function showError(e: any): void;
410
413
  declare function getId(): string;
411
414
  declare function importModule(file: string): Promise<any>;
412
415
 
413
- export { ActionOptions, ActionRegistry, AfterCommandHookListener, BREAK, BeforeCommandHookListener, EnhanceAction, ICommandHookListener, MixCli, MixCliCommand, MixCliEvents, MixCliOptions, MixCommand, MixOption, MixedOptionParams, OriginalAction, addBuiltInOptions, createFileByTemplate, fileExists, fixIndent, getId, importModule, isDebug, isEnablePrompts, mkDirs, mkdir, outputDebug, outputStr, readFile, showError, writeFile };
416
+ export { type ActionOptions, type ActionRegistry, type AfterCommandHookListener, BREAK, type BeforeCommandHookListener, type EnhanceAction, type ICommandHookListener, MixCli, type MixCliCommand, type MixCliEvents, type MixCliOptions, MixCommand, MixOption, type MixedOptionParams, type OriginalAction, addBuiltInOptions, createFileByTemplate, fileExists, fixIndent, getId, importModule, isDebug, isEnablePrompts, mkDirs, mkdir, outputDebug, outputStr, readFile, showError, writeFile };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { LiteEvent } from 'flex-tools/events/liteEvent';
2
2
  import { Option, Command } from 'commander';
3
3
  import { PromptObject } from 'prompts';
4
- import * as flex_tools_types_asyncFunction from 'flex-tools/types/asyncFunction';
4
+ import * as flex_tools__ from 'flex-tools/*';
5
5
 
6
6
  type PromptType = "text" | "password" | "invisible" | "number" | "confirm" | "list" | "toggle" | "select" | "multiselect" | "autocomplete" | "date" | "autocompleteMultiselect";
7
7
  type PromptParam = 'auto' | boolean | PromptType | PromptObject;
@@ -81,6 +81,7 @@ interface MixedOptionParams extends IPromptableOptions {
81
81
  };
82
82
  }
83
83
  declare class MixOption extends Option implements IPromptable {
84
+ __MIX_OPTION__: boolean;
84
85
  prompt?: PromptManager;
85
86
  promptChoices?: PromptChoice[];
86
87
  private _validate?;
@@ -137,6 +138,7 @@ type EnhanceAction = ({ args, options, value, command, }: {
137
138
  }) => void | Promise<any>;
138
139
  declare const BREAK: unique symbol;
139
140
  declare class MixCommand extends Command {
141
+ __MIX_COMMAND__: boolean;
140
142
  private _beforeHooks;
141
143
  private _afterHooks;
142
144
  private _customPrompts;
@@ -253,6 +255,7 @@ interface MixCliOptions {
253
255
  cliDir?: string;
254
256
  context?: Record<string, any>;
255
257
  prompt?: 'auto' | boolean;
258
+ ignoreError?: boolean;
256
259
  }
257
260
  type MixCliCommand = (cli: MixCli) => MixCommand | MixCommand[] | void;
258
261
  type MixCliEvents = "register";
@@ -382,10 +385,10 @@ declare function isEnablePrompts(): boolean;
382
385
  * @param args
383
386
  */
384
387
  declare function outputDebug(message: string, ...args: any[]): void;
385
- declare const fileExists: flex_tools_types_asyncFunction.AsyncFunction;
386
- declare const readFile: flex_tools_types_asyncFunction.AsyncFunction;
387
- declare const writeFile: flex_tools_types_asyncFunction.AsyncFunction;
388
- declare const mkdir: flex_tools_types_asyncFunction.AsyncFunction;
388
+ declare const fileExists: flex_tools__.AsyncFunction;
389
+ declare const readFile: flex_tools__.AsyncFunction;
390
+ declare const writeFile: flex_tools__.AsyncFunction;
391
+ declare const mkdir: flex_tools__.AsyncFunction;
389
392
  /**
390
393
  * 基于artTemplate模板生成文件
391
394
  *
@@ -410,4 +413,4 @@ declare function showError(e: any): void;
410
413
  declare function getId(): string;
411
414
  declare function importModule(file: string): Promise<any>;
412
415
 
413
- export { ActionOptions, ActionRegistry, AfterCommandHookListener, BREAK, BeforeCommandHookListener, EnhanceAction, ICommandHookListener, MixCli, MixCliCommand, MixCliEvents, MixCliOptions, MixCommand, MixOption, MixedOptionParams, OriginalAction, addBuiltInOptions, createFileByTemplate, fileExists, fixIndent, getId, importModule, isDebug, isEnablePrompts, mkDirs, mkdir, outputDebug, outputStr, readFile, showError, writeFile };
416
+ export { type ActionOptions, type ActionRegistry, type AfterCommandHookListener, BREAK, type BeforeCommandHookListener, type EnhanceAction, type ICommandHookListener, MixCli, type MixCliCommand, type MixCliEvents, type MixCliOptions, MixCommand, MixOption, type MixedOptionParams, type OriginalAction, addBuiltInOptions, createFileByTemplate, fileExists, fixIndent, getId, importModule, isDebug, isEnablePrompts, mkDirs, mkdir, outputDebug, outputStr, readFile, showError, writeFile };
package/dist/index.js CHANGED
@@ -316,6 +316,7 @@ var PromptManager = class {
316
316
  var MixOption = class extends import_commander.Option {
317
317
  constructor(flags, description, optsOrDefault) {
318
318
  super(flags, description);
319
+ this.__MIX_OPTION__ = true;
319
320
  let params = {};
320
321
  if (arguments.length == 3 && typeof arguments[2] == "object") {
321
322
  params = Object.assign({}, arguments[2]);
@@ -415,6 +416,7 @@ var MixCommand = class extends import_commander2.Command {
415
416
  // 是否启用交互提示
416
417
  constructor(name) {
417
418
  super(name);
419
+ this.__MIX_COMMAND__ = true;
418
420
  this._beforeHooks = [];
419
421
  this._afterHooks = [];
420
422
  this._customPrompts = [];
@@ -724,7 +726,7 @@ var MixCommand = class extends import_commander2.Command {
724
726
  */
725
727
  generateAutoPrompts() {
726
728
  const options = this.options;
727
- const optionPromports = options.filter((option) => !option.hidden && option instanceof MixOption).map((option) => option.getPrompt(this._optionValues[option.name()])).filter((prompt) => prompt);
729
+ const optionPromports = options.filter((option) => !option.hidden && option.__MIX_OPTION__).map((option) => option.getPrompt(this._optionValues[option.name()])).filter((prompt) => prompt);
728
730
  outputDebug("\u547D\u4EE4<{}>\u81EA\u52A8\u751F\u6210{}\u4E2A\u9009\u9879\u63D0\u793A:{}", [
729
731
  this.name(),
730
732
  optionPromports.length,
@@ -915,7 +917,8 @@ var MixCli = class extends import_liteEvent.LiteEvent {
915
917
  name: "mixcli",
916
918
  package: null,
917
919
  cliDir: "cli",
918
- prompt: "auto"
920
+ prompt: "auto",
921
+ ignoreError: false
919
922
  }, options);
920
923
  this.createRootCommand();
921
924
  }
@@ -945,6 +948,7 @@ var MixCli = class extends import_liteEvent.LiteEvent {
945
948
  this.register(() => cmds);
946
949
  }
947
950
  } catch (e) {
951
+ outputDebug("\u6CE8\u518C\u547D\u4EE4\u5931\u8D25:{}", e.stack);
948
952
  }
949
953
  }
950
954
  });
@@ -998,14 +1002,17 @@ var MixCli = class extends import_liteEvent.LiteEvent {
998
1002
  let result = cmd(this);
999
1003
  let cmds = result instanceof Array ? result : result == void 0 ? [] : [result];
1000
1004
  for (let cmd2 of cmds) {
1001
- if (cmd2 instanceof MixCommand) {
1005
+ if (cmd2.__MIX_COMMAND__) {
1002
1006
  if (this.hasCommand(cmd2.name())) {
1003
1007
  import_logsets2.default.error(`Command <${cmd2.name()}> has been registered!`);
1004
1008
  } else {
1009
+ outputDebug("\u6CE8\u518C\u547D\u4EE4:{}", cmd2.fullname);
1005
1010
  this.root.addCommand(cmd2);
1006
1011
  cmd2._cli = this;
1007
1012
  this.emit("register", cmd2.fullname, true);
1008
1013
  }
1014
+ } else {
1015
+ import_logsets2.default.error(`Command <${cmd2.toString()}> is not a valid command!`);
1009
1016
  }
1010
1017
  }
1011
1018
  } else {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/cli.ts","../src/command.ts","../src/option.ts","../src/utils.ts","../src/prompt.ts","../src/finder.ts"],"sourcesContent":["export * from \"./cli\"\r\nexport * from \"./utils\"\r\nexport * from \"./command\"\r\nexport * from \"./option\"","#!/usr/bin/env node\nimport \"flex-tools/string\"\nimport { LiteEvent, LiteEventSubscriber } from \"flex-tools/events/liteEvent\"\nimport { Command } from \"commander\"\nimport logsets from \"logsets\"\n\nimport { assignObject } from \"flex-tools/object/assignObject\"\nimport { MixCommand } from \"./command\"\nimport { addBuiltInOptions, fixIndent, isDebug } from './utils';\nimport { findCommands } from \"./finder\"\nimport { asyncSignal } from \"flex-tools/async/asyncSignal\"\n// @ts-ignore\nimport replaceAll from 'string.prototype.replaceall'\nimport { getPackageEntry, getPackageRootPath } from \"flex-tools\"\nimport { getPackageJson } from 'flex-tools/package/getPackageJson';\nreplaceAll.shim() \n\nexport interface MixCliOptions{\n name:string,\n title?:string | (string | boolean | number)[],\n description?:string,\n version?:string\n // 定义显示帮助信息\n logo?:string ,\n // 在根命令执行前执行==commander的preAction\n before?:(thisCommand:Command,actionCommand:Command)=>void,\n // 在根命令执行后执行==commander的postAction\n after?:(thisCommand:Command,actionCommand:Command)=>void, \n // flexcli运行时会在当前工程的package.json的依赖中查找以prefix/开头的包,然后自动加载其cli目录下的命令\n // 例如:prefix=myapp,则会自动加载flex-cli-xxx包中的cli目录下的命令\n // 如prefix=myapp, cliPath=\"cmds\",则会自动加载flex-cli-xxx包中的cmds目录下的命令\n include?:string | RegExp | string[] | RegExp[],\n // 忽略查找正则表达式\n exclude?:string | RegExp | string[] | RegExp[],\n // flexcli会在当前工程的以prefix/开头下查找命令声明\n // / pattern默认值是cli,即会在当前工程的以prefix/开头的包下查找cli目录下的命令\n // 指定cli所在的目录,默认值是cli,要遍历该目录下的所有js文件作为命令导出\n cliDir?:string \n context?:Record<string,any> // 传递给命令的共享上下文,所有命令均可要使用 \n // 默认是否启用交互提示, auto当没有值时,会根据当前是否在终端中运行来决定是否启用交互提示\n // 为false时,禁用所有交互提示,为true时,启用所有交互提示 \n prompt?:'auto' | boolean \n}\n\n \n \n\nexport type MixCliCommand = (cli:MixCli)=>MixCommand | MixCommand[] | void\n\n\nexport type MixCliEvents = \n \"register\" // 当命令注册时触发\n\nexport class MixCli extends LiteEvent<any,MixCliEvents>{\n options:Required<MixCliOptions> \n root!:Command \n private findSignals:any[]=[]\n constructor(options?:MixCliOptions){\n super()\n this.options= assignObject({\n name:\"mixcli\",\n package:null,\n cliDir:\"cli\",\n prompt:'auto'\n },options) \n this.createRootCommand() \n } \n get context(){return this.options.context}\n get name(){return this.options.name}\n /**\n * 是否禁用了所有的交互提示\n */\n get isDisabledPrompts(){\n return(this.root as any).rawArgs.includes(\"--no-prompts\") \n } \n /**\n * 扫描当前工程的依赖,加载匹配include的依赖下的命令\n */\n private async installCommands(){\n const cmders = await findCommands(this)\n for(let cmder of cmders){\n try{\n if(typeof(cmder)===\"function\"){\n let cmds = cmder(this)\n cmds =cmds ? (Array.isArray(cmds) ? cmds : [cmds]) : []\n this.register(()=>cmds) \n }\n }catch(e:any){\n }\n }\n } \n /**\n * 创建根命令\n * \n */\n private createRootCommand(){\n this.root = new MixCommand(this.name);\n this.root \n .helpOption('-h, --help')\n .action(()=>{ \n if(this.options.logo) logsets.log(fixIndent(this.options.logo,2))\n console.log()\n // 显示标题\n let title = this.options.title|| this.options.name\n if(Array.isArray(title)){\n logsets.log(String(title[0]).firstUpper(),[...title.slice(1)])\n }else{\n logsets.log(`${title.firstUpper()} Version: {}`,this.options.version)\n } \n // @ts-ignore\n if(this.options.description) logsets.log(logsets.colors.darkGray(this.options.description)) \n console.log()\n this.root.help() \n }) \n addBuiltInOptions(this.root)\n if(this.options.before) this.root.hook('preAction',this.options.before)\n if(this.options.after) this.root.hook('postAction',this.options.after) \n } \n /**\n * 添加帮助选项\n * \n * @param text 帮助文本\n * @param position 显示位置,可选值:before|after|beforeAll|afterAll\n * @param fixIndent 是否自动修正缩进,如果为true,则会自动修正缩进,当显示多行时文本时,会自动修正缩进\n * \n */\n public addHelp(text:string,{pos='beforeAll',alignIndent=true}:{pos:'before'|'after' | 'beforeAll' | 'afterAll',alignIndent?:boolean | number}){\n if(alignIndent) text = fixIndent(text,alignIndent)\n this.root.addHelpText(pos,text)\n }\n\n /**\n * 注册一个命令\n * @param cmd \n */\n register(cmd:MixCliCommand){\n if(typeof(cmd)==\"function\"){\n let result = cmd(this)\n let cmds = result instanceof Array ? result : (result==undefined ? [] : [result])\n for(let cmd of cmds){\n if(cmd instanceof MixCommand){\n if(this.hasCommand(cmd.name())){\n logsets.error(`Command <${cmd.name()}> has been registered!`)\n }else{\n this.root.addCommand(cmd) ;\n (cmd as any)._cli = this\n this.emit(\"register\",cmd.fullname,true)\n } \n }\n } \n }else{\n logsets.error(\"Invalid command\")\n } \n }\n\n hasCommand(name:string):boolean{\n return this.root.commands.some(c=>c.name()==name)\n }\n\n /**\n * 根据命令名称查找命令\n * \n * @remarks\n * \n * find(\"dev\")\n * find(\"dev.microservice\") 支持多级命令\n * find(\"abc\",DevCommand) 允许指定从DevCommand下开始查找abc命令\n * \n * @param name \n */\n get(name:string):MixCommand | undefined{\n const names=name.split(\".\")\n let curCmd:Command = this.root\n let resultCmd:MixCommand | undefined\n while(names.length>0){\n const topName = names.shift()\n const r = curCmd.commands.find(c=>c.name()==topName) as MixCommand\n if(r && names.length==0){\n resultCmd = r\n }\n curCmd = r\n } \n return resultCmd \n }\n /**\n * 查找一个命令\n * \n * 如果命令不存在,则等待命令注册后再返回\n * \n * 在多包场景下,如果命令在其他包中注册并且该包中的命令还没注册,则会等待命令注册后再返回\n * \n * @param name \n * @returns \n */\n find(name:string):Promise<MixCommand | undefined>{\n const cmd = this.get(name)\n if(cmd){\n return Promise.resolve(cmd) \n }else{\n const signal = asyncSignal()\n this.findSignals.push(signal)\n return new Promise<MixCommand | undefined>((resolve)=>{\n let listener:LiteEventSubscriber\n listener = this.on(\"register\",(fullname:string)=>{\n if(fullname==`${this.name}.${name}`){\n listener.off()\n signal.resolve()\n this.findSignals = this.findSignals.filter(s=>s!=signal)\n resolve(this.get(name))\n }\n },{objectify:true}) as LiteEventSubscriber\n })\n } \n }\n /**\n * 判断命令是否存在\n * \n * @param name \n * @returns \n */\n exists(name:string):boolean{\n if(name in this.root.commands){\n return true\n }else{\n return this.get(name) != undefined\n }\n } \n \n /**\n * 运行命令行程序\n */\n run(){ \n // 为什么有findSignal这玩意,解决什么问题?\n // 当我们要扩展command时,通过get(\"命令名称\")来获取已经注册的命令的方式有个缺陷\n // 就是如果对命令的注册顺序有严格的要求,比如调用get('dev')时要求dev命令必须已经存在\n // 这对动态包的命令注册扩展开发体验不好\n // 所以引入find(\"命令名称\")来获取命令,该方法可以获取到后注册的命令\n // 其副作用是,在run时,可能find还没有运行到,从而导致在帮助信息里面看不到扩展的信息(实际上是已经生效的)\n // 所以我们在find里面注入一个异步信号来解决此问题\n this.installCommands().then(()=>{\n return Promise.all(this.findSignals.map(signal=>signal(10000))).then(()=>{\n this.root.parseAsync(process.argv); \n })\n }) \n }\n /**\n * 创建一个命令\n * \n * \n */\n create(){\n } \n}\n ","import { Command, Option } from \"commander\";\r\nimport prompts, { PromptObject } from \"prompts\";\r\nimport { MixOption, type MixedOptionParams } from \"./option\";\r\nimport { addBuiltInOptions, isEnablePrompts, outputDebug } from \"./utils\";\r\nimport path from \"node:path\";\r\nimport fs from \"node:fs\";\r\nimport type { AsyncFunction } from \"flex-tools\";\r\n\r\nexport type ICommandHookListener = ({\r\n\targs,\r\n\toptions,\r\n\tcommand,\r\n}: {\r\n\targs: any[];\r\n\toptions: Record<string, any>;\r\n\tcommand: MixCommand;\r\n}) => void | Promise<void>;\r\n\r\nexport type BeforeCommandHookListener = ({\r\n\targs,\r\n\toptions,\r\n\tcommand,\r\n}: {\r\n\targs: any[];\r\n\toptions: Record<string, any>;\r\n\tcommand: MixCommand;\r\n}) => void | Promise<void>;\r\nexport type AfterCommandHookListener = ({\r\n\tvalue,\r\n\targs,\r\n\toptions,\r\n\tcommand,\r\n}: {\r\n\tvalue: any;\r\n\targs: any[];\r\n\toptions: Record<string, any>;\r\n\tcommand: MixCommand;\r\n}) => void | Promise<void>;\r\n\r\nexport interface ActionOptions {\r\n\tid: string;\r\n\tat: \"replace\" | \"before\" | \"after\" | \"preappend\" | \"append\" | number;\r\n\t// 函数签名类型,即采用原始的commander的action函数签名,还是mixcli的action函数签名\r\n\tenhance: boolean;\r\n}\r\n\r\nexport interface ActionRegistry extends Omit<ActionOptions, \"at\"> {\r\n\tfn: Function;\r\n}\r\n\r\n// 原始的Action动作函数\r\nexport type OriginalAction = (...args: any[]) => void | Promise<void>;\r\n// 增强的Action函数签名\r\nexport type EnhanceAction = ({\r\n\targs,\r\n\toptions,\r\n\tvalue,\r\n\tcommand,\r\n}: {\r\n\targs: any[];\r\n\toptions: Record<string, any>;\r\n\tvalue: any;\r\n\tcommand: MixCommand;\r\n}) => void | Promise<any>;\r\n\r\n// 执行action的返回结果\r\nexport const BREAK = Symbol(\"BREAK_ACTION\"); // 中止后续的action执行\r\n\r\nexport class MixCommand extends Command {\r\n\tprivate _beforeHooks: [BeforeCommandHookListener, boolean][] = [];\r\n\tprivate _afterHooks: [AfterCommandHookListener, boolean][] = [];\r\n\tprivate _customPrompts: PromptObject[] = [];\r\n\tprivate _optionValues: Record<string, any> = {}; // 命令行输入的选项值\r\n\tprivate _actions: ActionRegistry[] = []; // 允许多个action\r\n\tprivate _enable_prompts: boolean = true; // 是否启用交互提示\r\n\tconstructor(name?: string) {\r\n\t\tsuper(name);\r\n\t\tconst self = this;\r\n\t\tif (!this.isRoot) addBuiltInOptions(this);\r\n\t\tthis.hook(\"preAction\", async function (this: any) {\r\n\t\t\tself._optionValues = self.getOptionValues(this.hookedCommand);\r\n\t\t\ttry {\r\n\t\t\t\t// @ts-ignore\r\n\t\t\t\tawait self.preActionHook.apply(self, arguments);\r\n\t\t\t} catch {}\r\n\t\t});\r\n\t}\r\n\t/**\r\n\t * 是否是根命令\r\n\t */\r\n\tget isRoot() {\r\n\t\treturn !!!this.parent;\r\n\t}\r\n\tget actions() {\r\n\t\treturn this._actions;\r\n\t}\r\n\tget beforeHooks() {\r\n\t\treturn this._beforeHooks;\r\n\t}\r\n\tget afterHooks() {\r\n\t\treturn this._afterHooks;\r\n\t}\r\n\tget fullname() {\r\n\t\tlet names = [this.name()];\r\n\t\tlet parent = this.parent;\r\n\t\twhile (parent) {\r\n\t\t\tif (parent.name() !== \"root\") {\r\n\t\t\t\tnames.unshift(parent.name());\r\n\t\t\t}\r\n\t\t\tparent = parent.parent;\r\n\t\t}\r\n\t\treturn names.join(\".\");\r\n\t}\r\n\r\n\t/**\r\n\t * 返回根命令\r\n\t */\r\n\troot() {\r\n\t\tlet root: MixCommand | null | undefined = this;\r\n\t\twhile (root && root.parent != null) {\r\n\t\t\troot = root.parent as unknown as MixCommand;\r\n\t\t}\r\n\t\treturn root;\r\n\t}\r\n\taction(fn: EnhanceAction, options: ActionOptions): this;\r\n\taction(fn: OriginalAction): this;\r\n\taction(fn: OriginalAction): this {\r\n\t\tconst actionFunc = arguments[0];\r\n\t\tif (arguments.length == 1 && typeof actionFunc == \"function\") {\r\n\t\t\t// 原始方式\r\n\t\t\tthis._actions.push({\r\n\t\t\t\tid: Math.random().toString(36).substring(2),\r\n\t\t\t\tenhance: false,\r\n\t\t\t\tfn: actionFunc,\r\n\t\t\t});\r\n\t\t} else if (\r\n\t\t\targuments.length == 2 &&\r\n\t\t\ttypeof actionFunc == \"function\" &&\r\n\t\t\ttypeof arguments[1] == \"object\"\r\n\t\t) {\r\n\t\t\t// 增强模式\r\n\t\t\tconst actionFn = arguments[0];\r\n\t\t\tconst actionOpts: ActionOptions = Object.assign({ at: \"append\" }, arguments[1]);\r\n\t\t\tif (actionOpts.at == \"replace\") this._actions = [];\r\n\t\t\tconst actionItem = {\r\n\t\t\t\tid: actionOpts.id || Math.random().toString(36).substring(2),\r\n\t\t\t\tenhance: actionOpts.enhance == undefined ? true : actionOpts.enhance,\r\n\t\t\t\tfn: actionFn,\r\n\t\t\t} as const;\r\n\t\t\tif (typeof actionOpts.at == \"number\") {\r\n\t\t\t\tthis._actions.splice(Number(actionOpts.at), 0, actionItem);\r\n\t\t\t} else if ([\"append\", \"before\"].includes(actionOpts.at)) {\r\n\t\t\t\tthis._actions.push(actionItem);\r\n\t\t\t} else if ([\"preappend\", \"after\"].includes(actionOpts.at)) {\r\n\t\t\t\tthis._actions.splice(0, 0, actionItem);\r\n\t\t\t} else {\r\n\t\t\t\tthis._actions.push(actionItem);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tconsole.log(\"[mixcli] action params error\");\r\n\t\t}\r\n\t\treturn super.action(this.getWrapperedAction());\r\n\t}\r\n\r\n\t/**\r\n\t * 读取命令配置值,包括父命令提供的配置选项\r\n\t * @param command\r\n\t */\r\n\tprivate getOptionValues(command: Command) {\r\n\t\tlet opts = {};\r\n\t\tlet parent: Command | null = command;\r\n\t\twhile (parent) {\r\n\t\t\tObject.assign(opts, (parent as MixCommand)._optionValues);\r\n\t\t\tparent = parent.parent;\r\n\t\t}\r\n\t\treturn opts;\r\n\t}\r\n\t/**\r\n\t * 本函数在运行时子类进行action生成该命令的action\r\n\t */\r\n\tprivate getWrapperedAction() {\r\n\t\treturn this.wrapperWorkDirsAction(this.wrapperChainActions());\r\n\t}\r\n\r\n\t/**\r\n\t * 向上查找所有祖先命令\r\n\t */\r\n\tprivate getAncestorCommands(): MixCommand[] {\r\n\t\tlet cmds: MixCommand[] = [];\r\n\t\tlet cmd: MixCommand | null = this;\r\n\t\twhile (cmd) {\r\n\t\t\tcmd = cmd.parent as MixCommand;\r\n\t\t\tif (cmd) {\r\n\t\t\t\tcmds.push(cmd);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn cmds;\r\n\t}\r\n\t/***\r\n\t * 将所有actions包装成一个链式调用的函数\r\n\t */\r\n\tprivate wrapperChainActions() {\r\n\t\tconst self = this;\r\n\t\treturn async function (this: any) {\r\n\t\t\tconst args = Array.from(arguments); // 原始输入的参数\r\n\t\t\tlet preValue: any; // 保存上一个action的返回值\r\n\t\t\t//解析参数, 0-1个参数为options,最后一个参数为command\r\n\t\t\tlet actionOpts: Record<string, any> = {},\r\n\t\t\t\tactionArgs: any[] = [],\r\n\t\t\t\tcmd: any;\r\n\t\t\tif (args.length >= 2) {\r\n\t\t\t\tcmd = args[args.length - 1]; // 最后一个command\r\n\t\t\t\tactionOpts = args[args.length - 2];\r\n\t\t\t\tactionArgs = args.slice(0, args.length - 2);\r\n\t\t\t}\r\n\t\t\tawait self.executeBeforeHooks({ args: actionArgs, options: actionOpts, command: cmd });\r\n\t\t\ttry {\r\n\t\t\t\tfor (let action of self._actions) {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tif (action.enhance) {\r\n\t\t\t\t\t\t\t// 增强模式\r\n\t\t\t\t\t\t\toutputDebug(\"执行<{}>: args={}, options={}\", () => [\r\n\t\t\t\t\t\t\t\tself.name(),\r\n\t\t\t\t\t\t\t\tactionArgs,\r\n\t\t\t\t\t\t\t\tactionOpts,\r\n\t\t\t\t\t\t\t]);\r\n\t\t\t\t\t\t\tpreValue = await action.fn.call(this, {\r\n\t\t\t\t\t\t\t\tcommand: cmd,\r\n\t\t\t\t\t\t\t\tvalue: preValue,\r\n\t\t\t\t\t\t\t\targs: actionArgs,\r\n\t\t\t\t\t\t\t\toptions: actionOpts,\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t// 原始模式\r\n\t\t\t\t\t\t\tpreValue = await action.fn.apply(this, args);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (preValue === BREAK) break;\r\n\t\t\t\t\t} catch (e) {\r\n\t\t\t\t\t\toutputDebug(\"命令{}的Action({})执行出错:{}\", [self.name, action.id, e]);\r\n\t\t\t\t\t\tthrow e;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} finally {\r\n\t\t\t\tawait self.executeAfterHooks({\r\n\t\t\t\t\tvalue: preValue,\r\n\t\t\t\t\targs: actionArgs,\r\n\t\t\t\t\toptions: actionOpts,\r\n\t\t\t\t\tcommand: cmd,\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\t/**\r\n\t * 当传入--work-dirs时用来处理工作目录\r\n\t */\r\n\tprivate wrapperWorkDirsAction(fn: AsyncFunction) {\r\n\t\tconst self = this;\r\n\t\treturn async function (this: any) {\r\n\t\t\tlet workDirs = self._optionValues.workDirs;\r\n\t\t\t// 未指定工作目录参数\r\n\t\t\tif (!workDirs) {\r\n\t\t\t\treturn await fn.apply(this, Array.from(arguments));\r\n\t\t\t}\r\n\t\t\tif (!Array.isArray(workDirs)) workDirs = workDirs.split(\",\");\r\n\t\t\tworkDirs = workDirs.reduce((dirs: any[], dir: string) => {\r\n\t\t\t\tif (typeof dir == \"string\") dirs.push(...dir.split(\",\"));\r\n\t\t\t\treturn dirs;\r\n\t\t\t}, []);\r\n\t\t\tfor (let workDir of workDirs) {\r\n\t\t\t\tconst cwd = process.cwd();\r\n\t\t\t\ttry {\r\n\t\t\t\t\tif (!path.isAbsolute(workDir)) workDir = path.join(cwd, workDir);\r\n\t\t\t\t\tif (fs.existsSync(workDir) && fs.statSync(workDir).isDirectory()) {\r\n\t\t\t\t\t\toutputDebug(\"切换到工作目录:{}\", workDir);\r\n\t\t\t\t\t\tprocess.chdir(workDir); // 切换\r\n\t\t\t\t\t\tawait fn.apply(this, Array.from(arguments));\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\toutputDebug(\"无效的工作目录:{}\", workDir);\r\n\t\t\t\t\t}\r\n\t\t\t\t} catch (e) {\r\n\t\t\t\t\tthrow e;\r\n\t\t\t\t} finally {\r\n\t\t\t\t\tprocess.chdir(cwd);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\tgetOption(name: string): MixOption {\r\n\t\treturn this.options.find((option) => option.name() == name) as unknown as MixOption;\r\n\t}\r\n\t/**\r\n\t * 添加一个Before钩子\r\n\t * @param listener\r\n\t * @param scope =false时代表只在本命令执行,=true时代表在本命令及其子命令执行\r\n\t * @returns\r\n\t */\r\n\tbefore(listener: BeforeCommandHookListener, scope: boolean = true) {\r\n\t\tthis._beforeHooks.push([listener, scope]);\r\n\t\treturn this;\r\n\t}\r\n\tprivate async executeBeforeHooks(args: any) {\r\n\t\tconst hooks: [BeforeCommandHookListener, boolean, MixCommand][] = this.beforeHooks.map(\r\n\t\t\t([hook, scope]) => [hook, scope, this]\r\n\t\t);\r\n\t\tthis.getAncestorCommands().forEach((cmd: MixCommand) => {\r\n\t\t\thooks.unshift(\r\n\t\t\t\t...cmd.beforeHooks.map(([hook, scope]) => {\r\n\t\t\t\t\treturn [hook, scope, cmd] as [BeforeCommandHookListener, boolean, MixCommand];\r\n\t\t\t\t})\r\n\t\t\t);\r\n\t\t});\r\n\t\tfor (let [hook, scope, cmd] of hooks) {\r\n\t\t\tif (!scope) continue;\r\n\t\t\tawait hook.call(cmd, args);\r\n\t\t}\r\n\t}\r\n\t/**\r\n\t * 添加一个After钩子\r\n\t * @param listener\r\n\t * @param scope =false时代表只在本命令执行,=true时代表在本命令及其子命令执行\r\n\t * @returns\r\n\t */\r\n\tafter(listener: AfterCommandHookListener, scope: boolean = true) {\r\n\t\tthis._afterHooks.push([listener, scope]);\r\n\t\treturn this;\r\n\t}\r\n\tprivate async executeAfterHooks(args: any) {\r\n\t\tconst hooks: [AfterCommandHookListener, boolean, MixCommand][] = this.afterHooks.map(\r\n\t\t\t([hook, scope]) => [hook, scope, this]\r\n\t\t);\r\n\t\tthis.getAncestorCommands().forEach((cmd: MixCommand) => {\r\n\t\t\thooks.push(\r\n\t\t\t\t...cmd.afterHooks.map(([hook, scope]) => {\r\n\t\t\t\t\treturn [hook, scope, cmd] as [BeforeCommandHookListener, boolean, MixCommand];\r\n\t\t\t\t})\r\n\t\t\t);\r\n\t\t});\r\n\t\tfor (let [hook, scope, cmd] of hooks) {\r\n\t\t\tif (!scope) continue; //=false时不执行\r\n\t\t\tawait hook.call(cmd, args);\r\n\t\t}\r\n\t}\r\n\tprivate async preActionHook(thisCommand: Command, actionCommand: Command) {\r\n\t\tif (this.isEnablePrompts()) {\r\n\t\t\t// 自动生成提示\r\n\t\t\tconst questions: PromptObject[] = [\r\n\t\t\t\t...this.generateAutoPrompts(),\r\n\t\t\t\t...this._customPrompts,\r\n\t\t\t];\r\n\t\t\t// 用户提示\r\n\t\t\tif (questions.length > 0) {\r\n\t\t\t\tconst results = await prompts(questions);\r\n\t\t\t\tObject.entries(results).forEach(([key, value]) => {\r\n\t\t\t\t\tthisCommand.setOptionValue(key, value);\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate isEnablePrompts() {\r\n\t\tif (isEnablePrompts() === false) {\r\n\t\t\t// 命令行参数禁用了提示,优先级最高\r\n\t\t\treturn false;\r\n\t\t} else {\r\n\t\t\treturn this._enable_prompts;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * 生成选项自动提示\r\n\t *\r\n\t * @remarks\r\n\t * FlexCli要求所有未提供默认值的Option自动生成提示\r\n\t *\r\n\t * - 未提供默认值,并且是必选的参数Option\r\n\t * - 指定了choices但未提供有效值的Option\r\n\t *\r\n\t */\r\n\tprivate generateAutoPrompts(): PromptObject[] {\r\n\t\tconst options = this.options as unknown as MixOption[];\r\n\t\tconst optionPromports = options\r\n\t\t\t.filter((option) => !option.hidden && option instanceof MixOption)\r\n\t\t\t.map((option) => option.getPrompt(this._optionValues[option.name()]))\r\n\t\t\t.filter((prompt) => prompt) as PromptObject[];\r\n\t\toutputDebug(\"命令<{}>自动生成{}个选项提示:{}\", [\r\n\t\t\tthis.name(),\r\n\t\t\toptionPromports.length,\r\n\t\t\toptionPromports.map((prompt) => `${prompt.name}(${prompt.type})`).join(\",\"),\r\n\t\t]);\r\n\t\treturn optionPromports;\r\n\t}\r\n\toption(flags: string, description?: string | undefined, defaultValue?: any): this;\r\n\toption(flags: string, description?: string | undefined, options?: MixedOptionParams): this {\r\n\t\t// @ts-ignore\r\n\t\tconst option = new MixOption(...arguments);\r\n\t\tif (option.required && !this.isEnablePrompts()) option.mandatory = true;\r\n\t\treturn this.addOption(option as unknown as Option);\r\n\t}\r\n\r\n\t/**\r\n\t * 添加提示\r\n\t *\r\n\t * @remarks\r\n\t *\r\n\t * 添加一些自定义提示\r\n\t *\r\n\t *\r\n\t * @param questions\r\n\t * @param show 是否显示提示信息,auto表示只有在用户没有提供option的值时才显示提示信息,always表示总是显示提示信息,never表示不显示提示信息\r\n\t * @returns\r\n\t */\r\n\tprompt(questions: PromptObject | PromptObject[]) {\r\n\t\tthis._customPrompts.push(...(Array.isArray(questions) ? questions : [questions]));\r\n\t\treturn this;\r\n\t}\r\n\t/**\r\n\t *\r\n\t * 选择命令并执行\r\n\t *\r\n\t * @remorks\r\n\t *\r\n\t * 当命令具有多个子命令时,并且没有提供默认子命令时,提示用户选择一个子命令\r\n\t *\r\n\t */\r\n\tasync selectCommands() {\r\n\t\tconst choices = this.commands.map((command) => ({\r\n\t\t\ttitle: `${command.description()}(${command.name()})`,\r\n\t\t\tvalue: command.name(),\r\n\t\t}));\r\n\t\tconst result = await prompts({\r\n\t\t\ttype: \"select\",\r\n\t\t\tname: \"command\",\r\n\t\t\tmessage: \"请选择命令:\",\r\n\t\t\tchoices,\r\n\t\t});\r\n\t\t// 重新解析命令行参数标志,\r\n\t\tconst command = this.commands.find((command) => command.name() === result.command);\r\n\t\tawait command?.parseAsync([result.command], { from: \"user\" });\r\n\t}\r\n\t/**\r\n\t * 禁用/启用所有提示\r\n\t */\r\n\tdisablePrompts() {\r\n\t\tthis._enable_prompts = false;\r\n\t\treturn this;\r\n\t}\r\n\tenablePrompts() {\r\n\t\tthis._enable_prompts = true;\r\n\t\treturn this;\r\n\t}\r\n}\r\n","import { Option } from 'commander'\nimport { PromptObject } from 'prompts'\nimport { IPromptable, IPromptableOptions, PromptChoice, PromptManager } from './prompt'\n\n\nexport interface MixedOptionParams extends IPromptableOptions{\n hidden?:boolean\n defaultDescription?:string // 默认值的描述 \n conflicts?:string | string[]\n env?:string\n argParser?:<T>(value: string, previous: T) => T \n hideHelp?:boolean\n mandatory?: boolean \n implies?:{[key:string]:any} \n}\n\n\nexport class MixOption extends Option implements IPromptable{\n // 是否提示用户输入\n prompt?: PromptManager \n promptChoices?:PromptChoice[]\n private _validate?: (value: any) => boolean \n constructor(flags: string, description?: string | undefined,optsOrDefault?:any) {\n super(flags, description)\n let params:MixedOptionParams = {}\n if(arguments.length==3 && typeof arguments[2] == \"object\"){\n params = Object.assign({ },arguments[2]) \n }else if(arguments.length==3){\n params.default = arguments[2]\n }\n if(params.prompt===undefined) params.prompt = 'auto'\n if(params.default) this.default(params.default,params.defaultDescription)\n if(params.choices) this.choices(params.choices)\n if(params.conflicts) this.conflicts(params.conflicts)\n if(params.env) this.env(params.env)\n if(params.argParser) this.argParser(params.argParser)\n if(params.hideHelp) this.hideHelp(params.hideHelp)\n if(params.hidden) this.hidden = params.hidden\n if(params.mandatory) this.makeOptionMandatory(params.mandatory)\n if(params.implies) this.implies(params.implies) \n if(params.optional) this.optional=params.optional\n if(typeof(params.validate)=='function') this._validate = params.validate.bind(this)\n if(params.required) {\n this.required = params.required\n if(!this._validate ) this._validate = (value:any)=>String(value).length>0\n }\n this.prompt = new PromptManager(this as IPromptable,params.prompt)\n } \n validate(value: any): boolean {\n if(typeof(this._validate)=='function'){\n return this._validate(value)\n }else{\n return true\n }\n }\n // @ts-ignore\n choices(values:(PromptChoice | string)[]){\n if(!this.promptChoices){\n this.promptChoices = values.map(choice=>{\n if(typeof(choice)=='object'){\n return choice\n }else{\n return {title:choice,value:choice} \n }\n })\n } \n super.choices(this.promptChoices.map((item:any)=>item.value)) \n } \n\n private resetChoices(){\n super.choices(this.promptChoices!.map((item:any)=>item.value)) \n }\n\n addChoice(value:PromptChoice | string){\n if(!this.promptChoices || !Array.isArray(this.promptChoices)) this.promptChoices = []\n this.promptChoices!.push(typeof(value)=='string' ? {title:value,value} : value)\n this.resetChoices()\n }\n removeChoice(value:any){\n this.promptChoices =this.promptChoices?.filter(choice=>choice.value!==value)\n this.resetChoices()\n }\n clearChoice(){\n this.promptChoices = []\n this.resetChoices()\n }\n\n \n /**\n * 返回选项的提示对象\n * \n * @remarks\n * \n *\n * \n * @param inputValue \n * @returns \n */\n getPrompt(inputValue?:any): PromptObject | undefined {\n return this.prompt?.get(inputValue)\n } \n}","import artTemplate from \"art-template\"\r\nimport fs from \"fs-extra\"\r\nimport path from \"node:path\"\r\nimport { promisify } from \"flex-tools/func/promisify\"\r\nimport logsets from \"logsets\" \r\n/**\r\n * \r\n * 在控制台输出一个字符串\r\n * 本方法会将字符串中的每一行空格去掉\r\n * \r\n * @remarks\r\n * \r\n * outputStr(String.raw`\r\n * a\r\n * b`)\r\n * \r\n * 会输出\r\n * a\r\n * b\r\n *\r\n * 此功能可以用于输出多行字符串时,保持代码的缩进格式,而不会影响输出结果\r\n * \r\n * @param str : 要输出的字符串\r\n * @param vars : 用于替换字符串中的变量\r\n * \r\n */\r\nexport function outputStr(str:string,vars?:Record<string,any> | any[]){ \r\n logsets.log(fixIndent(str),vars)\r\n}\r\n\r\n/**\r\n * 修正多行字符串的缩进\r\n * \r\n * @param text \r\n * @param indent \r\n * @returns \r\n */\r\nexport function fixIndent(text:string,indent?:boolean | number):string{\r\n let indentValue = (indent==undefined || indent===true) ? 0 : (typeof(indent)=='number' ? indent : -1)\r\n if(indentValue==-1) return text // 不修正缩进\r\n let lines:string[] = text.split(\"\\n\")\r\n let minSpaceCount = lines.reduce<number>((minCount,line,index)=>{\r\n if(index==0) return minCount\r\n const spaceCount = line.match(/^\\s*/)?.[0].length || 0\r\n return Math.min(minCount,spaceCount)\r\n },9999)\r\n lines = lines.map(line=>line.substring(minSpaceCount))\r\n return lines.join(\"\\n\")\r\n}\r\n\r\n/**\r\n * 增加内置选项\r\n * @param command \r\n */\r\nexport function addBuiltInOptions(command:any){ \r\n command.option(\"--work-dirs <values...>\",\"指定工作目录\",{hidden:true,optional:true,required:true,prompt:false})\r\n command.option(\"--disable-prompts\",\"禁用所有交互提示\",{hidden:true,prompt:false}) \r\n command.option(\"--debug-cli\",\"显示调试信息\",{hidden:true,prompt:false})\r\n}\r\n\r\n\r\n/**\r\n * 是否命令行中包含了--debug-cli选项\r\n */\r\nexport function isDebug(){\r\n return process.argv.includes(\"--debug-cli\")\r\n}\r\nexport function isEnablePrompts(){ \r\n return !process.argv.includes(\"--disable-prompts\")\r\n}\r\n\r\n/**\r\n * 打印调试信息\r\n * @param message \r\n * @param args \r\n */\r\nexport function outputDebug(message:string,...args:any[]){ \r\n let vars = (args.length == 1 && typeof(args[0])=='function') ? args[0]() : args\r\n if(isDebug()) logsets.log(`[MixCli] ${message}`,...vars)\r\n}\r\n\r\nexport const fileExists = promisify(fs.exists,{\r\n parseCallback:(results)=>{\r\n return results[0]\r\n }\r\n})\r\nexport const readFile = promisify(fs.readFile)\r\nexport const writeFile = promisify(fs.writeFile)\r\nexport const mkdir = promisify(fs.mkdir)\r\n\r\n/**\r\n * 基于artTemplate模板生成文件\r\n * \r\n * @param {*} tmplFile \r\n * @param {*} vars \r\n */\r\nexport async function createFileByTemplate(targetFile:string,tmplFile:string,vars:Record<string,any>={}){\r\n tmplFile=path.isAbsolute(tmplFile)? tmplFile : path.join(process.cwd(),tmplFile)\r\n if(!fs.existsSync(tmplFile)){\r\n throw new Error(\"模板文件不存在:\"+tmplFile)\r\n }\r\n targetFile=path.isAbsolute(targetFile)? targetFile : path.join(process.cwd(),targetFile)\r\n const outPath = path.dirname(targetFile)\r\n if(!await fileExists(outPath)){\r\n await mkdir(outPath,{recursive:true})\r\n } \r\n const template = artTemplate(tmplFile,await readFile(tmplFile,{encoding:\"utf-8\"})); \r\n await writeFile(targetFile,template(vars),{encoding:\"utf-8\"})\r\n return targetFile\r\n}\r\n\r\n/** \r\n * 创建目录 \r\n * \r\n * \r\n * \r\n * @param {String[]} dirs 要创建的目录列表,类型为字符串数组 \r\n * @param callback 创建目录过程中的回调函数,类型为异步函数,接收一个参数 dir,表示当前正在创建的目录 \r\n * @returns 该函数返回一个 Promise 对象,表示创建目录的操作是否完成 \r\n */\r\nexport async function mkDirs(dirs:string[],{callback,base}:{callback?:Function,base?:string}){\r\n if(!Array.isArray(dirs)) throw new Error(\"dirs参数必须为字符串数组\")\r\n for(let dir of dirs){\r\n if(!path.isAbsolute(dir)) dir = path.join(base || process.cwd(),dir)\r\n if(typeof(callback)=='function') callback(dir)\r\n await mkdir(dir,{recursive:true})\r\n }\r\n}\r\n\r\nexport function showError(e:any){\r\n if(isDebug()){\r\n outputDebug(\"导入命令<>出错:{}\",e.stack)\r\n }else{\r\n console.error(e)\r\n } \r\n\r\n}\r\n\r\n\r\nexport function getId(){\r\n return Math.random().toString(36).substr(2)\r\n}\r\n\r\n\r\nexport async function importModule(file:string){\r\n let module \r\n try{\r\n module = require(file)\r\n }catch(e:any){\r\n try{\r\n const cmd = await import(`file://${file}`)\r\n module = cmd.default\r\n }catch(e:any){\r\n throw e\r\n } \r\n }\r\n return module\r\n}\r\n","import { PromptObject } from \"prompts\" \nimport { outputDebug } from \"./utils\"\n \n\nexport type PromptType = \"text\" | \"password\" | \"invisible\" | \"number\"| \"confirm\"| \"list\"| \"toggle\"| \"select\" | \"multiselect\" | \"autocomplete\" | \"date\" | \"autocompleteMultiselect\"\n\nexport type PromptParam = 'auto' | boolean | PromptType | PromptObject\nexport type InputPromptParam = PromptParam | ((value:any)=>PromptParam) | boolean\nexport type PromptParamDefaultValue = string | boolean | string[] \n\nexport const promptTypeMap:Record<string,string> = {\n boolean:\"confirm\",\n string:\"text\",\n number:\"number\", \n array:\"list\", \n} \n\nexport const supportedPromptTypes = [\"text\",\"password\",\"invisible\", \"number\", \"confirm\" , \"list\", \"toggle\" , \"select\" , \"multiselect\" , \"autocomplete\" , \"date\" , \"autocompleteMultiselect\"]\nexport interface PromptChoice {\n title: string;\n value?: any;\n disabled?: boolean | undefined;\n selected?: boolean | undefined;\n description?: string | undefined;\n}\n\n\n\nexport interface IPromptableOptions{\n required?: boolean; // A value must be supplied when the option is specified.\n optional?: boolean; // A value is optional when the option is specified.\n default?:PromptParamDefaultValue\n choices?:(PromptChoice | any)[] // 选项值的可选值\n prompt?:InputPromptParam\n validate?:(value: any) => boolean\n}\n\n\nexport interface IPromptable{\n name():string \n description?:string\n flags:string\n promptChoices?:PromptChoice[]\n argChoices?:string[]\n variadic?:boolean\n defaultValue?:PromptParamDefaultValue\n input?:any \n required?:boolean\n validate?: (value: any) => boolean \n getPrompt(inputValue?:any):PromptObject | undefined \n}\n\n/**\n * 供command.option()使用的参数对象\n */\nexport interface PromptableObject{\n \n\n}\n\n\n/**\n * 负责生成prompt对象\n * \n */\nexport class PromptManager{\n args:InputPromptParam \n private _promptable:IPromptable // 对应的FlexOption或FlexArgument\n constructor(promptable:IPromptable,promptArgs?:InputPromptParam){ \n this._promptable = promptable\n this.args= promptArgs===undefined ? 'auto' : promptArgs\n }\n\n /**\n * 返回输入的是否是有效的prompt类型\n * @param type \n * @returns \n */\n isValid(type:any){\n return supportedPromptTypes.includes(String(type))\n }\n /**\n * 推断是否需要提示\n * \n */\n isNeed(input:any,defaultValue?:any){\n \n const promptArg = this.args\n const inputValue = input || defaultValue\n // 是否有输入值,即在命令行输入了值\n const hasInput = !(inputValue === undefined)\n // 1. 显式指定了_prompt为true,则需要提示,后续进行提示类型的推断,可能不会准确\n if(promptArg===true) return true\n if(promptArg===false) return false \n\n // 2. 提供了一个prompt对象,并且没有在命令行输入值,则需要提示\n if(typeof(promptArg)=='object'){\n return !hasInput\n }\n\n // 3. 指定了内置的prompt类型,如prompt='password',则使用password类型提示输入\n if(typeof(promptArg) == 'string' && supportedPromptTypes.includes(promptArg)){\n return !hasInput\n }\n \n // 4. 判断输入是否有效,则显示提示\n if(this._promptable.argChoices && this._promptable.argChoices.indexOf(inputValue) == -1){\n return true\n } \n return !hasInput\n }\n /**\n * 返回生成prompt对象\n * \n * @param inputValue 从命令行输入的值\n */\n get(inputValue?:any){\n const {description,promptChoices,validate,defaultValue} = this._promptable\n let input = inputValue || defaultValue\n // 判断是否需要输入提示\n if(!this.isNeed(input,defaultValue)) return\n // 推断prompt类型\n let promptType = this.infer(inputValue)\n const prompt = {\n type:promptType, \n name:this._promptable.name(),\n message:description,\n initial: input,\n ...typeof(this.args) == 'object' ? this.args : {}\n } as PromptObject\n // 指定了验证函数,用来验证输入值是否有效\n prompt.validate = validate?.bind(this._promptable)\n if(promptType=='multiselect') prompt.instructions=false\n if(['select','multiselect'].includes(promptType)){\n let index = promptChoices?.findIndex(item=>item.value==input)\n prompt.initial = index==-1 ? undefined : index\n } \n // 选项值的可选值\n if(Array.isArray(promptChoices)) {\n prompt.choices =promptChoices\n }\n return prompt\n }\n /**\n * 推断prompt类型\n * \n * @param inputValue 从命令行输入的值\n */\n infer(inputValue?:any){\n const {argChoices,variadic,defaultValue} = this._promptable\n let input = inputValue || defaultValue\n // 如果选择指定了\"-p [value]或[value...]\",则使用text类型,如果没有要求输入值,则使用confirm类型\n let promptType = /(\\<[\\w\\.]+\\>)|(\\[[\\w\\.]+\\])/.test(this._promptable.flags) ? 'text' : 'confirm'\n let promptArg = this.args\n if(this.isValid(promptArg)){ // 显式指定了prompt类型\n promptType = promptArg as string\n }else{ // 未显式指定prompt类型,需要按一定规则推断类型\n if(typeof(promptArg)=='object'){\n promptType = promptArg.type as string\n }else{\n if(argChoices){ // 提供多个可选值时\n promptType = variadic ? 'multiselect' : 'select'\n }else{\n const datatype:string = Array.isArray(defaultValue) ? 'array' : typeof(defaultValue) \n // 如果输入值班是数组,则使用list类型,允许使用逗号分隔的多个值\n if(Array.isArray(input) || variadic){\n promptType = \"list\"\n }else{\n if(datatype in promptTypeMap){\n promptType = promptTypeMap[datatype]\n }\n }\n }\n }\n }\n outputDebug(\"选项<{}> -> 提示类型<{}>\",[this._promptable.name(),promptType])\n return promptType\n }\n\n}","import { getPackageJson } from \"flex-tools/package/getPackageJson\"\r\nimport { getPackageRootPath } from 'flex-tools/package/getPackageRootPath';\r\nimport type { MixCli } from './cli';\r\nimport { globSync } from 'glob'\r\nimport { MixCliCommand } from './cli';\r\nimport { importModule, isDebug, outputDebug } from './utils';\r\nimport fs from \"node:fs\"\r\nimport path from \"node:path\"\r\n\r\n\r\n/**\r\n * \r\n * 在当前工程中查找符合FlexCli.prefix约定的命令 \r\n * \r\n * - 读取当前包的package.json\r\n * - 找出所有以cli.prefix开头的依赖\r\n * - 加载这些依赖的目录下的匹配cli.pattern的命令\r\n * - 加载加载这样命令\r\n * \r\n */\r\n \r\n\r\nexport function getMatchedDependencies(this:MixCli,entry:string):string[]{\r\n const pacakgeMacher = this.options.include\r\n if(!(pacakgeMacher instanceof RegExp)) return []\r\n \r\n // 找出当前包的所有依赖\r\n const { dependencies={},devDependencies={},peerDependencies={},optionalDependencies={},bundleDependencies={} } = getPackageJson(entry)\r\n const packageNames = [\r\n ...Object.keys(dependencies),\r\n ...Object.keys(devDependencies),\r\n ...Object.keys(peerDependencies),\r\n ...Object.keys(optionalDependencies),\r\n ...Object.keys(bundleDependencies)\r\n ]\r\n return packageNames.filter(name=>name!==\"@voerka/cli\" && pacakgeMacher.test(name))\r\n}\r\n\r\nfunction isMatched(str:string,reg?:string | RegExp | string[] | RegExp[]):boolean{\r\n // let regexps:RegExp[]=[]\r\n const regexps = reg ? (Array.isArray(reg) ? reg : [reg]) : []\r\n return regexps.some(regexp=>{\r\n if(typeof regexp === \"string\"){\r\n return (new RegExp(regexp)).test(str)\r\n }else if(regexp instanceof RegExp){\r\n return regexp.test(str)\r\n }else{\r\n return false\r\n }\r\n })\r\n}\r\n\r\nexport function findCliPaths(this:MixCli,packageName?:string ,entry?:string):string[]{\r\n const includeMacher = this.options.include\r\n const excludeMacher = this.options.exclude\r\n if(!includeMacher) return []\r\n const packageRoot = getPackageRootPath(entry || process.cwd())\r\n const packagePath = packageName ? path.dirname(require.resolve(packageName,{paths:[packageRoot as string]})) : packageRoot\r\n\r\n if(!packagePath) {\r\n outputDebug(\"MixCli只能运行在Nodejs环境\" )\r\n return []\r\n }\r\n\r\n // 找出当前包的所有依赖\r\n const packageNames = getMatchedDependencies.call(this,packagePath)\r\n\r\n const cliDirs:string[]=[]\r\n \r\n if(entry!==undefined) cliDirs.push(path.join(packagePath,this.options.cliDir))\r\n packageNames.filter(name=>{\r\n return isMatched(name,includeMacher) && !isMatched(name,excludeMacher) \r\n })\r\n .forEach(name=>{\r\n outputDebug(\"匹配包:{}\",`${packageName ? name+\" <- \"+packageName : name}`)\r\n try{\r\n const packageEntry = path.dirname(require.resolve(name,{paths:packagePath ? [packagePath] : [process.cwd()]}))\r\n const packageCliDir =path.join(packageEntry,this.options.cliDir!) \r\n // 查找当前包的所属工程的依赖\r\n let dependencies = getMatchedDependencies.call(this,packageEntry)\r\n cliDirs.push(...dependencies.reduce<string[]>((result,dependencie)=>{\r\n outputDebug(\"匹配包:{}\",`${dependencie} <- ${name}`)\r\n result.push(...findCliPaths.call(this,dependencie,packageEntry))\r\n return result\r\n },[])) \r\n if(fs.existsSync(packageCliDir)){\r\n cliDirs.push(packageCliDir)\r\n }\r\n }catch(e:any){\r\n outputDebug(\"解析包<{}>路径出错:{}\",[name,e.stack])\r\n } \r\n })\r\n // 由于一些包可能存在循环依赖,所以需要去重\r\n return [...new Set(cliDirs)]\r\n}\r\n\r\n\r\n/**\r\n * \r\n * 扫描当前工程中所有符合条件的命令\r\n * \r\n * @param cli \r\n * \r\n */\r\nexport async function findCommands(cli:MixCli){ \r\n const cliDirs = findCliPaths.call(cli)\r\n const commands:MixCliCommand[] = []\r\n const files = [] as string[]\r\n cliDirs.forEach(dir=>{\r\n globSync(\"*\",{\r\n cwd:dir,\r\n absolute :true \r\n }).forEach((file:string)=>{ \r\n const baseName = path.basename(file) \r\n if(baseName.startsWith(\"_\")) return\r\n const ext = path.extname(file).toLowerCase()\r\n if([\".js\",\".cjs\",\".mjs\"].includes(ext)){\r\n files.push(file)\r\n }else if(fs.statSync(file).isDirectory()){\r\n files.push(path.join(file,\"index.js\"))\r\n files.push(path.join(file,\"index.cjs\"))\r\n files.push(path.join(file,\"index.mjs\"))\r\n }\r\n })\r\n })\r\n for(let file of files){ \r\n if(!fs.existsSync(file)) continue\r\n try{\r\n outputDebug(\"导入命令:{}\",file)\r\n if(file.endsWith(\".cjs\") || file.endsWith(\".js\")){\r\n commands.push(await importModule(file))\r\n }else if(file.endsWith(\".mjs\")){\r\n const cmd = await import(`file://${file}`)\r\n commands.push(cmd.default)\r\n } \r\n }catch(e:any){\r\n outputDebug(e) \r\n }\r\n }\r\n return commands\r\n}\r\n\r\n"],"mappings":"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","names":["import_logsets","import_commander","logsets","fs","path","artTemplate","module","e","import_node_path","path","fs","prompts","command","import_node_fs","import_node_path","path","fs","replaceAll","logsets","cmd"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/cli.ts","../src/command.ts","../src/option.ts","../src/utils.ts","../src/prompt.ts","../src/finder.ts"],"sourcesContent":["export * from \"./cli\"\r\nexport * from \"./utils\"\r\nexport * from \"./command\"\r\nexport * from \"./option\"","#!/usr/bin/env node\nimport \"flex-tools/string\"\nimport { LiteEvent, LiteEventSubscriber } from \"flex-tools/events/liteEvent\"\nimport { Command } from \"commander\"\nimport logsets from \"logsets\"\n\nimport { assignObject } from \"flex-tools/object/assignObject\"\nimport { MixCommand } from \"./command\"\nimport { addBuiltInOptions, fixIndent, outputDebug } from './utils';\nimport { findCommands } from \"./finder\"\nimport { asyncSignal } from \"flex-tools/async/asyncSignal\"\n// @ts-ignore\nimport replaceAll from 'string.prototype.replaceall' \nreplaceAll.shim() \n\nexport interface MixCliOptions{\n name:string,\n title?:string | (string | boolean | number)[],\n description?:string,\n version?:string\n // 定义显示帮助信息\n logo?:string ,\n // 在根命令执行前执行==commander的preAction\n before?:(thisCommand:Command,actionCommand:Command)=>void,\n // 在根命令执行后执行==commander的postAction\n after?:(thisCommand:Command,actionCommand:Command)=>void, \n // flexcli运行时会在当前工程的package.json的依赖中查找以prefix/开头的包,然后自动加载其cli目录下的命令\n // 例如:prefix=myapp,则会自动加载flex-cli-xxx包中的cli目录下的命令\n // 如prefix=myapp, cliPath=\"cmds\",则会自动加载flex-cli-xxx包中的cmds目录下的命令\n include?:string | RegExp | string[] | RegExp[],\n // 忽略查找正则表达式\n exclude?:string | RegExp | string[] | RegExp[],\n // flexcli会在当前工程的以prefix/开头下查找命令声明\n // / pattern默认值是cli,即会在当前工程的以prefix/开头的包下查找cli目录下的命令\n // 指定cli所在的目录,默认值是cli,要遍历该目录下的所有js文件作为命令导出\n cliDir?:string \n context?:Record<string,any> // 传递给命令的共享上下文,所有命令均可要使用 \n // 默认是否启用交互提示, auto当没有值时,会根据当前是否在终端中运行来决定是否启用交互提示\n // 为false时,禁用所有交互提示,为true时,启用所有交互提示 \n prompt?:'auto' | boolean \n ignoreError?:boolean\n}\n\n \n \n\nexport type MixCliCommand = (cli:MixCli)=>MixCommand | MixCommand[] | void\n\n\nexport type MixCliEvents = \n \"register\" // 当命令注册时触发\n\nexport class MixCli extends LiteEvent<any,MixCliEvents>{\n options:Required<MixCliOptions> \n root!:Command \n private findSignals:any[]=[]\n constructor(options?:MixCliOptions){\n super()\n this.options= assignObject({\n name:\"mixcli\",\n package:null,\n cliDir:\"cli\",\n prompt:'auto',\n ignoreError:false\n },options) as Required<MixCliOptions> \n this.createRootCommand() \n } \n get context(){return this.options.context}\n get name(){return this.options.name}\n /**\n * 是否禁用了所有的交互提示\n */\n get isDisabledPrompts(){\n return(this.root as any).rawArgs.includes(\"--no-prompts\") \n } \n /**\n * 扫描当前工程的依赖,加载匹配include的依赖下的命令\n */\n private async installCommands(){\n const cmders = await findCommands(this)\n for(let cmder of cmders){\n try{\n if(typeof(cmder)===\"function\"){\n let cmds = cmder(this)\n cmds = cmds ? (Array.isArray(cmds) ? cmds : [cmds]) : []\n this.register(()=>cmds) \n }\n }catch(e:any){\n outputDebug(\"注册命令失败:{}\",e.stack)\n }\n }\n } \n /**\n * 创建根命令\n * \n */\n private createRootCommand(){\n this.root = new MixCommand(this.name);\n this.root \n .helpOption('-h, --help')\n .action(()=>{ \n if(this.options.logo) logsets.log(fixIndent(this.options.logo,2))\n console.log()\n // 显示标题\n let title = this.options.title|| this.options.name\n if(Array.isArray(title)){\n logsets.log(String(title[0]).firstUpper(),[...title.slice(1)])\n }else{\n logsets.log(`${title.firstUpper()} Version: {}`,this.options.version)\n } \n // @ts-ignore\n if(this.options.description) logsets.log(logsets.colors.darkGray(this.options.description)) \n console.log()\n this.root.help() \n }) \n addBuiltInOptions(this.root)\n if(this.options.before) this.root.hook('preAction',this.options.before)\n if(this.options.after) this.root.hook('postAction',this.options.after) \n } \n /**\n * 添加帮助选项\n * \n * @param text 帮助文本\n * @param position 显示位置,可选值:before|after|beforeAll|afterAll\n * @param fixIndent 是否自动修正缩进,如果为true,则会自动修正缩进,当显示多行时文本时,会自动修正缩进\n * \n */\n public addHelp(text:string,{pos='beforeAll',alignIndent=true}:{pos:'before'|'after' | 'beforeAll' | 'afterAll',alignIndent?:boolean | number}){\n if(alignIndent) text = fixIndent(text,alignIndent)\n this.root.addHelpText(pos,text)\n }\n\n /**\n * 注册一个命令\n * @param cmd \n */\n register(cmd:MixCliCommand){\n if(typeof(cmd)==\"function\"){\n let result = cmd(this)\n let cmds = result instanceof Array ? result : (result==undefined ? [] : [result])\n for(let cmd of cmds){\n // 为什么不用cmd instanceof MixCommand来判断是否是一个有效的命令?\n // 因为当不同的包引用了与主包不一样版本的mixcli时,判断会失效,导致不能识别\n // 所以我们通过cmd.__MIX_COMMAND__来判断是否是一个有效的命令\n if(cmd.__MIX_COMMAND__){ \n if(this.hasCommand(cmd.name())){\n logsets.error(`Command <${cmd.name()}> has been registered!`)\n }else{\n outputDebug(\"注册命令:{}\",cmd.fullname)\n this.root.addCommand(cmd) ;\n (cmd as any)._cli = this\n this.emit(\"register\",cmd.fullname,true)\n } \n }else{\n logsets.error(`Command <${cmd.toString()}> is not a valid command!`)\n }\n } \n }else{\n logsets.error(\"Invalid command\")\n } \n }\n\n hasCommand(name:string):boolean{\n return this.root.commands.some(c=>c.name()==name)\n }\n\n /**\n * 根据命令名称查找命令\n * \n * @remarks\n * \n * find(\"dev\")\n * find(\"dev.microservice\") 支持多级命令\n * find(\"abc\",DevCommand) 允许指定从DevCommand下开始查找abc命令\n * \n * @param name \n */\n get(name:string):MixCommand | undefined{\n const names=name.split(\".\")\n let curCmd:Command = this.root\n let resultCmd:MixCommand | undefined\n while(names.length>0){\n const topName = names.shift()\n const r = curCmd.commands.find(c=>c.name()==topName) as MixCommand\n if(r && names.length==0){\n resultCmd = r\n }\n curCmd = r\n } \n return resultCmd \n }\n /**\n * 查找一个命令\n * \n * 如果命令不存在,则等待命令注册后再返回\n * \n * 在多包场景下,如果命令在其他包中注册并且该包中的命令还没注册,则会等待命令注册后再返回\n * \n * @param name \n * @returns \n */\n find(name:string):Promise<MixCommand | undefined>{\n const cmd = this.get(name)\n if(cmd){\n return Promise.resolve(cmd) \n }else{\n const signal = asyncSignal()\n this.findSignals.push(signal)\n return new Promise<MixCommand | undefined>((resolve)=>{\n let listener:LiteEventSubscriber\n listener = this.on(\"register\",(fullname:string)=>{\n if(fullname==`${this.name}.${name}`){\n listener.off()\n signal.resolve()\n this.findSignals = this.findSignals.filter(s=>s!=signal)\n resolve(this.get(name))\n }\n },{objectify:true}) as LiteEventSubscriber\n })\n } \n }\n /**\n * 判断命令是否存在\n * \n * @param name \n * @returns \n */\n exists(name:string):boolean{\n if(name in this.root.commands){\n return true\n }else{\n return this.get(name) != undefined\n }\n } \n \n /**\n * 运行命令行程序\n */\n run(){ \n // 为什么有findSignal这玩意,解决什么问题?\n // 当我们要扩展command时,通过get(\"命令名称\")来获取已经注册的命令的方式有个缺陷\n // 就是如果对命令的注册顺序有严格的要求,比如调用get('dev')时要求dev命令必须已经存在\n // 这对动态包的命令注册扩展开发体验不好\n // 所以引入find(\"命令名称\")来获取命令,该方法可以获取到后注册的命令\n // 其副作用是,在run时,可能find还没有运行到,从而导致在帮助信息里面看不到扩展的信息(实际上是已经生效的)\n // 所以我们在find里面注入一个异步信号来解决此问题\n this.installCommands().then(()=>{\n return Promise.all(this.findSignals.map(signal=>signal(10000))).then(()=>{\n this.root.parseAsync(process.argv); \n })\n }) \n }\n /**\n * 创建一个命令\n * \n * \n */\n create(){\n } \n}\n ","import { Command, Option } from \"commander\";\r\nimport prompts, { PromptObject } from \"prompts\";\r\nimport { MixOption, type MixedOptionParams } from \"./option\";\r\nimport { addBuiltInOptions, isEnablePrompts, outputDebug } from \"./utils\";\r\nimport path from \"node:path\";\r\nimport fs from \"node:fs\";\r\nimport type { AsyncFunction } from \"flex-tools\";\r\n\r\nexport type ICommandHookListener = ({\r\n\targs,\r\n\toptions,\r\n\tcommand,\r\n}: {\r\n\targs: any[];\r\n\toptions: Record<string, any>;\r\n\tcommand: MixCommand;\r\n}) => void | Promise<void>;\r\n\r\nexport type BeforeCommandHookListener = ({\r\n\targs,\r\n\toptions,\r\n\tcommand,\r\n}: {\r\n\targs: any[];\r\n\toptions: Record<string, any>;\r\n\tcommand: MixCommand;\r\n}) => void | Promise<void>;\r\nexport type AfterCommandHookListener = ({\r\n\tvalue,\r\n\targs,\r\n\toptions,\r\n\tcommand,\r\n}: {\r\n\tvalue: any;\r\n\targs: any[];\r\n\toptions: Record<string, any>;\r\n\tcommand: MixCommand;\r\n}) => void | Promise<void>;\r\n\r\nexport interface ActionOptions {\r\n\tid: string;\r\n\tat: \"replace\" | \"before\" | \"after\" | \"preappend\" | \"append\" | number;\r\n\t// 函数签名类型,即采用原始的commander的action函数签名,还是mixcli的action函数签名\r\n\tenhance: boolean;\r\n}\r\n\r\nexport interface ActionRegistry extends Omit<ActionOptions, \"at\"> {\r\n\tfn: Function;\r\n}\r\n\r\n// 原始的Action动作函数\r\nexport type OriginalAction = (...args: any[]) => void | Promise<void>;\r\n// 增强的Action函数签名\r\nexport type EnhanceAction = ({\r\n\targs,\r\n\toptions,\r\n\tvalue,\r\n\tcommand,\r\n}: {\r\n\targs: any[];\r\n\toptions: Record<string, any>;\r\n\tvalue: any;\r\n\tcommand: MixCommand;\r\n}) => void | Promise<any>;\r\n\r\n// 执行action的返回结果\r\nexport const BREAK = Symbol(\"BREAK_ACTION\"); // 中止后续的action执行\r\n\r\nexport class MixCommand extends Command {\r\n\t__MIX_COMMAND__ = true;\r\n\tprivate _beforeHooks: [BeforeCommandHookListener, boolean][] = [];\r\n\tprivate _afterHooks: [AfterCommandHookListener, boolean][] = [];\r\n\tprivate _customPrompts: PromptObject[] = [];\r\n\tprivate _optionValues: Record<string, any> = {}; // 命令行输入的选项值\r\n\tprivate _actions: ActionRegistry[] = []; // 允许多个action\r\n\tprivate _enable_prompts: boolean = true; // 是否启用交互提示\r\n\tconstructor(name?: string) {\r\n\t\tsuper(name);\r\n\t\tconst self = this;\r\n\t\tif (!this.isRoot) addBuiltInOptions(this);\r\n\t\tthis.hook(\"preAction\", async function (this: any) {\r\n\t\t\tself._optionValues = self.getOptionValues(this.hookedCommand);\r\n\t\t\ttry {\r\n\t\t\t\t// @ts-ignore\r\n\t\t\t\tawait self.preActionHook.apply(self, arguments);\r\n\t\t\t} catch {}\r\n\t\t});\r\n\t}\r\n\t/**\r\n\t * 是否是根命令\r\n\t */\r\n\tget isRoot() {\r\n\t\treturn !!!this.parent;\r\n\t}\r\n\tget actions() {\r\n\t\treturn this._actions;\r\n\t}\r\n\tget beforeHooks() {\r\n\t\treturn this._beforeHooks;\r\n\t}\r\n\tget afterHooks() {\r\n\t\treturn this._afterHooks;\r\n\t}\r\n\tget fullname() {\r\n\t\tlet names = [this.name()];\r\n\t\tlet parent = this.parent;\r\n\t\twhile (parent) {\r\n\t\t\tif (parent.name() !== \"root\") {\r\n\t\t\t\tnames.unshift(parent.name());\r\n\t\t\t}\r\n\t\t\tparent = parent.parent;\r\n\t\t}\r\n\t\treturn names.join(\".\");\r\n\t}\r\n\r\n\t/**\r\n\t * 返回根命令\r\n\t */\r\n\troot() {\r\n\t\tlet root: MixCommand | null | undefined = this;\r\n\t\twhile (root && root.parent != null) {\r\n\t\t\troot = root.parent as unknown as MixCommand;\r\n\t\t}\r\n\t\treturn root;\r\n\t}\r\n\taction(fn: EnhanceAction, options: ActionOptions): this;\r\n\taction(fn: OriginalAction): this;\r\n\taction(fn: OriginalAction): this {\r\n\t\tconst actionFunc = arguments[0];\r\n\t\tif (arguments.length == 1 && typeof actionFunc == \"function\") {\r\n\t\t\t// 原始方式\r\n\t\t\tthis._actions.push({\r\n\t\t\t\tid: Math.random().toString(36).substring(2),\r\n\t\t\t\tenhance: false,\r\n\t\t\t\tfn: actionFunc,\r\n\t\t\t});\r\n\t\t} else if (\r\n\t\t\targuments.length == 2 &&\r\n\t\t\ttypeof actionFunc == \"function\" &&\r\n\t\t\ttypeof arguments[1] == \"object\"\r\n\t\t) {\r\n\t\t\t// 增强模式\r\n\t\t\tconst actionFn = arguments[0];\r\n\t\t\tconst actionOpts: ActionOptions = Object.assign({ at: \"append\" }, arguments[1]);\r\n\t\t\tif (actionOpts.at == \"replace\") this._actions = [];\r\n\t\t\tconst actionItem = {\r\n\t\t\t\tid: actionOpts.id || Math.random().toString(36).substring(2),\r\n\t\t\t\tenhance: actionOpts.enhance == undefined ? true : actionOpts.enhance,\r\n\t\t\t\tfn: actionFn,\r\n\t\t\t} as const;\r\n\t\t\tif (typeof actionOpts.at == \"number\") {\r\n\t\t\t\tthis._actions.splice(Number(actionOpts.at), 0, actionItem);\r\n\t\t\t} else if ([\"append\", \"before\"].includes(actionOpts.at)) {\r\n\t\t\t\tthis._actions.push(actionItem);\r\n\t\t\t} else if ([\"preappend\", \"after\"].includes(actionOpts.at)) {\r\n\t\t\t\tthis._actions.splice(0, 0, actionItem);\r\n\t\t\t} else {\r\n\t\t\t\tthis._actions.push(actionItem);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tconsole.log(\"[mixcli] action params error\");\r\n\t\t}\r\n\t\treturn super.action(this.getWrapperedAction());\r\n\t}\r\n\r\n\t/**\r\n\t * 读取命令配置值,包括父命令提供的配置选项\r\n\t * @param command\r\n\t */\r\n\tprivate getOptionValues(command: Command) {\r\n\t\tlet opts = {};\r\n\t\tlet parent: Command | null = command;\r\n\t\twhile (parent) {\r\n\t\t\tObject.assign(opts, (parent as MixCommand)._optionValues);\r\n\t\t\tparent = parent.parent;\r\n\t\t}\r\n\t\treturn opts;\r\n\t}\r\n\t/**\r\n\t * 本函数在运行时子类进行action生成该命令的action\r\n\t */\r\n\tprivate getWrapperedAction() {\r\n\t\treturn this.wrapperWorkDirsAction(this.wrapperChainActions());\r\n\t}\r\n\r\n\t/**\r\n\t * 向上查找所有祖先命令\r\n\t */\r\n\tprivate getAncestorCommands(): MixCommand[] {\r\n\t\tlet cmds: MixCommand[] = [];\r\n\t\tlet cmd: MixCommand | null = this;\r\n\t\twhile (cmd) {\r\n\t\t\tcmd = cmd.parent as MixCommand;\r\n\t\t\tif (cmd) {\r\n\t\t\t\tcmds.push(cmd);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn cmds;\r\n\t}\r\n\t/***\r\n\t * 将所有actions包装成一个链式调用的函数\r\n\t */\r\n\tprivate wrapperChainActions() {\r\n\t\tconst self = this;\r\n\t\treturn async function (this: any) {\r\n\t\t\tconst args = Array.from(arguments); // 原始输入的参数\r\n\t\t\tlet preValue: any; // 保存上一个action的返回值\r\n\t\t\t//解析参数, 0-1个参数为options,最后一个参数为command\r\n\t\t\tlet actionOpts: Record<string, any> = {},\r\n\t\t\t\tactionArgs: any[] = [],\r\n\t\t\t\tcmd: any;\r\n\t\t\tif (args.length >= 2) {\r\n\t\t\t\tcmd = args[args.length - 1]; // 最后一个command\r\n\t\t\t\tactionOpts = args[args.length - 2];\r\n\t\t\t\tactionArgs = args.slice(0, args.length - 2);\r\n\t\t\t}\r\n\t\t\tawait self.executeBeforeHooks({ args: actionArgs, options: actionOpts, command: cmd });\r\n\t\t\ttry {\r\n\t\t\t\tfor (let action of self._actions) {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tif (action.enhance) {\r\n\t\t\t\t\t\t\t// 增强模式\r\n\t\t\t\t\t\t\toutputDebug(\"执行<{}>: args={}, options={}\", () => [\r\n\t\t\t\t\t\t\t\tself.name(),\r\n\t\t\t\t\t\t\t\tactionArgs,\r\n\t\t\t\t\t\t\t\tactionOpts,\r\n\t\t\t\t\t\t\t]);\r\n\t\t\t\t\t\t\tpreValue = await action.fn.call(this, {\r\n\t\t\t\t\t\t\t\tcommand: cmd,\r\n\t\t\t\t\t\t\t\tvalue: preValue,\r\n\t\t\t\t\t\t\t\targs: actionArgs,\r\n\t\t\t\t\t\t\t\toptions: actionOpts,\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t// 原始模式\r\n\t\t\t\t\t\t\tpreValue = await action.fn.apply(this, args);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (preValue === BREAK) break;\r\n\t\t\t\t\t} catch (e) {\r\n\t\t\t\t\t\toutputDebug(\"命令{}的Action({})执行出错:{}\", [self.name, action.id, e]);\r\n\t\t\t\t\t\tthrow e;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} finally {\r\n\t\t\t\tawait self.executeAfterHooks({\r\n\t\t\t\t\tvalue: preValue,\r\n\t\t\t\t\targs: actionArgs,\r\n\t\t\t\t\toptions: actionOpts,\r\n\t\t\t\t\tcommand: cmd,\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\t/**\r\n\t * 当传入--work-dirs时用来处理工作目录\r\n\t */\r\n\tprivate wrapperWorkDirsAction(fn: AsyncFunction) {\r\n\t\tconst self = this;\r\n\t\treturn async function (this: any) {\r\n\t\t\tlet workDirs = self._optionValues.workDirs;\r\n\t\t\t// 未指定工作目录参数\r\n\t\t\tif (!workDirs) {\r\n\t\t\t\treturn await fn.apply(this, Array.from(arguments));\r\n\t\t\t}\r\n\t\t\tif (!Array.isArray(workDirs)) workDirs = workDirs.split(\",\");\r\n\t\t\tworkDirs = workDirs.reduce((dirs: any[], dir: string) => {\r\n\t\t\t\tif (typeof dir == \"string\") dirs.push(...dir.split(\",\"));\r\n\t\t\t\treturn dirs;\r\n\t\t\t}, []);\r\n\t\t\tfor (let workDir of workDirs) {\r\n\t\t\t\tconst cwd = process.cwd();\r\n\t\t\t\ttry {\r\n\t\t\t\t\tif (!path.isAbsolute(workDir)) workDir = path.join(cwd, workDir);\r\n\t\t\t\t\tif (fs.existsSync(workDir) && fs.statSync(workDir).isDirectory()) {\r\n\t\t\t\t\t\toutputDebug(\"切换到工作目录:{}\", workDir);\r\n\t\t\t\t\t\tprocess.chdir(workDir); // 切换\r\n\t\t\t\t\t\tawait fn.apply(this, Array.from(arguments));\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\toutputDebug(\"无效的工作目录:{}\", workDir);\r\n\t\t\t\t\t}\r\n\t\t\t\t} catch (e) {\r\n\t\t\t\t\tthrow e;\r\n\t\t\t\t} finally {\r\n\t\t\t\t\tprocess.chdir(cwd);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\tgetOption(name: string): MixOption {\r\n\t\treturn this.options.find((option) => option.name() == name) as unknown as MixOption;\r\n\t}\r\n\t/**\r\n\t * 添加一个Before钩子\r\n\t * @param listener\r\n\t * @param scope =false时代表只在本命令执行,=true时代表在本命令及其子命令执行\r\n\t * @returns\r\n\t */\r\n\tbefore(listener: BeforeCommandHookListener, scope: boolean = true) {\r\n\t\tthis._beforeHooks.push([listener, scope]);\r\n\t\treturn this;\r\n\t}\r\n\tprivate async executeBeforeHooks(args: any) {\r\n\t\tconst hooks: [BeforeCommandHookListener, boolean, MixCommand][] = this.beforeHooks.map(\r\n\t\t\t([hook, scope]) => [hook, scope, this]\r\n\t\t);\r\n\t\tthis.getAncestorCommands().forEach((cmd: MixCommand) => {\r\n\t\t\thooks.unshift(\r\n\t\t\t\t...cmd.beforeHooks.map(([hook, scope]) => {\r\n\t\t\t\t\treturn [hook, scope, cmd] as [BeforeCommandHookListener, boolean, MixCommand];\r\n\t\t\t\t})\r\n\t\t\t);\r\n\t\t});\r\n\t\tfor (let [hook, scope, cmd] of hooks) {\r\n\t\t\tif (!scope) continue;\r\n\t\t\tawait hook.call(cmd, args);\r\n\t\t}\r\n\t}\r\n\t/**\r\n\t * 添加一个After钩子\r\n\t * @param listener\r\n\t * @param scope =false时代表只在本命令执行,=true时代表在本命令及其子命令执行\r\n\t * @returns\r\n\t */\r\n\tafter(listener: AfterCommandHookListener, scope: boolean = true) {\r\n\t\tthis._afterHooks.push([listener, scope]);\r\n\t\treturn this;\r\n\t}\r\n\tprivate async executeAfterHooks(args: any) {\r\n\t\tconst hooks: [AfterCommandHookListener, boolean, MixCommand][] = this.afterHooks.map(\r\n\t\t\t([hook, scope]) => [hook, scope, this]\r\n\t\t);\r\n\t\tthis.getAncestorCommands().forEach((cmd: MixCommand) => {\r\n\t\t\thooks.push(\r\n\t\t\t\t...cmd.afterHooks.map(([hook, scope]) => {\r\n\t\t\t\t\treturn [hook, scope, cmd] as [BeforeCommandHookListener, boolean, MixCommand];\r\n\t\t\t\t})\r\n\t\t\t);\r\n\t\t});\r\n\t\tfor (let [hook, scope, cmd] of hooks) {\r\n\t\t\tif (!scope) continue; //=false时不执行\r\n\t\t\tawait hook.call(cmd, args);\r\n\t\t}\r\n\t}\r\n\tprivate async preActionHook(thisCommand: Command, actionCommand: Command) {\r\n\t\tif (this.isEnablePrompts()) {\r\n\t\t\t// 自动生成提示\r\n\t\t\tconst questions: PromptObject[] = [\r\n\t\t\t\t...this.generateAutoPrompts(),\r\n\t\t\t\t...this._customPrompts,\r\n\t\t\t];\r\n\t\t\t// 用户提示\r\n\t\t\tif (questions.length > 0) {\r\n\t\t\t\tconst results = await prompts(questions);\r\n\t\t\t\tObject.entries(results).forEach(([key, value]) => {\r\n\t\t\t\t\tthisCommand.setOptionValue(key, value);\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate isEnablePrompts() {\r\n\t\tif (isEnablePrompts() === false) {\r\n\t\t\t// 命令行参数禁用了提示,优先级最高\r\n\t\t\treturn false;\r\n\t\t} else {\r\n\t\t\treturn this._enable_prompts;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * 生成选项自动提示\r\n\t *\r\n\t * @remarks\r\n\t * FlexCli要求所有未提供默认值的Option自动生成提示\r\n\t *\r\n\t * - 未提供默认值,并且是必选的参数Option\r\n\t * - 指定了choices但未提供有效值的Option\r\n\t *\r\n\t */\r\n\tprivate generateAutoPrompts(): PromptObject[] {\r\n\t\tconst options = this.options as unknown as MixOption[];\r\n\t\tconst optionPromports = options\r\n\t\t\t.filter((option) => !option.hidden && option.__MIX_OPTION__)\r\n\t\t\t.map((option) => option.getPrompt(this._optionValues[option.name()]))\r\n\t\t\t.filter((prompt) => prompt) as PromptObject[];\r\n\t\toutputDebug(\"命令<{}>自动生成{}个选项提示:{}\", [\r\n\t\t\tthis.name(),\r\n\t\t\toptionPromports.length,\r\n\t\t\toptionPromports.map((prompt) => `${prompt.name}(${prompt.type})`).join(\",\"),\r\n\t\t]);\r\n\t\treturn optionPromports;\r\n\t}\r\n\toption(flags: string, description?: string | undefined, defaultValue?: any): this;\r\n\toption(flags: string, description?: string | undefined, options?: MixedOptionParams): this {\r\n\t\t// @ts-ignore\r\n\t\tconst option = new MixOption(...arguments);\r\n\t\tif (option.required && !this.isEnablePrompts()) option.mandatory = true;\r\n\t\treturn this.addOption(option as unknown as Option);\r\n\t}\r\n\r\n\t/**\r\n\t * 添加提示\r\n\t *\r\n\t * @remarks\r\n\t *\r\n\t * 添加一些自定义提示\r\n\t *\r\n\t *\r\n\t * @param questions\r\n\t * @param show 是否显示提示信息,auto表示只有在用户没有提供option的值时才显示提示信息,always表示总是显示提示信息,never表示不显示提示信息\r\n\t * @returns\r\n\t */\r\n\tprompt(questions: PromptObject | PromptObject[]) {\r\n\t\tthis._customPrompts.push(...(Array.isArray(questions) ? questions : [questions]));\r\n\t\treturn this;\r\n\t}\r\n\t/**\r\n\t *\r\n\t * 选择命令并执行\r\n\t *\r\n\t * @remorks\r\n\t *\r\n\t * 当命令具有多个子命令时,并且没有提供默认子命令时,提示用户选择一个子命令\r\n\t *\r\n\t */\r\n\tasync selectCommands() {\r\n\t\tconst choices = this.commands.map((command) => ({\r\n\t\t\ttitle: `${command.description()}(${command.name()})`,\r\n\t\t\tvalue: command.name(),\r\n\t\t}));\r\n\t\tconst result = await prompts({\r\n\t\t\ttype: \"select\",\r\n\t\t\tname: \"command\",\r\n\t\t\tmessage: \"请选择命令:\",\r\n\t\t\tchoices,\r\n\t\t});\r\n\t\t// 重新解析命令行参数标志,\r\n\t\tconst command = this.commands.find((command) => command.name() === result.command);\r\n\t\tawait command?.parseAsync([result.command], { from: \"user\" });\r\n\t}\r\n\t/**\r\n\t * 禁用/启用所有提示\r\n\t */\r\n\tdisablePrompts() {\r\n\t\tthis._enable_prompts = false;\r\n\t\treturn this;\r\n\t}\r\n\tenablePrompts() {\r\n\t\tthis._enable_prompts = true;\r\n\t\treturn this;\r\n\t}\r\n}\r\n","import { Option } from 'commander'\nimport { PromptObject } from 'prompts'\nimport { IPromptable, IPromptableOptions, PromptChoice, PromptManager } from './prompt'\n\n\nexport interface MixedOptionParams extends IPromptableOptions{\n hidden?:boolean\n defaultDescription?:string // 默认值的描述 \n conflicts?:string | string[]\n env?:string\n argParser?:<T>(value: string, previous: T) => T \n hideHelp?:boolean\n mandatory?: boolean \n implies?:{[key:string]:any} \n}\n\n\nexport class MixOption extends Option implements IPromptable{\n __MIX_OPTION__ = true\n // 是否提示用户输入\n prompt?: PromptManager \n promptChoices?:PromptChoice[]\n private _validate?: (value: any) => boolean \n constructor(flags: string, description?: string | undefined,optsOrDefault?:any) {\n super(flags, description)\n let params:MixedOptionParams = {}\n if(arguments.length==3 && typeof arguments[2] == \"object\"){\n params = Object.assign({ },arguments[2]) \n }else if(arguments.length==3){\n params.default = arguments[2]\n }\n if(params.prompt===undefined) params.prompt = 'auto'\n if(params.default) this.default(params.default,params.defaultDescription)\n if(params.choices) this.choices(params.choices)\n if(params.conflicts) this.conflicts(params.conflicts)\n if(params.env) this.env(params.env)\n if(params.argParser) this.argParser(params.argParser)\n if(params.hideHelp) this.hideHelp(params.hideHelp)\n if(params.hidden) this.hidden = params.hidden\n if(params.mandatory) this.makeOptionMandatory(params.mandatory)\n if(params.implies) this.implies(params.implies) \n if(params.optional) this.optional=params.optional\n if(typeof(params.validate)=='function') this._validate = params.validate.bind(this)\n if(params.required) {\n this.required = params.required\n if(!this._validate ) this._validate = (value:any)=>String(value).length>0\n }\n this.prompt = new PromptManager(this as IPromptable,params.prompt)\n } \n validate(value: any): boolean {\n if(typeof(this._validate)=='function'){\n return this._validate(value)\n }else{\n return true\n }\n }\n // @ts-ignore\n choices(values:(PromptChoice | string)[]){\n if(!this.promptChoices){\n this.promptChoices = values.map(choice=>{\n if(typeof(choice)=='object'){\n return choice\n }else{\n return {title:choice,value:choice} \n }\n })\n } \n super.choices(this.promptChoices.map((item:any)=>item.value)) \n } \n\n private resetChoices(){\n super.choices(this.promptChoices!.map((item:any)=>item.value)) \n }\n\n addChoice(value:PromptChoice | string){\n if(!this.promptChoices || !Array.isArray(this.promptChoices)) this.promptChoices = []\n this.promptChoices!.push(typeof(value)=='string' ? {title:value,value} : value)\n this.resetChoices()\n }\n removeChoice(value:any){\n this.promptChoices =this.promptChoices?.filter(choice=>choice.value!==value)\n this.resetChoices()\n }\n clearChoice(){\n this.promptChoices = []\n this.resetChoices()\n }\n\n \n /**\n * 返回选项的提示对象\n * \n * @remarks\n * \n *\n * \n * @param inputValue \n * @returns \n */\n getPrompt(inputValue?:any): PromptObject | undefined {\n return this.prompt?.get(inputValue)\n } \n}","import artTemplate from \"art-template\"\r\nimport fs from \"fs-extra\"\r\nimport path from \"node:path\"\r\nimport { promisify } from \"flex-tools/func/promisify\"\r\nimport logsets from \"logsets\" \r\n/**\r\n * \r\n * 在控制台输出一个字符串\r\n * 本方法会将字符串中的每一行空格去掉\r\n * \r\n * @remarks\r\n * \r\n * outputStr(String.raw`\r\n * a\r\n * b`)\r\n * \r\n * 会输出\r\n * a\r\n * b\r\n *\r\n * 此功能可以用于输出多行字符串时,保持代码的缩进格式,而不会影响输出结果\r\n * \r\n * @param str : 要输出的字符串\r\n * @param vars : 用于替换字符串中的变量\r\n * \r\n */\r\nexport function outputStr(str:string,vars?:Record<string,any> | any[]){ \r\n logsets.log(fixIndent(str),vars)\r\n}\r\n\r\n/**\r\n * 修正多行字符串的缩进\r\n * \r\n * @param text \r\n * @param indent \r\n * @returns \r\n */\r\nexport function fixIndent(text:string,indent?:boolean | number):string{\r\n let indentValue = (indent==undefined || indent===true) ? 0 : (typeof(indent)=='number' ? indent : -1)\r\n if(indentValue==-1) return text // 不修正缩进\r\n let lines:string[] = text.split(\"\\n\")\r\n let minSpaceCount = lines.reduce<number>((minCount,line,index)=>{\r\n if(index==0) return minCount\r\n const spaceCount = line.match(/^\\s*/)?.[0].length || 0\r\n return Math.min(minCount,spaceCount)\r\n },9999)\r\n lines = lines.map(line=>line.substring(minSpaceCount))\r\n return lines.join(\"\\n\")\r\n}\r\n\r\n/**\r\n * 增加内置选项\r\n * @param command \r\n */\r\nexport function addBuiltInOptions(command:any){ \r\n command.option(\"--work-dirs <values...>\",\"指定工作目录\",{hidden:true,optional:true,required:true,prompt:false})\r\n command.option(\"--disable-prompts\",\"禁用所有交互提示\",{hidden:true,prompt:false}) \r\n command.option(\"--debug-cli\",\"显示调试信息\",{hidden:true,prompt:false})\r\n}\r\n\r\n\r\n/**\r\n * 是否命令行中包含了--debug-cli选项\r\n */\r\nexport function isDebug(){\r\n return process.argv.includes(\"--debug-cli\")\r\n}\r\nexport function isEnablePrompts(){ \r\n return !process.argv.includes(\"--disable-prompts\")\r\n}\r\n\r\n/**\r\n * 打印调试信息\r\n * @param message \r\n * @param args \r\n */\r\nexport function outputDebug(message:string,...args:any[]){ \r\n let vars = (args.length == 1 && typeof(args[0])=='function') ? args[0]() : args\r\n if(isDebug()) logsets.log(`[MixCli] ${message}`,...vars)\r\n}\r\n\r\nexport const fileExists = promisify(fs.exists,{\r\n parseCallback:(results)=>{\r\n return results[0]\r\n }\r\n})\r\nexport const readFile = promisify(fs.readFile)\r\nexport const writeFile = promisify(fs.writeFile)\r\nexport const mkdir = promisify(fs.mkdir)\r\n\r\n/**\r\n * 基于artTemplate模板生成文件\r\n * \r\n * @param {*} tmplFile \r\n * @param {*} vars \r\n */\r\nexport async function createFileByTemplate(targetFile:string,tmplFile:string,vars:Record<string,any>={}){\r\n tmplFile=path.isAbsolute(tmplFile)? tmplFile : path.join(process.cwd(),tmplFile)\r\n if(!fs.existsSync(tmplFile)){\r\n throw new Error(\"模板文件不存在:\"+tmplFile)\r\n }\r\n targetFile=path.isAbsolute(targetFile)? targetFile : path.join(process.cwd(),targetFile)\r\n const outPath = path.dirname(targetFile)\r\n if(!await fileExists(outPath)){\r\n await mkdir(outPath,{recursive:true})\r\n } \r\n const template = artTemplate(tmplFile,await readFile(tmplFile,{encoding:\"utf-8\"})); \r\n await writeFile(targetFile,template(vars),{encoding:\"utf-8\"})\r\n return targetFile\r\n}\r\n\r\n/** \r\n * 创建目录 \r\n * \r\n * \r\n * \r\n * @param {String[]} dirs 要创建的目录列表,类型为字符串数组 \r\n * @param callback 创建目录过程中的回调函数,类型为异步函数,接收一个参数 dir,表示当前正在创建的目录 \r\n * @returns 该函数返回一个 Promise 对象,表示创建目录的操作是否完成 \r\n */\r\nexport async function mkDirs(dirs:string[],{callback,base}:{callback?:Function,base?:string}){\r\n if(!Array.isArray(dirs)) throw new Error(\"dirs参数必须为字符串数组\")\r\n for(let dir of dirs){\r\n if(!path.isAbsolute(dir)) dir = path.join(base || process.cwd(),dir)\r\n if(typeof(callback)=='function') callback(dir)\r\n await mkdir(dir,{recursive:true})\r\n }\r\n}\r\n\r\nexport function showError(e:any){\r\n if(isDebug()){\r\n outputDebug(\"导入命令<>出错:{}\",e.stack)\r\n }else{\r\n console.error(e)\r\n } \r\n\r\n}\r\n\r\n\r\nexport function getId(){\r\n return Math.random().toString(36).substr(2)\r\n}\r\n\r\n\r\nexport async function importModule(file:string){\r\n let module \r\n try{\r\n module = require(file)\r\n }catch(e:any){\r\n try{\r\n const cmd = await import(`file://${file}`)\r\n module = cmd.default\r\n }catch(e:any){\r\n throw e\r\n } \r\n }\r\n return module\r\n}\r\n","import { PromptObject } from \"prompts\" \nimport { outputDebug } from \"./utils\"\n \n\nexport type PromptType = \"text\" | \"password\" | \"invisible\" | \"number\"| \"confirm\"| \"list\"| \"toggle\"| \"select\" | \"multiselect\" | \"autocomplete\" | \"date\" | \"autocompleteMultiselect\"\n\nexport type PromptParam = 'auto' | boolean | PromptType | PromptObject\nexport type InputPromptParam = PromptParam | ((value:any)=>PromptParam) | boolean\nexport type PromptParamDefaultValue = string | boolean | string[] \n\nexport const promptTypeMap:Record<string,string> = {\n boolean:\"confirm\",\n string:\"text\",\n number:\"number\", \n array:\"list\", \n} \n\nexport const supportedPromptTypes = [\"text\",\"password\",\"invisible\", \"number\", \"confirm\" , \"list\", \"toggle\" , \"select\" , \"multiselect\" , \"autocomplete\" , \"date\" , \"autocompleteMultiselect\"]\nexport interface PromptChoice {\n title: string;\n value?: any;\n disabled?: boolean | undefined;\n selected?: boolean | undefined;\n description?: string | undefined;\n}\n\n\n\nexport interface IPromptableOptions{\n required?: boolean; // A value must be supplied when the option is specified.\n optional?: boolean; // A value is optional when the option is specified.\n default?:PromptParamDefaultValue\n choices?:(PromptChoice | any)[] // 选项值的可选值\n prompt?:InputPromptParam\n validate?:(value: any) => boolean\n}\n\n\nexport interface IPromptable{\n name():string \n description?:string\n flags:string\n promptChoices?:PromptChoice[]\n argChoices?:string[]\n variadic?:boolean\n defaultValue?:PromptParamDefaultValue\n input?:any \n required?:boolean\n validate?: (value: any) => boolean \n getPrompt(inputValue?:any):PromptObject | undefined \n}\n\n/**\n * 供command.option()使用的参数对象\n */\nexport interface PromptableObject{\n \n\n}\n\n\n/**\n * 负责生成prompt对象\n * \n */\nexport class PromptManager{\n args:InputPromptParam \n private _promptable:IPromptable // 对应的FlexOption或FlexArgument\n constructor(promptable:IPromptable,promptArgs?:InputPromptParam){ \n this._promptable = promptable\n this.args= promptArgs===undefined ? 'auto' : promptArgs\n }\n\n /**\n * 返回输入的是否是有效的prompt类型\n * @param type \n * @returns \n */\n isValid(type:any){\n return supportedPromptTypes.includes(String(type))\n }\n /**\n * 推断是否需要提示\n * \n */\n isNeed(input:any,defaultValue?:any){\n \n const promptArg = this.args\n const inputValue = input || defaultValue\n // 是否有输入值,即在命令行输入了值\n const hasInput = !(inputValue === undefined)\n // 1. 显式指定了_prompt为true,则需要提示,后续进行提示类型的推断,可能不会准确\n if(promptArg===true) return true\n if(promptArg===false) return false \n\n // 2. 提供了一个prompt对象,并且没有在命令行输入值,则需要提示\n if(typeof(promptArg)=='object'){\n return !hasInput\n }\n\n // 3. 指定了内置的prompt类型,如prompt='password',则使用password类型提示输入\n if(typeof(promptArg) == 'string' && supportedPromptTypes.includes(promptArg)){\n return !hasInput\n }\n \n // 4. 判断输入是否有效,则显示提示\n if(this._promptable.argChoices && this._promptable.argChoices.indexOf(inputValue) == -1){\n return true\n } \n return !hasInput\n }\n /**\n * 返回生成prompt对象\n * \n * @param inputValue 从命令行输入的值\n */\n get(inputValue?:any){\n const {description,promptChoices,validate,defaultValue} = this._promptable\n let input = inputValue || defaultValue\n // 判断是否需要输入提示\n if(!this.isNeed(input,defaultValue)) return\n // 推断prompt类型\n let promptType = this.infer(inputValue)\n const prompt = {\n type:promptType, \n name:this._promptable.name(),\n message:description,\n initial: input,\n ...typeof(this.args) == 'object' ? this.args : {}\n } as PromptObject\n // 指定了验证函数,用来验证输入值是否有效\n prompt.validate = validate?.bind(this._promptable)\n if(promptType=='multiselect') prompt.instructions=false\n if(['select','multiselect'].includes(promptType)){\n let index = promptChoices?.findIndex(item=>item.value==input)\n prompt.initial = index==-1 ? undefined : index\n } \n // 选项值的可选值\n if(Array.isArray(promptChoices)) {\n prompt.choices =promptChoices\n }\n return prompt\n }\n /**\n * 推断prompt类型\n * \n * @param inputValue 从命令行输入的值\n */\n infer(inputValue?:any){\n const {argChoices,variadic,defaultValue} = this._promptable\n let input = inputValue || defaultValue\n // 如果选择指定了\"-p [value]或[value...]\",则使用text类型,如果没有要求输入值,则使用confirm类型\n let promptType = /(\\<[\\w\\.]+\\>)|(\\[[\\w\\.]+\\])/.test(this._promptable.flags) ? 'text' : 'confirm'\n let promptArg = this.args\n if(this.isValid(promptArg)){ // 显式指定了prompt类型\n promptType = promptArg as string\n }else{ // 未显式指定prompt类型,需要按一定规则推断类型\n if(typeof(promptArg)=='object'){\n promptType = promptArg.type as string\n }else{\n if(argChoices){ // 提供多个可选值时\n promptType = variadic ? 'multiselect' : 'select'\n }else{\n const datatype:string = Array.isArray(defaultValue) ? 'array' : typeof(defaultValue) \n // 如果输入值班是数组,则使用list类型,允许使用逗号分隔的多个值\n if(Array.isArray(input) || variadic){\n promptType = \"list\"\n }else{\n if(datatype in promptTypeMap){\n promptType = promptTypeMap[datatype]\n }\n }\n }\n }\n }\n outputDebug(\"选项<{}> -> 提示类型<{}>\",[this._promptable.name(),promptType])\n return promptType\n }\n\n}","import { getPackageJson } from \"flex-tools/package/getPackageJson\"\r\nimport { getPackageRootPath } from 'flex-tools/package/getPackageRootPath';\r\nimport type { MixCli } from './cli';\r\nimport { globSync } from 'glob'\r\nimport { MixCliCommand } from './cli';\r\nimport { importModule, isDebug, outputDebug } from './utils';\r\nimport fs from \"node:fs\"\r\nimport path from \"node:path\"\r\n\r\n\r\n/**\r\n * \r\n * 在当前工程中查找符合FlexCli.prefix约定的命令 \r\n * \r\n * - 读取当前包的package.json\r\n * - 找出所有以cli.prefix开头的依赖\r\n * - 加载这些依赖的目录下的匹配cli.pattern的命令\r\n * - 加载加载这样命令\r\n * \r\n */\r\n \r\n\r\nexport function getMatchedDependencies(this:MixCli,entry:string):string[]{\r\n const pacakgeMacher = this.options.include\r\n if(!(pacakgeMacher instanceof RegExp)) return []\r\n \r\n // 找出当前包的所有依赖\r\n const { dependencies={},devDependencies={},peerDependencies={},optionalDependencies={},bundleDependencies={} } = getPackageJson(entry)\r\n const packageNames = [\r\n ...Object.keys(dependencies),\r\n ...Object.keys(devDependencies),\r\n ...Object.keys(peerDependencies),\r\n ...Object.keys(optionalDependencies),\r\n ...Object.keys(bundleDependencies)\r\n ]\r\n return packageNames.filter(name=>name!==\"@voerka/cli\" && pacakgeMacher.test(name))\r\n}\r\n\r\nfunction isMatched(str:string,reg?:string | RegExp | string[] | RegExp[]):boolean{\r\n // let regexps:RegExp[]=[]\r\n const regexps = reg ? (Array.isArray(reg) ? reg : [reg]) : []\r\n return regexps.some(regexp=>{\r\n if(typeof regexp === \"string\"){\r\n return (new RegExp(regexp)).test(str)\r\n }else if(regexp instanceof RegExp){\r\n return regexp.test(str)\r\n }else{\r\n return false\r\n }\r\n })\r\n}\r\n\r\nexport function findCliPaths(this:MixCli,packageName?:string ,entry?:string):string[]{\r\n const includeMacher = this.options.include\r\n const excludeMacher = this.options.exclude\r\n if(!includeMacher) return []\r\n const packageRoot = getPackageRootPath(entry || process.cwd())\r\n const packagePath = packageName ? path.dirname(require.resolve(packageName,{paths:[packageRoot as string]})) : packageRoot\r\n\r\n if(!packagePath) {\r\n outputDebug(\"MixCli只能运行在Nodejs环境\" )\r\n return []\r\n }\r\n\r\n // 找出当前包的所有依赖\r\n const packageNames = getMatchedDependencies.call(this,packagePath)\r\n\r\n const cliDirs:string[]=[]\r\n \r\n if(entry!==undefined) cliDirs.push(path.join(packagePath,this.options.cliDir))\r\n packageNames.filter(name=>{\r\n return isMatched(name,includeMacher) && !isMatched(name,excludeMacher) \r\n })\r\n .forEach(name=>{\r\n outputDebug(\"匹配包:{}\",`${packageName ? name+\" <- \"+packageName : name}`)\r\n try{\r\n const packageEntry = path.dirname(require.resolve(name,{paths:packagePath ? [packagePath] : [process.cwd()]}))\r\n const packageCliDir =path.join(packageEntry,this.options.cliDir!) \r\n // 查找当前包的所属工程的依赖\r\n let dependencies = getMatchedDependencies.call(this,packageEntry)\r\n cliDirs.push(...dependencies.reduce<string[]>((result,dependencie)=>{\r\n outputDebug(\"匹配包:{}\",`${dependencie} <- ${name}`)\r\n result.push(...findCliPaths.call(this,dependencie,packageEntry))\r\n return result\r\n },[])) \r\n if(fs.existsSync(packageCliDir)){\r\n cliDirs.push(packageCliDir)\r\n }\r\n }catch(e:any){\r\n outputDebug(\"解析包<{}>路径出错:{}\",[name,e.stack])\r\n } \r\n })\r\n // 由于一些包可能存在循环依赖,所以需要去重\r\n return [...new Set(cliDirs)]\r\n}\r\n\r\n\r\n/**\r\n * \r\n * 扫描当前工程中所有符合条件的命令\r\n * \r\n * @param cli \r\n * \r\n */\r\nexport async function findCommands(cli:MixCli){ \r\n const cliDirs = findCliPaths.call(cli)\r\n const commands:MixCliCommand[] = []\r\n const files = [] as string[]\r\n cliDirs.forEach(dir=>{\r\n globSync(\"*\",{\r\n cwd:dir,\r\n absolute :true \r\n }).forEach((file:string)=>{ \r\n const baseName = path.basename(file) \r\n if(baseName.startsWith(\"_\")) return\r\n const ext = path.extname(file).toLowerCase()\r\n if([\".js\",\".cjs\",\".mjs\"].includes(ext)){\r\n files.push(file)\r\n }else if(fs.statSync(file).isDirectory()){\r\n files.push(path.join(file,\"index.js\"))\r\n files.push(path.join(file,\"index.cjs\"))\r\n files.push(path.join(file,\"index.mjs\"))\r\n }\r\n })\r\n })\r\n for(let file of files){ \r\n if(!fs.existsSync(file)) continue\r\n try{\r\n outputDebug(\"导入命令:{}\",file)\r\n if(file.endsWith(\".cjs\") || file.endsWith(\".js\")){\r\n commands.push(await importModule(file))\r\n }else if(file.endsWith(\".mjs\")){\r\n const cmd = await import(`file://${file}`)\r\n commands.push(cmd.default)\r\n } \r\n }catch(e:any){\r\n outputDebug(e) \r\n }\r\n }\r\n return commands\r\n}\r\n\r\n"],"mappings":"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","names":["import_logsets","import_commander","logsets","fs","path","artTemplate","module","e","import_node_path","path","fs","prompts","command","import_node_fs","import_node_path","path","fs","replaceAll","logsets","cmd"]}
package/dist/index.mjs CHANGED
@@ -272,6 +272,7 @@ var PromptManager = class {
272
272
  var MixOption = class extends Option {
273
273
  constructor(flags, description, optsOrDefault) {
274
274
  super(flags, description);
275
+ this.__MIX_OPTION__ = true;
275
276
  let params = {};
276
277
  if (arguments.length == 3 && typeof arguments[2] == "object") {
277
278
  params = Object.assign({}, arguments[2]);
@@ -371,6 +372,7 @@ var MixCommand = class extends Command {
371
372
  // 是否启用交互提示
372
373
  constructor(name) {
373
374
  super(name);
375
+ this.__MIX_COMMAND__ = true;
374
376
  this._beforeHooks = [];
375
377
  this._afterHooks = [];
376
378
  this._customPrompts = [];
@@ -680,7 +682,7 @@ var MixCommand = class extends Command {
680
682
  */
681
683
  generateAutoPrompts() {
682
684
  const options = this.options;
683
- const optionPromports = options.filter((option) => !option.hidden && option instanceof MixOption).map((option) => option.getPrompt(this._optionValues[option.name()])).filter((prompt) => prompt);
685
+ const optionPromports = options.filter((option) => !option.hidden && option.__MIX_OPTION__).map((option) => option.getPrompt(this._optionValues[option.name()])).filter((prompt) => prompt);
684
686
  outputDebug("\u547D\u4EE4<{}>\u81EA\u52A8\u751F\u6210{}\u4E2A\u9009\u9879\u63D0\u793A:{}", [
685
687
  this.name(),
686
688
  optionPromports.length,
@@ -871,7 +873,8 @@ var MixCli = class extends LiteEvent {
871
873
  name: "mixcli",
872
874
  package: null,
873
875
  cliDir: "cli",
874
- prompt: "auto"
876
+ prompt: "auto",
877
+ ignoreError: false
875
878
  }, options);
876
879
  this.createRootCommand();
877
880
  }
@@ -901,6 +904,7 @@ var MixCli = class extends LiteEvent {
901
904
  this.register(() => cmds);
902
905
  }
903
906
  } catch (e) {
907
+ outputDebug("\u6CE8\u518C\u547D\u4EE4\u5931\u8D25:{}", e.stack);
904
908
  }
905
909
  }
906
910
  });
@@ -954,14 +958,17 @@ var MixCli = class extends LiteEvent {
954
958
  let result = cmd(this);
955
959
  let cmds = result instanceof Array ? result : result == void 0 ? [] : [result];
956
960
  for (let cmd2 of cmds) {
957
- if (cmd2 instanceof MixCommand) {
961
+ if (cmd2.__MIX_COMMAND__) {
958
962
  if (this.hasCommand(cmd2.name())) {
959
963
  logsets2.error(`Command <${cmd2.name()}> has been registered!`);
960
964
  } else {
965
+ outputDebug("\u6CE8\u518C\u547D\u4EE4:{}", cmd2.fullname);
961
966
  this.root.addCommand(cmd2);
962
967
  cmd2._cli = this;
963
968
  this.emit("register", cmd2.fullname, true);
964
969
  }
970
+ } else {
971
+ logsets2.error(`Command <${cmd2.toString()}> is not a valid command!`);
965
972
  }
966
973
  }
967
974
  } else {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/command.ts","../src/option.ts","../src/utils.ts","../src/prompt.ts","../src/finder.ts"],"sourcesContent":["#!/usr/bin/env node\nimport \"flex-tools/string\"\nimport { LiteEvent, LiteEventSubscriber } from \"flex-tools/events/liteEvent\"\nimport { Command } from \"commander\"\nimport logsets from \"logsets\"\n\nimport { assignObject } from \"flex-tools/object/assignObject\"\nimport { MixCommand } from \"./command\"\nimport { addBuiltInOptions, fixIndent, isDebug } from './utils';\nimport { findCommands } from \"./finder\"\nimport { asyncSignal } from \"flex-tools/async/asyncSignal\"\n// @ts-ignore\nimport replaceAll from 'string.prototype.replaceall'\nimport { getPackageEntry, getPackageRootPath } from \"flex-tools\"\nimport { getPackageJson } from 'flex-tools/package/getPackageJson';\nreplaceAll.shim() \n\nexport interface MixCliOptions{\n name:string,\n title?:string | (string | boolean | number)[],\n description?:string,\n version?:string\n // 定义显示帮助信息\n logo?:string ,\n // 在根命令执行前执行==commander的preAction\n before?:(thisCommand:Command,actionCommand:Command)=>void,\n // 在根命令执行后执行==commander的postAction\n after?:(thisCommand:Command,actionCommand:Command)=>void, \n // flexcli运行时会在当前工程的package.json的依赖中查找以prefix/开头的包,然后自动加载其cli目录下的命令\n // 例如:prefix=myapp,则会自动加载flex-cli-xxx包中的cli目录下的命令\n // 如prefix=myapp, cliPath=\"cmds\",则会自动加载flex-cli-xxx包中的cmds目录下的命令\n include?:string | RegExp | string[] | RegExp[],\n // 忽略查找正则表达式\n exclude?:string | RegExp | string[] | RegExp[],\n // flexcli会在当前工程的以prefix/开头下查找命令声明\n // / pattern默认值是cli,即会在当前工程的以prefix/开头的包下查找cli目录下的命令\n // 指定cli所在的目录,默认值是cli,要遍历该目录下的所有js文件作为命令导出\n cliDir?:string \n context?:Record<string,any> // 传递给命令的共享上下文,所有命令均可要使用 \n // 默认是否启用交互提示, auto当没有值时,会根据当前是否在终端中运行来决定是否启用交互提示\n // 为false时,禁用所有交互提示,为true时,启用所有交互提示 \n prompt?:'auto' | boolean \n}\n\n \n \n\nexport type MixCliCommand = (cli:MixCli)=>MixCommand | MixCommand[] | void\n\n\nexport type MixCliEvents = \n \"register\" // 当命令注册时触发\n\nexport class MixCli extends LiteEvent<any,MixCliEvents>{\n options:Required<MixCliOptions> \n root!:Command \n private findSignals:any[]=[]\n constructor(options?:MixCliOptions){\n super()\n this.options= assignObject({\n name:\"mixcli\",\n package:null,\n cliDir:\"cli\",\n prompt:'auto'\n },options) \n this.createRootCommand() \n } \n get context(){return this.options.context}\n get name(){return this.options.name}\n /**\n * 是否禁用了所有的交互提示\n */\n get isDisabledPrompts(){\n return(this.root as any).rawArgs.includes(\"--no-prompts\") \n } \n /**\n * 扫描当前工程的依赖,加载匹配include的依赖下的命令\n */\n private async installCommands(){\n const cmders = await findCommands(this)\n for(let cmder of cmders){\n try{\n if(typeof(cmder)===\"function\"){\n let cmds = cmder(this)\n cmds =cmds ? (Array.isArray(cmds) ? cmds : [cmds]) : []\n this.register(()=>cmds) \n }\n }catch(e:any){\n }\n }\n } \n /**\n * 创建根命令\n * \n */\n private createRootCommand(){\n this.root = new MixCommand(this.name);\n this.root \n .helpOption('-h, --help')\n .action(()=>{ \n if(this.options.logo) logsets.log(fixIndent(this.options.logo,2))\n console.log()\n // 显示标题\n let title = this.options.title|| this.options.name\n if(Array.isArray(title)){\n logsets.log(String(title[0]).firstUpper(),[...title.slice(1)])\n }else{\n logsets.log(`${title.firstUpper()} Version: {}`,this.options.version)\n } \n // @ts-ignore\n if(this.options.description) logsets.log(logsets.colors.darkGray(this.options.description)) \n console.log()\n this.root.help() \n }) \n addBuiltInOptions(this.root)\n if(this.options.before) this.root.hook('preAction',this.options.before)\n if(this.options.after) this.root.hook('postAction',this.options.after) \n } \n /**\n * 添加帮助选项\n * \n * @param text 帮助文本\n * @param position 显示位置,可选值:before|after|beforeAll|afterAll\n * @param fixIndent 是否自动修正缩进,如果为true,则会自动修正缩进,当显示多行时文本时,会自动修正缩进\n * \n */\n public addHelp(text:string,{pos='beforeAll',alignIndent=true}:{pos:'before'|'after' | 'beforeAll' | 'afterAll',alignIndent?:boolean | number}){\n if(alignIndent) text = fixIndent(text,alignIndent)\n this.root.addHelpText(pos,text)\n }\n\n /**\n * 注册一个命令\n * @param cmd \n */\n register(cmd:MixCliCommand){\n if(typeof(cmd)==\"function\"){\n let result = cmd(this)\n let cmds = result instanceof Array ? result : (result==undefined ? [] : [result])\n for(let cmd of cmds){\n if(cmd instanceof MixCommand){\n if(this.hasCommand(cmd.name())){\n logsets.error(`Command <${cmd.name()}> has been registered!`)\n }else{\n this.root.addCommand(cmd) ;\n (cmd as any)._cli = this\n this.emit(\"register\",cmd.fullname,true)\n } \n }\n } \n }else{\n logsets.error(\"Invalid command\")\n } \n }\n\n hasCommand(name:string):boolean{\n return this.root.commands.some(c=>c.name()==name)\n }\n\n /**\n * 根据命令名称查找命令\n * \n * @remarks\n * \n * find(\"dev\")\n * find(\"dev.microservice\") 支持多级命令\n * find(\"abc\",DevCommand) 允许指定从DevCommand下开始查找abc命令\n * \n * @param name \n */\n get(name:string):MixCommand | undefined{\n const names=name.split(\".\")\n let curCmd:Command = this.root\n let resultCmd:MixCommand | undefined\n while(names.length>0){\n const topName = names.shift()\n const r = curCmd.commands.find(c=>c.name()==topName) as MixCommand\n if(r && names.length==0){\n resultCmd = r\n }\n curCmd = r\n } \n return resultCmd \n }\n /**\n * 查找一个命令\n * \n * 如果命令不存在,则等待命令注册后再返回\n * \n * 在多包场景下,如果命令在其他包中注册并且该包中的命令还没注册,则会等待命令注册后再返回\n * \n * @param name \n * @returns \n */\n find(name:string):Promise<MixCommand | undefined>{\n const cmd = this.get(name)\n if(cmd){\n return Promise.resolve(cmd) \n }else{\n const signal = asyncSignal()\n this.findSignals.push(signal)\n return new Promise<MixCommand | undefined>((resolve)=>{\n let listener:LiteEventSubscriber\n listener = this.on(\"register\",(fullname:string)=>{\n if(fullname==`${this.name}.${name}`){\n listener.off()\n signal.resolve()\n this.findSignals = this.findSignals.filter(s=>s!=signal)\n resolve(this.get(name))\n }\n },{objectify:true}) as LiteEventSubscriber\n })\n } \n }\n /**\n * 判断命令是否存在\n * \n * @param name \n * @returns \n */\n exists(name:string):boolean{\n if(name in this.root.commands){\n return true\n }else{\n return this.get(name) != undefined\n }\n } \n \n /**\n * 运行命令行程序\n */\n run(){ \n // 为什么有findSignal这玩意,解决什么问题?\n // 当我们要扩展command时,通过get(\"命令名称\")来获取已经注册的命令的方式有个缺陷\n // 就是如果对命令的注册顺序有严格的要求,比如调用get('dev')时要求dev命令必须已经存在\n // 这对动态包的命令注册扩展开发体验不好\n // 所以引入find(\"命令名称\")来获取命令,该方法可以获取到后注册的命令\n // 其副作用是,在run时,可能find还没有运行到,从而导致在帮助信息里面看不到扩展的信息(实际上是已经生效的)\n // 所以我们在find里面注入一个异步信号来解决此问题\n this.installCommands().then(()=>{\n return Promise.all(this.findSignals.map(signal=>signal(10000))).then(()=>{\n this.root.parseAsync(process.argv); \n })\n }) \n }\n /**\n * 创建一个命令\n * \n * \n */\n create(){\n } \n}\n ","import { Command, Option } from \"commander\";\r\nimport prompts, { PromptObject } from \"prompts\";\r\nimport { MixOption, type MixedOptionParams } from \"./option\";\r\nimport { addBuiltInOptions, isEnablePrompts, outputDebug } from \"./utils\";\r\nimport path from \"node:path\";\r\nimport fs from \"node:fs\";\r\nimport type { AsyncFunction } from \"flex-tools\";\r\n\r\nexport type ICommandHookListener = ({\r\n\targs,\r\n\toptions,\r\n\tcommand,\r\n}: {\r\n\targs: any[];\r\n\toptions: Record<string, any>;\r\n\tcommand: MixCommand;\r\n}) => void | Promise<void>;\r\n\r\nexport type BeforeCommandHookListener = ({\r\n\targs,\r\n\toptions,\r\n\tcommand,\r\n}: {\r\n\targs: any[];\r\n\toptions: Record<string, any>;\r\n\tcommand: MixCommand;\r\n}) => void | Promise<void>;\r\nexport type AfterCommandHookListener = ({\r\n\tvalue,\r\n\targs,\r\n\toptions,\r\n\tcommand,\r\n}: {\r\n\tvalue: any;\r\n\targs: any[];\r\n\toptions: Record<string, any>;\r\n\tcommand: MixCommand;\r\n}) => void | Promise<void>;\r\n\r\nexport interface ActionOptions {\r\n\tid: string;\r\n\tat: \"replace\" | \"before\" | \"after\" | \"preappend\" | \"append\" | number;\r\n\t// 函数签名类型,即采用原始的commander的action函数签名,还是mixcli的action函数签名\r\n\tenhance: boolean;\r\n}\r\n\r\nexport interface ActionRegistry extends Omit<ActionOptions, \"at\"> {\r\n\tfn: Function;\r\n}\r\n\r\n// 原始的Action动作函数\r\nexport type OriginalAction = (...args: any[]) => void | Promise<void>;\r\n// 增强的Action函数签名\r\nexport type EnhanceAction = ({\r\n\targs,\r\n\toptions,\r\n\tvalue,\r\n\tcommand,\r\n}: {\r\n\targs: any[];\r\n\toptions: Record<string, any>;\r\n\tvalue: any;\r\n\tcommand: MixCommand;\r\n}) => void | Promise<any>;\r\n\r\n// 执行action的返回结果\r\nexport const BREAK = Symbol(\"BREAK_ACTION\"); // 中止后续的action执行\r\n\r\nexport class MixCommand extends Command {\r\n\tprivate _beforeHooks: [BeforeCommandHookListener, boolean][] = [];\r\n\tprivate _afterHooks: [AfterCommandHookListener, boolean][] = [];\r\n\tprivate _customPrompts: PromptObject[] = [];\r\n\tprivate _optionValues: Record<string, any> = {}; // 命令行输入的选项值\r\n\tprivate _actions: ActionRegistry[] = []; // 允许多个action\r\n\tprivate _enable_prompts: boolean = true; // 是否启用交互提示\r\n\tconstructor(name?: string) {\r\n\t\tsuper(name);\r\n\t\tconst self = this;\r\n\t\tif (!this.isRoot) addBuiltInOptions(this);\r\n\t\tthis.hook(\"preAction\", async function (this: any) {\r\n\t\t\tself._optionValues = self.getOptionValues(this.hookedCommand);\r\n\t\t\ttry {\r\n\t\t\t\t// @ts-ignore\r\n\t\t\t\tawait self.preActionHook.apply(self, arguments);\r\n\t\t\t} catch {}\r\n\t\t});\r\n\t}\r\n\t/**\r\n\t * 是否是根命令\r\n\t */\r\n\tget isRoot() {\r\n\t\treturn !!!this.parent;\r\n\t}\r\n\tget actions() {\r\n\t\treturn this._actions;\r\n\t}\r\n\tget beforeHooks() {\r\n\t\treturn this._beforeHooks;\r\n\t}\r\n\tget afterHooks() {\r\n\t\treturn this._afterHooks;\r\n\t}\r\n\tget fullname() {\r\n\t\tlet names = [this.name()];\r\n\t\tlet parent = this.parent;\r\n\t\twhile (parent) {\r\n\t\t\tif (parent.name() !== \"root\") {\r\n\t\t\t\tnames.unshift(parent.name());\r\n\t\t\t}\r\n\t\t\tparent = parent.parent;\r\n\t\t}\r\n\t\treturn names.join(\".\");\r\n\t}\r\n\r\n\t/**\r\n\t * 返回根命令\r\n\t */\r\n\troot() {\r\n\t\tlet root: MixCommand | null | undefined = this;\r\n\t\twhile (root && root.parent != null) {\r\n\t\t\troot = root.parent as unknown as MixCommand;\r\n\t\t}\r\n\t\treturn root;\r\n\t}\r\n\taction(fn: EnhanceAction, options: ActionOptions): this;\r\n\taction(fn: OriginalAction): this;\r\n\taction(fn: OriginalAction): this {\r\n\t\tconst actionFunc = arguments[0];\r\n\t\tif (arguments.length == 1 && typeof actionFunc == \"function\") {\r\n\t\t\t// 原始方式\r\n\t\t\tthis._actions.push({\r\n\t\t\t\tid: Math.random().toString(36).substring(2),\r\n\t\t\t\tenhance: false,\r\n\t\t\t\tfn: actionFunc,\r\n\t\t\t});\r\n\t\t} else if (\r\n\t\t\targuments.length == 2 &&\r\n\t\t\ttypeof actionFunc == \"function\" &&\r\n\t\t\ttypeof arguments[1] == \"object\"\r\n\t\t) {\r\n\t\t\t// 增强模式\r\n\t\t\tconst actionFn = arguments[0];\r\n\t\t\tconst actionOpts: ActionOptions = Object.assign({ at: \"append\" }, arguments[1]);\r\n\t\t\tif (actionOpts.at == \"replace\") this._actions = [];\r\n\t\t\tconst actionItem = {\r\n\t\t\t\tid: actionOpts.id || Math.random().toString(36).substring(2),\r\n\t\t\t\tenhance: actionOpts.enhance == undefined ? true : actionOpts.enhance,\r\n\t\t\t\tfn: actionFn,\r\n\t\t\t} as const;\r\n\t\t\tif (typeof actionOpts.at == \"number\") {\r\n\t\t\t\tthis._actions.splice(Number(actionOpts.at), 0, actionItem);\r\n\t\t\t} else if ([\"append\", \"before\"].includes(actionOpts.at)) {\r\n\t\t\t\tthis._actions.push(actionItem);\r\n\t\t\t} else if ([\"preappend\", \"after\"].includes(actionOpts.at)) {\r\n\t\t\t\tthis._actions.splice(0, 0, actionItem);\r\n\t\t\t} else {\r\n\t\t\t\tthis._actions.push(actionItem);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tconsole.log(\"[mixcli] action params error\");\r\n\t\t}\r\n\t\treturn super.action(this.getWrapperedAction());\r\n\t}\r\n\r\n\t/**\r\n\t * 读取命令配置值,包括父命令提供的配置选项\r\n\t * @param command\r\n\t */\r\n\tprivate getOptionValues(command: Command) {\r\n\t\tlet opts = {};\r\n\t\tlet parent: Command | null = command;\r\n\t\twhile (parent) {\r\n\t\t\tObject.assign(opts, (parent as MixCommand)._optionValues);\r\n\t\t\tparent = parent.parent;\r\n\t\t}\r\n\t\treturn opts;\r\n\t}\r\n\t/**\r\n\t * 本函数在运行时子类进行action生成该命令的action\r\n\t */\r\n\tprivate getWrapperedAction() {\r\n\t\treturn this.wrapperWorkDirsAction(this.wrapperChainActions());\r\n\t}\r\n\r\n\t/**\r\n\t * 向上查找所有祖先命令\r\n\t */\r\n\tprivate getAncestorCommands(): MixCommand[] {\r\n\t\tlet cmds: MixCommand[] = [];\r\n\t\tlet cmd: MixCommand | null = this;\r\n\t\twhile (cmd) {\r\n\t\t\tcmd = cmd.parent as MixCommand;\r\n\t\t\tif (cmd) {\r\n\t\t\t\tcmds.push(cmd);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn cmds;\r\n\t}\r\n\t/***\r\n\t * 将所有actions包装成一个链式调用的函数\r\n\t */\r\n\tprivate wrapperChainActions() {\r\n\t\tconst self = this;\r\n\t\treturn async function (this: any) {\r\n\t\t\tconst args = Array.from(arguments); // 原始输入的参数\r\n\t\t\tlet preValue: any; // 保存上一个action的返回值\r\n\t\t\t//解析参数, 0-1个参数为options,最后一个参数为command\r\n\t\t\tlet actionOpts: Record<string, any> = {},\r\n\t\t\t\tactionArgs: any[] = [],\r\n\t\t\t\tcmd: any;\r\n\t\t\tif (args.length >= 2) {\r\n\t\t\t\tcmd = args[args.length - 1]; // 最后一个command\r\n\t\t\t\tactionOpts = args[args.length - 2];\r\n\t\t\t\tactionArgs = args.slice(0, args.length - 2);\r\n\t\t\t}\r\n\t\t\tawait self.executeBeforeHooks({ args: actionArgs, options: actionOpts, command: cmd });\r\n\t\t\ttry {\r\n\t\t\t\tfor (let action of self._actions) {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tif (action.enhance) {\r\n\t\t\t\t\t\t\t// 增强模式\r\n\t\t\t\t\t\t\toutputDebug(\"执行<{}>: args={}, options={}\", () => [\r\n\t\t\t\t\t\t\t\tself.name(),\r\n\t\t\t\t\t\t\t\tactionArgs,\r\n\t\t\t\t\t\t\t\tactionOpts,\r\n\t\t\t\t\t\t\t]);\r\n\t\t\t\t\t\t\tpreValue = await action.fn.call(this, {\r\n\t\t\t\t\t\t\t\tcommand: cmd,\r\n\t\t\t\t\t\t\t\tvalue: preValue,\r\n\t\t\t\t\t\t\t\targs: actionArgs,\r\n\t\t\t\t\t\t\t\toptions: actionOpts,\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t// 原始模式\r\n\t\t\t\t\t\t\tpreValue = await action.fn.apply(this, args);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (preValue === BREAK) break;\r\n\t\t\t\t\t} catch (e) {\r\n\t\t\t\t\t\toutputDebug(\"命令{}的Action({})执行出错:{}\", [self.name, action.id, e]);\r\n\t\t\t\t\t\tthrow e;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} finally {\r\n\t\t\t\tawait self.executeAfterHooks({\r\n\t\t\t\t\tvalue: preValue,\r\n\t\t\t\t\targs: actionArgs,\r\n\t\t\t\t\toptions: actionOpts,\r\n\t\t\t\t\tcommand: cmd,\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\t/**\r\n\t * 当传入--work-dirs时用来处理工作目录\r\n\t */\r\n\tprivate wrapperWorkDirsAction(fn: AsyncFunction) {\r\n\t\tconst self = this;\r\n\t\treturn async function (this: any) {\r\n\t\t\tlet workDirs = self._optionValues.workDirs;\r\n\t\t\t// 未指定工作目录参数\r\n\t\t\tif (!workDirs) {\r\n\t\t\t\treturn await fn.apply(this, Array.from(arguments));\r\n\t\t\t}\r\n\t\t\tif (!Array.isArray(workDirs)) workDirs = workDirs.split(\",\");\r\n\t\t\tworkDirs = workDirs.reduce((dirs: any[], dir: string) => {\r\n\t\t\t\tif (typeof dir == \"string\") dirs.push(...dir.split(\",\"));\r\n\t\t\t\treturn dirs;\r\n\t\t\t}, []);\r\n\t\t\tfor (let workDir of workDirs) {\r\n\t\t\t\tconst cwd = process.cwd();\r\n\t\t\t\ttry {\r\n\t\t\t\t\tif (!path.isAbsolute(workDir)) workDir = path.join(cwd, workDir);\r\n\t\t\t\t\tif (fs.existsSync(workDir) && fs.statSync(workDir).isDirectory()) {\r\n\t\t\t\t\t\toutputDebug(\"切换到工作目录:{}\", workDir);\r\n\t\t\t\t\t\tprocess.chdir(workDir); // 切换\r\n\t\t\t\t\t\tawait fn.apply(this, Array.from(arguments));\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\toutputDebug(\"无效的工作目录:{}\", workDir);\r\n\t\t\t\t\t}\r\n\t\t\t\t} catch (e) {\r\n\t\t\t\t\tthrow e;\r\n\t\t\t\t} finally {\r\n\t\t\t\t\tprocess.chdir(cwd);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\tgetOption(name: string): MixOption {\r\n\t\treturn this.options.find((option) => option.name() == name) as unknown as MixOption;\r\n\t}\r\n\t/**\r\n\t * 添加一个Before钩子\r\n\t * @param listener\r\n\t * @param scope =false时代表只在本命令执行,=true时代表在本命令及其子命令执行\r\n\t * @returns\r\n\t */\r\n\tbefore(listener: BeforeCommandHookListener, scope: boolean = true) {\r\n\t\tthis._beforeHooks.push([listener, scope]);\r\n\t\treturn this;\r\n\t}\r\n\tprivate async executeBeforeHooks(args: any) {\r\n\t\tconst hooks: [BeforeCommandHookListener, boolean, MixCommand][] = this.beforeHooks.map(\r\n\t\t\t([hook, scope]) => [hook, scope, this]\r\n\t\t);\r\n\t\tthis.getAncestorCommands().forEach((cmd: MixCommand) => {\r\n\t\t\thooks.unshift(\r\n\t\t\t\t...cmd.beforeHooks.map(([hook, scope]) => {\r\n\t\t\t\t\treturn [hook, scope, cmd] as [BeforeCommandHookListener, boolean, MixCommand];\r\n\t\t\t\t})\r\n\t\t\t);\r\n\t\t});\r\n\t\tfor (let [hook, scope, cmd] of hooks) {\r\n\t\t\tif (!scope) continue;\r\n\t\t\tawait hook.call(cmd, args);\r\n\t\t}\r\n\t}\r\n\t/**\r\n\t * 添加一个After钩子\r\n\t * @param listener\r\n\t * @param scope =false时代表只在本命令执行,=true时代表在本命令及其子命令执行\r\n\t * @returns\r\n\t */\r\n\tafter(listener: AfterCommandHookListener, scope: boolean = true) {\r\n\t\tthis._afterHooks.push([listener, scope]);\r\n\t\treturn this;\r\n\t}\r\n\tprivate async executeAfterHooks(args: any) {\r\n\t\tconst hooks: [AfterCommandHookListener, boolean, MixCommand][] = this.afterHooks.map(\r\n\t\t\t([hook, scope]) => [hook, scope, this]\r\n\t\t);\r\n\t\tthis.getAncestorCommands().forEach((cmd: MixCommand) => {\r\n\t\t\thooks.push(\r\n\t\t\t\t...cmd.afterHooks.map(([hook, scope]) => {\r\n\t\t\t\t\treturn [hook, scope, cmd] as [BeforeCommandHookListener, boolean, MixCommand];\r\n\t\t\t\t})\r\n\t\t\t);\r\n\t\t});\r\n\t\tfor (let [hook, scope, cmd] of hooks) {\r\n\t\t\tif (!scope) continue; //=false时不执行\r\n\t\t\tawait hook.call(cmd, args);\r\n\t\t}\r\n\t}\r\n\tprivate async preActionHook(thisCommand: Command, actionCommand: Command) {\r\n\t\tif (this.isEnablePrompts()) {\r\n\t\t\t// 自动生成提示\r\n\t\t\tconst questions: PromptObject[] = [\r\n\t\t\t\t...this.generateAutoPrompts(),\r\n\t\t\t\t...this._customPrompts,\r\n\t\t\t];\r\n\t\t\t// 用户提示\r\n\t\t\tif (questions.length > 0) {\r\n\t\t\t\tconst results = await prompts(questions);\r\n\t\t\t\tObject.entries(results).forEach(([key, value]) => {\r\n\t\t\t\t\tthisCommand.setOptionValue(key, value);\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate isEnablePrompts() {\r\n\t\tif (isEnablePrompts() === false) {\r\n\t\t\t// 命令行参数禁用了提示,优先级最高\r\n\t\t\treturn false;\r\n\t\t} else {\r\n\t\t\treturn this._enable_prompts;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * 生成选项自动提示\r\n\t *\r\n\t * @remarks\r\n\t * FlexCli要求所有未提供默认值的Option自动生成提示\r\n\t *\r\n\t * - 未提供默认值,并且是必选的参数Option\r\n\t * - 指定了choices但未提供有效值的Option\r\n\t *\r\n\t */\r\n\tprivate generateAutoPrompts(): PromptObject[] {\r\n\t\tconst options = this.options as unknown as MixOption[];\r\n\t\tconst optionPromports = options\r\n\t\t\t.filter((option) => !option.hidden && option instanceof MixOption)\r\n\t\t\t.map((option) => option.getPrompt(this._optionValues[option.name()]))\r\n\t\t\t.filter((prompt) => prompt) as PromptObject[];\r\n\t\toutputDebug(\"命令<{}>自动生成{}个选项提示:{}\", [\r\n\t\t\tthis.name(),\r\n\t\t\toptionPromports.length,\r\n\t\t\toptionPromports.map((prompt) => `${prompt.name}(${prompt.type})`).join(\",\"),\r\n\t\t]);\r\n\t\treturn optionPromports;\r\n\t}\r\n\toption(flags: string, description?: string | undefined, defaultValue?: any): this;\r\n\toption(flags: string, description?: string | undefined, options?: MixedOptionParams): this {\r\n\t\t// @ts-ignore\r\n\t\tconst option = new MixOption(...arguments);\r\n\t\tif (option.required && !this.isEnablePrompts()) option.mandatory = true;\r\n\t\treturn this.addOption(option as unknown as Option);\r\n\t}\r\n\r\n\t/**\r\n\t * 添加提示\r\n\t *\r\n\t * @remarks\r\n\t *\r\n\t * 添加一些自定义提示\r\n\t *\r\n\t *\r\n\t * @param questions\r\n\t * @param show 是否显示提示信息,auto表示只有在用户没有提供option的值时才显示提示信息,always表示总是显示提示信息,never表示不显示提示信息\r\n\t * @returns\r\n\t */\r\n\tprompt(questions: PromptObject | PromptObject[]) {\r\n\t\tthis._customPrompts.push(...(Array.isArray(questions) ? questions : [questions]));\r\n\t\treturn this;\r\n\t}\r\n\t/**\r\n\t *\r\n\t * 选择命令并执行\r\n\t *\r\n\t * @remorks\r\n\t *\r\n\t * 当命令具有多个子命令时,并且没有提供默认子命令时,提示用户选择一个子命令\r\n\t *\r\n\t */\r\n\tasync selectCommands() {\r\n\t\tconst choices = this.commands.map((command) => ({\r\n\t\t\ttitle: `${command.description()}(${command.name()})`,\r\n\t\t\tvalue: command.name(),\r\n\t\t}));\r\n\t\tconst result = await prompts({\r\n\t\t\ttype: \"select\",\r\n\t\t\tname: \"command\",\r\n\t\t\tmessage: \"请选择命令:\",\r\n\t\t\tchoices,\r\n\t\t});\r\n\t\t// 重新解析命令行参数标志,\r\n\t\tconst command = this.commands.find((command) => command.name() === result.command);\r\n\t\tawait command?.parseAsync([result.command], { from: \"user\" });\r\n\t}\r\n\t/**\r\n\t * 禁用/启用所有提示\r\n\t */\r\n\tdisablePrompts() {\r\n\t\tthis._enable_prompts = false;\r\n\t\treturn this;\r\n\t}\r\n\tenablePrompts() {\r\n\t\tthis._enable_prompts = true;\r\n\t\treturn this;\r\n\t}\r\n}\r\n","import { Option } from 'commander'\nimport { PromptObject } from 'prompts'\nimport { IPromptable, IPromptableOptions, PromptChoice, PromptManager } from './prompt'\n\n\nexport interface MixedOptionParams extends IPromptableOptions{\n hidden?:boolean\n defaultDescription?:string // 默认值的描述 \n conflicts?:string | string[]\n env?:string\n argParser?:<T>(value: string, previous: T) => T \n hideHelp?:boolean\n mandatory?: boolean \n implies?:{[key:string]:any} \n}\n\n\nexport class MixOption extends Option implements IPromptable{\n // 是否提示用户输入\n prompt?: PromptManager \n promptChoices?:PromptChoice[]\n private _validate?: (value: any) => boolean \n constructor(flags: string, description?: string | undefined,optsOrDefault?:any) {\n super(flags, description)\n let params:MixedOptionParams = {}\n if(arguments.length==3 && typeof arguments[2] == \"object\"){\n params = Object.assign({ },arguments[2]) \n }else if(arguments.length==3){\n params.default = arguments[2]\n }\n if(params.prompt===undefined) params.prompt = 'auto'\n if(params.default) this.default(params.default,params.defaultDescription)\n if(params.choices) this.choices(params.choices)\n if(params.conflicts) this.conflicts(params.conflicts)\n if(params.env) this.env(params.env)\n if(params.argParser) this.argParser(params.argParser)\n if(params.hideHelp) this.hideHelp(params.hideHelp)\n if(params.hidden) this.hidden = params.hidden\n if(params.mandatory) this.makeOptionMandatory(params.mandatory)\n if(params.implies) this.implies(params.implies) \n if(params.optional) this.optional=params.optional\n if(typeof(params.validate)=='function') this._validate = params.validate.bind(this)\n if(params.required) {\n this.required = params.required\n if(!this._validate ) this._validate = (value:any)=>String(value).length>0\n }\n this.prompt = new PromptManager(this as IPromptable,params.prompt)\n } \n validate(value: any): boolean {\n if(typeof(this._validate)=='function'){\n return this._validate(value)\n }else{\n return true\n }\n }\n // @ts-ignore\n choices(values:(PromptChoice | string)[]){\n if(!this.promptChoices){\n this.promptChoices = values.map(choice=>{\n if(typeof(choice)=='object'){\n return choice\n }else{\n return {title:choice,value:choice} \n }\n })\n } \n super.choices(this.promptChoices.map((item:any)=>item.value)) \n } \n\n private resetChoices(){\n super.choices(this.promptChoices!.map((item:any)=>item.value)) \n }\n\n addChoice(value:PromptChoice | string){\n if(!this.promptChoices || !Array.isArray(this.promptChoices)) this.promptChoices = []\n this.promptChoices!.push(typeof(value)=='string' ? {title:value,value} : value)\n this.resetChoices()\n }\n removeChoice(value:any){\n this.promptChoices =this.promptChoices?.filter(choice=>choice.value!==value)\n this.resetChoices()\n }\n clearChoice(){\n this.promptChoices = []\n this.resetChoices()\n }\n\n \n /**\n * 返回选项的提示对象\n * \n * @remarks\n * \n *\n * \n * @param inputValue \n * @returns \n */\n getPrompt(inputValue?:any): PromptObject | undefined {\n return this.prompt?.get(inputValue)\n } \n}","import artTemplate from \"art-template\"\r\nimport fs from \"fs-extra\"\r\nimport path from \"node:path\"\r\nimport { promisify } from \"flex-tools/func/promisify\"\r\nimport logsets from \"logsets\" \r\n/**\r\n * \r\n * 在控制台输出一个字符串\r\n * 本方法会将字符串中的每一行空格去掉\r\n * \r\n * @remarks\r\n * \r\n * outputStr(String.raw`\r\n * a\r\n * b`)\r\n * \r\n * 会输出\r\n * a\r\n * b\r\n *\r\n * 此功能可以用于输出多行字符串时,保持代码的缩进格式,而不会影响输出结果\r\n * \r\n * @param str : 要输出的字符串\r\n * @param vars : 用于替换字符串中的变量\r\n * \r\n */\r\nexport function outputStr(str:string,vars?:Record<string,any> | any[]){ \r\n logsets.log(fixIndent(str),vars)\r\n}\r\n\r\n/**\r\n * 修正多行字符串的缩进\r\n * \r\n * @param text \r\n * @param indent \r\n * @returns \r\n */\r\nexport function fixIndent(text:string,indent?:boolean | number):string{\r\n let indentValue = (indent==undefined || indent===true) ? 0 : (typeof(indent)=='number' ? indent : -1)\r\n if(indentValue==-1) return text // 不修正缩进\r\n let lines:string[] = text.split(\"\\n\")\r\n let minSpaceCount = lines.reduce<number>((minCount,line,index)=>{\r\n if(index==0) return minCount\r\n const spaceCount = line.match(/^\\s*/)?.[0].length || 0\r\n return Math.min(minCount,spaceCount)\r\n },9999)\r\n lines = lines.map(line=>line.substring(minSpaceCount))\r\n return lines.join(\"\\n\")\r\n}\r\n\r\n/**\r\n * 增加内置选项\r\n * @param command \r\n */\r\nexport function addBuiltInOptions(command:any){ \r\n command.option(\"--work-dirs <values...>\",\"指定工作目录\",{hidden:true,optional:true,required:true,prompt:false})\r\n command.option(\"--disable-prompts\",\"禁用所有交互提示\",{hidden:true,prompt:false}) \r\n command.option(\"--debug-cli\",\"显示调试信息\",{hidden:true,prompt:false})\r\n}\r\n\r\n\r\n/**\r\n * 是否命令行中包含了--debug-cli选项\r\n */\r\nexport function isDebug(){\r\n return process.argv.includes(\"--debug-cli\")\r\n}\r\nexport function isEnablePrompts(){ \r\n return !process.argv.includes(\"--disable-prompts\")\r\n}\r\n\r\n/**\r\n * 打印调试信息\r\n * @param message \r\n * @param args \r\n */\r\nexport function outputDebug(message:string,...args:any[]){ \r\n let vars = (args.length == 1 && typeof(args[0])=='function') ? args[0]() : args\r\n if(isDebug()) logsets.log(`[MixCli] ${message}`,...vars)\r\n}\r\n\r\nexport const fileExists = promisify(fs.exists,{\r\n parseCallback:(results)=>{\r\n return results[0]\r\n }\r\n})\r\nexport const readFile = promisify(fs.readFile)\r\nexport const writeFile = promisify(fs.writeFile)\r\nexport const mkdir = promisify(fs.mkdir)\r\n\r\n/**\r\n * 基于artTemplate模板生成文件\r\n * \r\n * @param {*} tmplFile \r\n * @param {*} vars \r\n */\r\nexport async function createFileByTemplate(targetFile:string,tmplFile:string,vars:Record<string,any>={}){\r\n tmplFile=path.isAbsolute(tmplFile)? tmplFile : path.join(process.cwd(),tmplFile)\r\n if(!fs.existsSync(tmplFile)){\r\n throw new Error(\"模板文件不存在:\"+tmplFile)\r\n }\r\n targetFile=path.isAbsolute(targetFile)? targetFile : path.join(process.cwd(),targetFile)\r\n const outPath = path.dirname(targetFile)\r\n if(!await fileExists(outPath)){\r\n await mkdir(outPath,{recursive:true})\r\n } \r\n const template = artTemplate(tmplFile,await readFile(tmplFile,{encoding:\"utf-8\"})); \r\n await writeFile(targetFile,template(vars),{encoding:\"utf-8\"})\r\n return targetFile\r\n}\r\n\r\n/** \r\n * 创建目录 \r\n * \r\n * \r\n * \r\n * @param {String[]} dirs 要创建的目录列表,类型为字符串数组 \r\n * @param callback 创建目录过程中的回调函数,类型为异步函数,接收一个参数 dir,表示当前正在创建的目录 \r\n * @returns 该函数返回一个 Promise 对象,表示创建目录的操作是否完成 \r\n */\r\nexport async function mkDirs(dirs:string[],{callback,base}:{callback?:Function,base?:string}){\r\n if(!Array.isArray(dirs)) throw new Error(\"dirs参数必须为字符串数组\")\r\n for(let dir of dirs){\r\n if(!path.isAbsolute(dir)) dir = path.join(base || process.cwd(),dir)\r\n if(typeof(callback)=='function') callback(dir)\r\n await mkdir(dir,{recursive:true})\r\n }\r\n}\r\n\r\nexport function showError(e:any){\r\n if(isDebug()){\r\n outputDebug(\"导入命令<>出错:{}\",e.stack)\r\n }else{\r\n console.error(e)\r\n } \r\n\r\n}\r\n\r\n\r\nexport function getId(){\r\n return Math.random().toString(36).substr(2)\r\n}\r\n\r\n\r\nexport async function importModule(file:string){\r\n let module \r\n try{\r\n module = require(file)\r\n }catch(e:any){\r\n try{\r\n const cmd = await import(`file://${file}`)\r\n module = cmd.default\r\n }catch(e:any){\r\n throw e\r\n } \r\n }\r\n return module\r\n}\r\n","import { PromptObject } from \"prompts\" \nimport { outputDebug } from \"./utils\"\n \n\nexport type PromptType = \"text\" | \"password\" | \"invisible\" | \"number\"| \"confirm\"| \"list\"| \"toggle\"| \"select\" | \"multiselect\" | \"autocomplete\" | \"date\" | \"autocompleteMultiselect\"\n\nexport type PromptParam = 'auto' | boolean | PromptType | PromptObject\nexport type InputPromptParam = PromptParam | ((value:any)=>PromptParam) | boolean\nexport type PromptParamDefaultValue = string | boolean | string[] \n\nexport const promptTypeMap:Record<string,string> = {\n boolean:\"confirm\",\n string:\"text\",\n number:\"number\", \n array:\"list\", \n} \n\nexport const supportedPromptTypes = [\"text\",\"password\",\"invisible\", \"number\", \"confirm\" , \"list\", \"toggle\" , \"select\" , \"multiselect\" , \"autocomplete\" , \"date\" , \"autocompleteMultiselect\"]\nexport interface PromptChoice {\n title: string;\n value?: any;\n disabled?: boolean | undefined;\n selected?: boolean | undefined;\n description?: string | undefined;\n}\n\n\n\nexport interface IPromptableOptions{\n required?: boolean; // A value must be supplied when the option is specified.\n optional?: boolean; // A value is optional when the option is specified.\n default?:PromptParamDefaultValue\n choices?:(PromptChoice | any)[] // 选项值的可选值\n prompt?:InputPromptParam\n validate?:(value: any) => boolean\n}\n\n\nexport interface IPromptable{\n name():string \n description?:string\n flags:string\n promptChoices?:PromptChoice[]\n argChoices?:string[]\n variadic?:boolean\n defaultValue?:PromptParamDefaultValue\n input?:any \n required?:boolean\n validate?: (value: any) => boolean \n getPrompt(inputValue?:any):PromptObject | undefined \n}\n\n/**\n * 供command.option()使用的参数对象\n */\nexport interface PromptableObject{\n \n\n}\n\n\n/**\n * 负责生成prompt对象\n * \n */\nexport class PromptManager{\n args:InputPromptParam \n private _promptable:IPromptable // 对应的FlexOption或FlexArgument\n constructor(promptable:IPromptable,promptArgs?:InputPromptParam){ \n this._promptable = promptable\n this.args= promptArgs===undefined ? 'auto' : promptArgs\n }\n\n /**\n * 返回输入的是否是有效的prompt类型\n * @param type \n * @returns \n */\n isValid(type:any){\n return supportedPromptTypes.includes(String(type))\n }\n /**\n * 推断是否需要提示\n * \n */\n isNeed(input:any,defaultValue?:any){\n \n const promptArg = this.args\n const inputValue = input || defaultValue\n // 是否有输入值,即在命令行输入了值\n const hasInput = !(inputValue === undefined)\n // 1. 显式指定了_prompt为true,则需要提示,后续进行提示类型的推断,可能不会准确\n if(promptArg===true) return true\n if(promptArg===false) return false \n\n // 2. 提供了一个prompt对象,并且没有在命令行输入值,则需要提示\n if(typeof(promptArg)=='object'){\n return !hasInput\n }\n\n // 3. 指定了内置的prompt类型,如prompt='password',则使用password类型提示输入\n if(typeof(promptArg) == 'string' && supportedPromptTypes.includes(promptArg)){\n return !hasInput\n }\n \n // 4. 判断输入是否有效,则显示提示\n if(this._promptable.argChoices && this._promptable.argChoices.indexOf(inputValue) == -1){\n return true\n } \n return !hasInput\n }\n /**\n * 返回生成prompt对象\n * \n * @param inputValue 从命令行输入的值\n */\n get(inputValue?:any){\n const {description,promptChoices,validate,defaultValue} = this._promptable\n let input = inputValue || defaultValue\n // 判断是否需要输入提示\n if(!this.isNeed(input,defaultValue)) return\n // 推断prompt类型\n let promptType = this.infer(inputValue)\n const prompt = {\n type:promptType, \n name:this._promptable.name(),\n message:description,\n initial: input,\n ...typeof(this.args) == 'object' ? this.args : {}\n } as PromptObject\n // 指定了验证函数,用来验证输入值是否有效\n prompt.validate = validate?.bind(this._promptable)\n if(promptType=='multiselect') prompt.instructions=false\n if(['select','multiselect'].includes(promptType)){\n let index = promptChoices?.findIndex(item=>item.value==input)\n prompt.initial = index==-1 ? undefined : index\n } \n // 选项值的可选值\n if(Array.isArray(promptChoices)) {\n prompt.choices =promptChoices\n }\n return prompt\n }\n /**\n * 推断prompt类型\n * \n * @param inputValue 从命令行输入的值\n */\n infer(inputValue?:any){\n const {argChoices,variadic,defaultValue} = this._promptable\n let input = inputValue || defaultValue\n // 如果选择指定了\"-p [value]或[value...]\",则使用text类型,如果没有要求输入值,则使用confirm类型\n let promptType = /(\\<[\\w\\.]+\\>)|(\\[[\\w\\.]+\\])/.test(this._promptable.flags) ? 'text' : 'confirm'\n let promptArg = this.args\n if(this.isValid(promptArg)){ // 显式指定了prompt类型\n promptType = promptArg as string\n }else{ // 未显式指定prompt类型,需要按一定规则推断类型\n if(typeof(promptArg)=='object'){\n promptType = promptArg.type as string\n }else{\n if(argChoices){ // 提供多个可选值时\n promptType = variadic ? 'multiselect' : 'select'\n }else{\n const datatype:string = Array.isArray(defaultValue) ? 'array' : typeof(defaultValue) \n // 如果输入值班是数组,则使用list类型,允许使用逗号分隔的多个值\n if(Array.isArray(input) || variadic){\n promptType = \"list\"\n }else{\n if(datatype in promptTypeMap){\n promptType = promptTypeMap[datatype]\n }\n }\n }\n }\n }\n outputDebug(\"选项<{}> -> 提示类型<{}>\",[this._promptable.name(),promptType])\n return promptType\n }\n\n}","import { getPackageJson } from \"flex-tools/package/getPackageJson\"\r\nimport { getPackageRootPath } from 'flex-tools/package/getPackageRootPath';\r\nimport type { MixCli } from './cli';\r\nimport { globSync } from 'glob'\r\nimport { MixCliCommand } from './cli';\r\nimport { importModule, isDebug, outputDebug } from './utils';\r\nimport fs from \"node:fs\"\r\nimport path from \"node:path\"\r\n\r\n\r\n/**\r\n * \r\n * 在当前工程中查找符合FlexCli.prefix约定的命令 \r\n * \r\n * - 读取当前包的package.json\r\n * - 找出所有以cli.prefix开头的依赖\r\n * - 加载这些依赖的目录下的匹配cli.pattern的命令\r\n * - 加载加载这样命令\r\n * \r\n */\r\n \r\n\r\nexport function getMatchedDependencies(this:MixCli,entry:string):string[]{\r\n const pacakgeMacher = this.options.include\r\n if(!(pacakgeMacher instanceof RegExp)) return []\r\n \r\n // 找出当前包的所有依赖\r\n const { dependencies={},devDependencies={},peerDependencies={},optionalDependencies={},bundleDependencies={} } = getPackageJson(entry)\r\n const packageNames = [\r\n ...Object.keys(dependencies),\r\n ...Object.keys(devDependencies),\r\n ...Object.keys(peerDependencies),\r\n ...Object.keys(optionalDependencies),\r\n ...Object.keys(bundleDependencies)\r\n ]\r\n return packageNames.filter(name=>name!==\"@voerka/cli\" && pacakgeMacher.test(name))\r\n}\r\n\r\nfunction isMatched(str:string,reg?:string | RegExp | string[] | RegExp[]):boolean{\r\n // let regexps:RegExp[]=[]\r\n const regexps = reg ? (Array.isArray(reg) ? reg : [reg]) : []\r\n return regexps.some(regexp=>{\r\n if(typeof regexp === \"string\"){\r\n return (new RegExp(regexp)).test(str)\r\n }else if(regexp instanceof RegExp){\r\n return regexp.test(str)\r\n }else{\r\n return false\r\n }\r\n })\r\n}\r\n\r\nexport function findCliPaths(this:MixCli,packageName?:string ,entry?:string):string[]{\r\n const includeMacher = this.options.include\r\n const excludeMacher = this.options.exclude\r\n if(!includeMacher) return []\r\n const packageRoot = getPackageRootPath(entry || process.cwd())\r\n const packagePath = packageName ? path.dirname(require.resolve(packageName,{paths:[packageRoot as string]})) : packageRoot\r\n\r\n if(!packagePath) {\r\n outputDebug(\"MixCli只能运行在Nodejs环境\" )\r\n return []\r\n }\r\n\r\n // 找出当前包的所有依赖\r\n const packageNames = getMatchedDependencies.call(this,packagePath)\r\n\r\n const cliDirs:string[]=[]\r\n \r\n if(entry!==undefined) cliDirs.push(path.join(packagePath,this.options.cliDir))\r\n packageNames.filter(name=>{\r\n return isMatched(name,includeMacher) && !isMatched(name,excludeMacher) \r\n })\r\n .forEach(name=>{\r\n outputDebug(\"匹配包:{}\",`${packageName ? name+\" <- \"+packageName : name}`)\r\n try{\r\n const packageEntry = path.dirname(require.resolve(name,{paths:packagePath ? [packagePath] : [process.cwd()]}))\r\n const packageCliDir =path.join(packageEntry,this.options.cliDir!) \r\n // 查找当前包的所属工程的依赖\r\n let dependencies = getMatchedDependencies.call(this,packageEntry)\r\n cliDirs.push(...dependencies.reduce<string[]>((result,dependencie)=>{\r\n outputDebug(\"匹配包:{}\",`${dependencie} <- ${name}`)\r\n result.push(...findCliPaths.call(this,dependencie,packageEntry))\r\n return result\r\n },[])) \r\n if(fs.existsSync(packageCliDir)){\r\n cliDirs.push(packageCliDir)\r\n }\r\n }catch(e:any){\r\n outputDebug(\"解析包<{}>路径出错:{}\",[name,e.stack])\r\n } \r\n })\r\n // 由于一些包可能存在循环依赖,所以需要去重\r\n return [...new Set(cliDirs)]\r\n}\r\n\r\n\r\n/**\r\n * \r\n * 扫描当前工程中所有符合条件的命令\r\n * \r\n * @param cli \r\n * \r\n */\r\nexport async function findCommands(cli:MixCli){ \r\n const cliDirs = findCliPaths.call(cli)\r\n const commands:MixCliCommand[] = []\r\n const files = [] as string[]\r\n cliDirs.forEach(dir=>{\r\n globSync(\"*\",{\r\n cwd:dir,\r\n absolute :true \r\n }).forEach((file:string)=>{ \r\n const baseName = path.basename(file) \r\n if(baseName.startsWith(\"_\")) return\r\n const ext = path.extname(file).toLowerCase()\r\n if([\".js\",\".cjs\",\".mjs\"].includes(ext)){\r\n files.push(file)\r\n }else if(fs.statSync(file).isDirectory()){\r\n files.push(path.join(file,\"index.js\"))\r\n files.push(path.join(file,\"index.cjs\"))\r\n files.push(path.join(file,\"index.mjs\"))\r\n }\r\n })\r\n })\r\n for(let file of files){ \r\n if(!fs.existsSync(file)) continue\r\n try{\r\n outputDebug(\"导入命令:{}\",file)\r\n if(file.endsWith(\".cjs\") || file.endsWith(\".js\")){\r\n commands.push(await importModule(file))\r\n }else if(file.endsWith(\".mjs\")){\r\n const cmd = await import(`file://${file}`)\r\n commands.push(cmd.default)\r\n } \r\n }catch(e:any){\r\n outputDebug(e) \r\n }\r\n }\r\n return commands\r\n}\r\n\r\n"],"mappings":"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","names":["logsets","e","path","fs","path","fs","command","fs","path","path","fs","logsets","cmd"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/command.ts","../src/option.ts","../src/utils.ts","../src/prompt.ts","../src/finder.ts"],"sourcesContent":["#!/usr/bin/env node\nimport \"flex-tools/string\"\nimport { LiteEvent, LiteEventSubscriber } from \"flex-tools/events/liteEvent\"\nimport { Command } from \"commander\"\nimport logsets from \"logsets\"\n\nimport { assignObject } from \"flex-tools/object/assignObject\"\nimport { MixCommand } from \"./command\"\nimport { addBuiltInOptions, fixIndent, outputDebug } from './utils';\nimport { findCommands } from \"./finder\"\nimport { asyncSignal } from \"flex-tools/async/asyncSignal\"\n// @ts-ignore\nimport replaceAll from 'string.prototype.replaceall' \nreplaceAll.shim() \n\nexport interface MixCliOptions{\n name:string,\n title?:string | (string | boolean | number)[],\n description?:string,\n version?:string\n // 定义显示帮助信息\n logo?:string ,\n // 在根命令执行前执行==commander的preAction\n before?:(thisCommand:Command,actionCommand:Command)=>void,\n // 在根命令执行后执行==commander的postAction\n after?:(thisCommand:Command,actionCommand:Command)=>void, \n // flexcli运行时会在当前工程的package.json的依赖中查找以prefix/开头的包,然后自动加载其cli目录下的命令\n // 例如:prefix=myapp,则会自动加载flex-cli-xxx包中的cli目录下的命令\n // 如prefix=myapp, cliPath=\"cmds\",则会自动加载flex-cli-xxx包中的cmds目录下的命令\n include?:string | RegExp | string[] | RegExp[],\n // 忽略查找正则表达式\n exclude?:string | RegExp | string[] | RegExp[],\n // flexcli会在当前工程的以prefix/开头下查找命令声明\n // / pattern默认值是cli,即会在当前工程的以prefix/开头的包下查找cli目录下的命令\n // 指定cli所在的目录,默认值是cli,要遍历该目录下的所有js文件作为命令导出\n cliDir?:string \n context?:Record<string,any> // 传递给命令的共享上下文,所有命令均可要使用 \n // 默认是否启用交互提示, auto当没有值时,会根据当前是否在终端中运行来决定是否启用交互提示\n // 为false时,禁用所有交互提示,为true时,启用所有交互提示 \n prompt?:'auto' | boolean \n ignoreError?:boolean\n}\n\n \n \n\nexport type MixCliCommand = (cli:MixCli)=>MixCommand | MixCommand[] | void\n\n\nexport type MixCliEvents = \n \"register\" // 当命令注册时触发\n\nexport class MixCli extends LiteEvent<any,MixCliEvents>{\n options:Required<MixCliOptions> \n root!:Command \n private findSignals:any[]=[]\n constructor(options?:MixCliOptions){\n super()\n this.options= assignObject({\n name:\"mixcli\",\n package:null,\n cliDir:\"cli\",\n prompt:'auto',\n ignoreError:false\n },options) as Required<MixCliOptions> \n this.createRootCommand() \n } \n get context(){return this.options.context}\n get name(){return this.options.name}\n /**\n * 是否禁用了所有的交互提示\n */\n get isDisabledPrompts(){\n return(this.root as any).rawArgs.includes(\"--no-prompts\") \n } \n /**\n * 扫描当前工程的依赖,加载匹配include的依赖下的命令\n */\n private async installCommands(){\n const cmders = await findCommands(this)\n for(let cmder of cmders){\n try{\n if(typeof(cmder)===\"function\"){\n let cmds = cmder(this)\n cmds = cmds ? (Array.isArray(cmds) ? cmds : [cmds]) : []\n this.register(()=>cmds) \n }\n }catch(e:any){\n outputDebug(\"注册命令失败:{}\",e.stack)\n }\n }\n } \n /**\n * 创建根命令\n * \n */\n private createRootCommand(){\n this.root = new MixCommand(this.name);\n this.root \n .helpOption('-h, --help')\n .action(()=>{ \n if(this.options.logo) logsets.log(fixIndent(this.options.logo,2))\n console.log()\n // 显示标题\n let title = this.options.title|| this.options.name\n if(Array.isArray(title)){\n logsets.log(String(title[0]).firstUpper(),[...title.slice(1)])\n }else{\n logsets.log(`${title.firstUpper()} Version: {}`,this.options.version)\n } \n // @ts-ignore\n if(this.options.description) logsets.log(logsets.colors.darkGray(this.options.description)) \n console.log()\n this.root.help() \n }) \n addBuiltInOptions(this.root)\n if(this.options.before) this.root.hook('preAction',this.options.before)\n if(this.options.after) this.root.hook('postAction',this.options.after) \n } \n /**\n * 添加帮助选项\n * \n * @param text 帮助文本\n * @param position 显示位置,可选值:before|after|beforeAll|afterAll\n * @param fixIndent 是否自动修正缩进,如果为true,则会自动修正缩进,当显示多行时文本时,会自动修正缩进\n * \n */\n public addHelp(text:string,{pos='beforeAll',alignIndent=true}:{pos:'before'|'after' | 'beforeAll' | 'afterAll',alignIndent?:boolean | number}){\n if(alignIndent) text = fixIndent(text,alignIndent)\n this.root.addHelpText(pos,text)\n }\n\n /**\n * 注册一个命令\n * @param cmd \n */\n register(cmd:MixCliCommand){\n if(typeof(cmd)==\"function\"){\n let result = cmd(this)\n let cmds = result instanceof Array ? result : (result==undefined ? [] : [result])\n for(let cmd of cmds){\n // 为什么不用cmd instanceof MixCommand来判断是否是一个有效的命令?\n // 因为当不同的包引用了与主包不一样版本的mixcli时,判断会失效,导致不能识别\n // 所以我们通过cmd.__MIX_COMMAND__来判断是否是一个有效的命令\n if(cmd.__MIX_COMMAND__){ \n if(this.hasCommand(cmd.name())){\n logsets.error(`Command <${cmd.name()}> has been registered!`)\n }else{\n outputDebug(\"注册命令:{}\",cmd.fullname)\n this.root.addCommand(cmd) ;\n (cmd as any)._cli = this\n this.emit(\"register\",cmd.fullname,true)\n } \n }else{\n logsets.error(`Command <${cmd.toString()}> is not a valid command!`)\n }\n } \n }else{\n logsets.error(\"Invalid command\")\n } \n }\n\n hasCommand(name:string):boolean{\n return this.root.commands.some(c=>c.name()==name)\n }\n\n /**\n * 根据命令名称查找命令\n * \n * @remarks\n * \n * find(\"dev\")\n * find(\"dev.microservice\") 支持多级命令\n * find(\"abc\",DevCommand) 允许指定从DevCommand下开始查找abc命令\n * \n * @param name \n */\n get(name:string):MixCommand | undefined{\n const names=name.split(\".\")\n let curCmd:Command = this.root\n let resultCmd:MixCommand | undefined\n while(names.length>0){\n const topName = names.shift()\n const r = curCmd.commands.find(c=>c.name()==topName) as MixCommand\n if(r && names.length==0){\n resultCmd = r\n }\n curCmd = r\n } \n return resultCmd \n }\n /**\n * 查找一个命令\n * \n * 如果命令不存在,则等待命令注册后再返回\n * \n * 在多包场景下,如果命令在其他包中注册并且该包中的命令还没注册,则会等待命令注册后再返回\n * \n * @param name \n * @returns \n */\n find(name:string):Promise<MixCommand | undefined>{\n const cmd = this.get(name)\n if(cmd){\n return Promise.resolve(cmd) \n }else{\n const signal = asyncSignal()\n this.findSignals.push(signal)\n return new Promise<MixCommand | undefined>((resolve)=>{\n let listener:LiteEventSubscriber\n listener = this.on(\"register\",(fullname:string)=>{\n if(fullname==`${this.name}.${name}`){\n listener.off()\n signal.resolve()\n this.findSignals = this.findSignals.filter(s=>s!=signal)\n resolve(this.get(name))\n }\n },{objectify:true}) as LiteEventSubscriber\n })\n } \n }\n /**\n * 判断命令是否存在\n * \n * @param name \n * @returns \n */\n exists(name:string):boolean{\n if(name in this.root.commands){\n return true\n }else{\n return this.get(name) != undefined\n }\n } \n \n /**\n * 运行命令行程序\n */\n run(){ \n // 为什么有findSignal这玩意,解决什么问题?\n // 当我们要扩展command时,通过get(\"命令名称\")来获取已经注册的命令的方式有个缺陷\n // 就是如果对命令的注册顺序有严格的要求,比如调用get('dev')时要求dev命令必须已经存在\n // 这对动态包的命令注册扩展开发体验不好\n // 所以引入find(\"命令名称\")来获取命令,该方法可以获取到后注册的命令\n // 其副作用是,在run时,可能find还没有运行到,从而导致在帮助信息里面看不到扩展的信息(实际上是已经生效的)\n // 所以我们在find里面注入一个异步信号来解决此问题\n this.installCommands().then(()=>{\n return Promise.all(this.findSignals.map(signal=>signal(10000))).then(()=>{\n this.root.parseAsync(process.argv); \n })\n }) \n }\n /**\n * 创建一个命令\n * \n * \n */\n create(){\n } \n}\n ","import { Command, Option } from \"commander\";\r\nimport prompts, { PromptObject } from \"prompts\";\r\nimport { MixOption, type MixedOptionParams } from \"./option\";\r\nimport { addBuiltInOptions, isEnablePrompts, outputDebug } from \"./utils\";\r\nimport path from \"node:path\";\r\nimport fs from \"node:fs\";\r\nimport type { AsyncFunction } from \"flex-tools\";\r\n\r\nexport type ICommandHookListener = ({\r\n\targs,\r\n\toptions,\r\n\tcommand,\r\n}: {\r\n\targs: any[];\r\n\toptions: Record<string, any>;\r\n\tcommand: MixCommand;\r\n}) => void | Promise<void>;\r\n\r\nexport type BeforeCommandHookListener = ({\r\n\targs,\r\n\toptions,\r\n\tcommand,\r\n}: {\r\n\targs: any[];\r\n\toptions: Record<string, any>;\r\n\tcommand: MixCommand;\r\n}) => void | Promise<void>;\r\nexport type AfterCommandHookListener = ({\r\n\tvalue,\r\n\targs,\r\n\toptions,\r\n\tcommand,\r\n}: {\r\n\tvalue: any;\r\n\targs: any[];\r\n\toptions: Record<string, any>;\r\n\tcommand: MixCommand;\r\n}) => void | Promise<void>;\r\n\r\nexport interface ActionOptions {\r\n\tid: string;\r\n\tat: \"replace\" | \"before\" | \"after\" | \"preappend\" | \"append\" | number;\r\n\t// 函数签名类型,即采用原始的commander的action函数签名,还是mixcli的action函数签名\r\n\tenhance: boolean;\r\n}\r\n\r\nexport interface ActionRegistry extends Omit<ActionOptions, \"at\"> {\r\n\tfn: Function;\r\n}\r\n\r\n// 原始的Action动作函数\r\nexport type OriginalAction = (...args: any[]) => void | Promise<void>;\r\n// 增强的Action函数签名\r\nexport type EnhanceAction = ({\r\n\targs,\r\n\toptions,\r\n\tvalue,\r\n\tcommand,\r\n}: {\r\n\targs: any[];\r\n\toptions: Record<string, any>;\r\n\tvalue: any;\r\n\tcommand: MixCommand;\r\n}) => void | Promise<any>;\r\n\r\n// 执行action的返回结果\r\nexport const BREAK = Symbol(\"BREAK_ACTION\"); // 中止后续的action执行\r\n\r\nexport class MixCommand extends Command {\r\n\t__MIX_COMMAND__ = true;\r\n\tprivate _beforeHooks: [BeforeCommandHookListener, boolean][] = [];\r\n\tprivate _afterHooks: [AfterCommandHookListener, boolean][] = [];\r\n\tprivate _customPrompts: PromptObject[] = [];\r\n\tprivate _optionValues: Record<string, any> = {}; // 命令行输入的选项值\r\n\tprivate _actions: ActionRegistry[] = []; // 允许多个action\r\n\tprivate _enable_prompts: boolean = true; // 是否启用交互提示\r\n\tconstructor(name?: string) {\r\n\t\tsuper(name);\r\n\t\tconst self = this;\r\n\t\tif (!this.isRoot) addBuiltInOptions(this);\r\n\t\tthis.hook(\"preAction\", async function (this: any) {\r\n\t\t\tself._optionValues = self.getOptionValues(this.hookedCommand);\r\n\t\t\ttry {\r\n\t\t\t\t// @ts-ignore\r\n\t\t\t\tawait self.preActionHook.apply(self, arguments);\r\n\t\t\t} catch {}\r\n\t\t});\r\n\t}\r\n\t/**\r\n\t * 是否是根命令\r\n\t */\r\n\tget isRoot() {\r\n\t\treturn !!!this.parent;\r\n\t}\r\n\tget actions() {\r\n\t\treturn this._actions;\r\n\t}\r\n\tget beforeHooks() {\r\n\t\treturn this._beforeHooks;\r\n\t}\r\n\tget afterHooks() {\r\n\t\treturn this._afterHooks;\r\n\t}\r\n\tget fullname() {\r\n\t\tlet names = [this.name()];\r\n\t\tlet parent = this.parent;\r\n\t\twhile (parent) {\r\n\t\t\tif (parent.name() !== \"root\") {\r\n\t\t\t\tnames.unshift(parent.name());\r\n\t\t\t}\r\n\t\t\tparent = parent.parent;\r\n\t\t}\r\n\t\treturn names.join(\".\");\r\n\t}\r\n\r\n\t/**\r\n\t * 返回根命令\r\n\t */\r\n\troot() {\r\n\t\tlet root: MixCommand | null | undefined = this;\r\n\t\twhile (root && root.parent != null) {\r\n\t\t\troot = root.parent as unknown as MixCommand;\r\n\t\t}\r\n\t\treturn root;\r\n\t}\r\n\taction(fn: EnhanceAction, options: ActionOptions): this;\r\n\taction(fn: OriginalAction): this;\r\n\taction(fn: OriginalAction): this {\r\n\t\tconst actionFunc = arguments[0];\r\n\t\tif (arguments.length == 1 && typeof actionFunc == \"function\") {\r\n\t\t\t// 原始方式\r\n\t\t\tthis._actions.push({\r\n\t\t\t\tid: Math.random().toString(36).substring(2),\r\n\t\t\t\tenhance: false,\r\n\t\t\t\tfn: actionFunc,\r\n\t\t\t});\r\n\t\t} else if (\r\n\t\t\targuments.length == 2 &&\r\n\t\t\ttypeof actionFunc == \"function\" &&\r\n\t\t\ttypeof arguments[1] == \"object\"\r\n\t\t) {\r\n\t\t\t// 增强模式\r\n\t\t\tconst actionFn = arguments[0];\r\n\t\t\tconst actionOpts: ActionOptions = Object.assign({ at: \"append\" }, arguments[1]);\r\n\t\t\tif (actionOpts.at == \"replace\") this._actions = [];\r\n\t\t\tconst actionItem = {\r\n\t\t\t\tid: actionOpts.id || Math.random().toString(36).substring(2),\r\n\t\t\t\tenhance: actionOpts.enhance == undefined ? true : actionOpts.enhance,\r\n\t\t\t\tfn: actionFn,\r\n\t\t\t} as const;\r\n\t\t\tif (typeof actionOpts.at == \"number\") {\r\n\t\t\t\tthis._actions.splice(Number(actionOpts.at), 0, actionItem);\r\n\t\t\t} else if ([\"append\", \"before\"].includes(actionOpts.at)) {\r\n\t\t\t\tthis._actions.push(actionItem);\r\n\t\t\t} else if ([\"preappend\", \"after\"].includes(actionOpts.at)) {\r\n\t\t\t\tthis._actions.splice(0, 0, actionItem);\r\n\t\t\t} else {\r\n\t\t\t\tthis._actions.push(actionItem);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tconsole.log(\"[mixcli] action params error\");\r\n\t\t}\r\n\t\treturn super.action(this.getWrapperedAction());\r\n\t}\r\n\r\n\t/**\r\n\t * 读取命令配置值,包括父命令提供的配置选项\r\n\t * @param command\r\n\t */\r\n\tprivate getOptionValues(command: Command) {\r\n\t\tlet opts = {};\r\n\t\tlet parent: Command | null = command;\r\n\t\twhile (parent) {\r\n\t\t\tObject.assign(opts, (parent as MixCommand)._optionValues);\r\n\t\t\tparent = parent.parent;\r\n\t\t}\r\n\t\treturn opts;\r\n\t}\r\n\t/**\r\n\t * 本函数在运行时子类进行action生成该命令的action\r\n\t */\r\n\tprivate getWrapperedAction() {\r\n\t\treturn this.wrapperWorkDirsAction(this.wrapperChainActions());\r\n\t}\r\n\r\n\t/**\r\n\t * 向上查找所有祖先命令\r\n\t */\r\n\tprivate getAncestorCommands(): MixCommand[] {\r\n\t\tlet cmds: MixCommand[] = [];\r\n\t\tlet cmd: MixCommand | null = this;\r\n\t\twhile (cmd) {\r\n\t\t\tcmd = cmd.parent as MixCommand;\r\n\t\t\tif (cmd) {\r\n\t\t\t\tcmds.push(cmd);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn cmds;\r\n\t}\r\n\t/***\r\n\t * 将所有actions包装成一个链式调用的函数\r\n\t */\r\n\tprivate wrapperChainActions() {\r\n\t\tconst self = this;\r\n\t\treturn async function (this: any) {\r\n\t\t\tconst args = Array.from(arguments); // 原始输入的参数\r\n\t\t\tlet preValue: any; // 保存上一个action的返回值\r\n\t\t\t//解析参数, 0-1个参数为options,最后一个参数为command\r\n\t\t\tlet actionOpts: Record<string, any> = {},\r\n\t\t\t\tactionArgs: any[] = [],\r\n\t\t\t\tcmd: any;\r\n\t\t\tif (args.length >= 2) {\r\n\t\t\t\tcmd = args[args.length - 1]; // 最后一个command\r\n\t\t\t\tactionOpts = args[args.length - 2];\r\n\t\t\t\tactionArgs = args.slice(0, args.length - 2);\r\n\t\t\t}\r\n\t\t\tawait self.executeBeforeHooks({ args: actionArgs, options: actionOpts, command: cmd });\r\n\t\t\ttry {\r\n\t\t\t\tfor (let action of self._actions) {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tif (action.enhance) {\r\n\t\t\t\t\t\t\t// 增强模式\r\n\t\t\t\t\t\t\toutputDebug(\"执行<{}>: args={}, options={}\", () => [\r\n\t\t\t\t\t\t\t\tself.name(),\r\n\t\t\t\t\t\t\t\tactionArgs,\r\n\t\t\t\t\t\t\t\tactionOpts,\r\n\t\t\t\t\t\t\t]);\r\n\t\t\t\t\t\t\tpreValue = await action.fn.call(this, {\r\n\t\t\t\t\t\t\t\tcommand: cmd,\r\n\t\t\t\t\t\t\t\tvalue: preValue,\r\n\t\t\t\t\t\t\t\targs: actionArgs,\r\n\t\t\t\t\t\t\t\toptions: actionOpts,\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t// 原始模式\r\n\t\t\t\t\t\t\tpreValue = await action.fn.apply(this, args);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (preValue === BREAK) break;\r\n\t\t\t\t\t} catch (e) {\r\n\t\t\t\t\t\toutputDebug(\"命令{}的Action({})执行出错:{}\", [self.name, action.id, e]);\r\n\t\t\t\t\t\tthrow e;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} finally {\r\n\t\t\t\tawait self.executeAfterHooks({\r\n\t\t\t\t\tvalue: preValue,\r\n\t\t\t\t\targs: actionArgs,\r\n\t\t\t\t\toptions: actionOpts,\r\n\t\t\t\t\tcommand: cmd,\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\t/**\r\n\t * 当传入--work-dirs时用来处理工作目录\r\n\t */\r\n\tprivate wrapperWorkDirsAction(fn: AsyncFunction) {\r\n\t\tconst self = this;\r\n\t\treturn async function (this: any) {\r\n\t\t\tlet workDirs = self._optionValues.workDirs;\r\n\t\t\t// 未指定工作目录参数\r\n\t\t\tif (!workDirs) {\r\n\t\t\t\treturn await fn.apply(this, Array.from(arguments));\r\n\t\t\t}\r\n\t\t\tif (!Array.isArray(workDirs)) workDirs = workDirs.split(\",\");\r\n\t\t\tworkDirs = workDirs.reduce((dirs: any[], dir: string) => {\r\n\t\t\t\tif (typeof dir == \"string\") dirs.push(...dir.split(\",\"));\r\n\t\t\t\treturn dirs;\r\n\t\t\t}, []);\r\n\t\t\tfor (let workDir of workDirs) {\r\n\t\t\t\tconst cwd = process.cwd();\r\n\t\t\t\ttry {\r\n\t\t\t\t\tif (!path.isAbsolute(workDir)) workDir = path.join(cwd, workDir);\r\n\t\t\t\t\tif (fs.existsSync(workDir) && fs.statSync(workDir).isDirectory()) {\r\n\t\t\t\t\t\toutputDebug(\"切换到工作目录:{}\", workDir);\r\n\t\t\t\t\t\tprocess.chdir(workDir); // 切换\r\n\t\t\t\t\t\tawait fn.apply(this, Array.from(arguments));\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\toutputDebug(\"无效的工作目录:{}\", workDir);\r\n\t\t\t\t\t}\r\n\t\t\t\t} catch (e) {\r\n\t\t\t\t\tthrow e;\r\n\t\t\t\t} finally {\r\n\t\t\t\t\tprocess.chdir(cwd);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\tgetOption(name: string): MixOption {\r\n\t\treturn this.options.find((option) => option.name() == name) as unknown as MixOption;\r\n\t}\r\n\t/**\r\n\t * 添加一个Before钩子\r\n\t * @param listener\r\n\t * @param scope =false时代表只在本命令执行,=true时代表在本命令及其子命令执行\r\n\t * @returns\r\n\t */\r\n\tbefore(listener: BeforeCommandHookListener, scope: boolean = true) {\r\n\t\tthis._beforeHooks.push([listener, scope]);\r\n\t\treturn this;\r\n\t}\r\n\tprivate async executeBeforeHooks(args: any) {\r\n\t\tconst hooks: [BeforeCommandHookListener, boolean, MixCommand][] = this.beforeHooks.map(\r\n\t\t\t([hook, scope]) => [hook, scope, this]\r\n\t\t);\r\n\t\tthis.getAncestorCommands().forEach((cmd: MixCommand) => {\r\n\t\t\thooks.unshift(\r\n\t\t\t\t...cmd.beforeHooks.map(([hook, scope]) => {\r\n\t\t\t\t\treturn [hook, scope, cmd] as [BeforeCommandHookListener, boolean, MixCommand];\r\n\t\t\t\t})\r\n\t\t\t);\r\n\t\t});\r\n\t\tfor (let [hook, scope, cmd] of hooks) {\r\n\t\t\tif (!scope) continue;\r\n\t\t\tawait hook.call(cmd, args);\r\n\t\t}\r\n\t}\r\n\t/**\r\n\t * 添加一个After钩子\r\n\t * @param listener\r\n\t * @param scope =false时代表只在本命令执行,=true时代表在本命令及其子命令执行\r\n\t * @returns\r\n\t */\r\n\tafter(listener: AfterCommandHookListener, scope: boolean = true) {\r\n\t\tthis._afterHooks.push([listener, scope]);\r\n\t\treturn this;\r\n\t}\r\n\tprivate async executeAfterHooks(args: any) {\r\n\t\tconst hooks: [AfterCommandHookListener, boolean, MixCommand][] = this.afterHooks.map(\r\n\t\t\t([hook, scope]) => [hook, scope, this]\r\n\t\t);\r\n\t\tthis.getAncestorCommands().forEach((cmd: MixCommand) => {\r\n\t\t\thooks.push(\r\n\t\t\t\t...cmd.afterHooks.map(([hook, scope]) => {\r\n\t\t\t\t\treturn [hook, scope, cmd] as [BeforeCommandHookListener, boolean, MixCommand];\r\n\t\t\t\t})\r\n\t\t\t);\r\n\t\t});\r\n\t\tfor (let [hook, scope, cmd] of hooks) {\r\n\t\t\tif (!scope) continue; //=false时不执行\r\n\t\t\tawait hook.call(cmd, args);\r\n\t\t}\r\n\t}\r\n\tprivate async preActionHook(thisCommand: Command, actionCommand: Command) {\r\n\t\tif (this.isEnablePrompts()) {\r\n\t\t\t// 自动生成提示\r\n\t\t\tconst questions: PromptObject[] = [\r\n\t\t\t\t...this.generateAutoPrompts(),\r\n\t\t\t\t...this._customPrompts,\r\n\t\t\t];\r\n\t\t\t// 用户提示\r\n\t\t\tif (questions.length > 0) {\r\n\t\t\t\tconst results = await prompts(questions);\r\n\t\t\t\tObject.entries(results).forEach(([key, value]) => {\r\n\t\t\t\t\tthisCommand.setOptionValue(key, value);\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate isEnablePrompts() {\r\n\t\tif (isEnablePrompts() === false) {\r\n\t\t\t// 命令行参数禁用了提示,优先级最高\r\n\t\t\treturn false;\r\n\t\t} else {\r\n\t\t\treturn this._enable_prompts;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * 生成选项自动提示\r\n\t *\r\n\t * @remarks\r\n\t * FlexCli要求所有未提供默认值的Option自动生成提示\r\n\t *\r\n\t * - 未提供默认值,并且是必选的参数Option\r\n\t * - 指定了choices但未提供有效值的Option\r\n\t *\r\n\t */\r\n\tprivate generateAutoPrompts(): PromptObject[] {\r\n\t\tconst options = this.options as unknown as MixOption[];\r\n\t\tconst optionPromports = options\r\n\t\t\t.filter((option) => !option.hidden && option.__MIX_OPTION__)\r\n\t\t\t.map((option) => option.getPrompt(this._optionValues[option.name()]))\r\n\t\t\t.filter((prompt) => prompt) as PromptObject[];\r\n\t\toutputDebug(\"命令<{}>自动生成{}个选项提示:{}\", [\r\n\t\t\tthis.name(),\r\n\t\t\toptionPromports.length,\r\n\t\t\toptionPromports.map((prompt) => `${prompt.name}(${prompt.type})`).join(\",\"),\r\n\t\t]);\r\n\t\treturn optionPromports;\r\n\t}\r\n\toption(flags: string, description?: string | undefined, defaultValue?: any): this;\r\n\toption(flags: string, description?: string | undefined, options?: MixedOptionParams): this {\r\n\t\t// @ts-ignore\r\n\t\tconst option = new MixOption(...arguments);\r\n\t\tif (option.required && !this.isEnablePrompts()) option.mandatory = true;\r\n\t\treturn this.addOption(option as unknown as Option);\r\n\t}\r\n\r\n\t/**\r\n\t * 添加提示\r\n\t *\r\n\t * @remarks\r\n\t *\r\n\t * 添加一些自定义提示\r\n\t *\r\n\t *\r\n\t * @param questions\r\n\t * @param show 是否显示提示信息,auto表示只有在用户没有提供option的值时才显示提示信息,always表示总是显示提示信息,never表示不显示提示信息\r\n\t * @returns\r\n\t */\r\n\tprompt(questions: PromptObject | PromptObject[]) {\r\n\t\tthis._customPrompts.push(...(Array.isArray(questions) ? questions : [questions]));\r\n\t\treturn this;\r\n\t}\r\n\t/**\r\n\t *\r\n\t * 选择命令并执行\r\n\t *\r\n\t * @remorks\r\n\t *\r\n\t * 当命令具有多个子命令时,并且没有提供默认子命令时,提示用户选择一个子命令\r\n\t *\r\n\t */\r\n\tasync selectCommands() {\r\n\t\tconst choices = this.commands.map((command) => ({\r\n\t\t\ttitle: `${command.description()}(${command.name()})`,\r\n\t\t\tvalue: command.name(),\r\n\t\t}));\r\n\t\tconst result = await prompts({\r\n\t\t\ttype: \"select\",\r\n\t\t\tname: \"command\",\r\n\t\t\tmessage: \"请选择命令:\",\r\n\t\t\tchoices,\r\n\t\t});\r\n\t\t// 重新解析命令行参数标志,\r\n\t\tconst command = this.commands.find((command) => command.name() === result.command);\r\n\t\tawait command?.parseAsync([result.command], { from: \"user\" });\r\n\t}\r\n\t/**\r\n\t * 禁用/启用所有提示\r\n\t */\r\n\tdisablePrompts() {\r\n\t\tthis._enable_prompts = false;\r\n\t\treturn this;\r\n\t}\r\n\tenablePrompts() {\r\n\t\tthis._enable_prompts = true;\r\n\t\treturn this;\r\n\t}\r\n}\r\n","import { Option } from 'commander'\nimport { PromptObject } from 'prompts'\nimport { IPromptable, IPromptableOptions, PromptChoice, PromptManager } from './prompt'\n\n\nexport interface MixedOptionParams extends IPromptableOptions{\n hidden?:boolean\n defaultDescription?:string // 默认值的描述 \n conflicts?:string | string[]\n env?:string\n argParser?:<T>(value: string, previous: T) => T \n hideHelp?:boolean\n mandatory?: boolean \n implies?:{[key:string]:any} \n}\n\n\nexport class MixOption extends Option implements IPromptable{\n __MIX_OPTION__ = true\n // 是否提示用户输入\n prompt?: PromptManager \n promptChoices?:PromptChoice[]\n private _validate?: (value: any) => boolean \n constructor(flags: string, description?: string | undefined,optsOrDefault?:any) {\n super(flags, description)\n let params:MixedOptionParams = {}\n if(arguments.length==3 && typeof arguments[2] == \"object\"){\n params = Object.assign({ },arguments[2]) \n }else if(arguments.length==3){\n params.default = arguments[2]\n }\n if(params.prompt===undefined) params.prompt = 'auto'\n if(params.default) this.default(params.default,params.defaultDescription)\n if(params.choices) this.choices(params.choices)\n if(params.conflicts) this.conflicts(params.conflicts)\n if(params.env) this.env(params.env)\n if(params.argParser) this.argParser(params.argParser)\n if(params.hideHelp) this.hideHelp(params.hideHelp)\n if(params.hidden) this.hidden = params.hidden\n if(params.mandatory) this.makeOptionMandatory(params.mandatory)\n if(params.implies) this.implies(params.implies) \n if(params.optional) this.optional=params.optional\n if(typeof(params.validate)=='function') this._validate = params.validate.bind(this)\n if(params.required) {\n this.required = params.required\n if(!this._validate ) this._validate = (value:any)=>String(value).length>0\n }\n this.prompt = new PromptManager(this as IPromptable,params.prompt)\n } \n validate(value: any): boolean {\n if(typeof(this._validate)=='function'){\n return this._validate(value)\n }else{\n return true\n }\n }\n // @ts-ignore\n choices(values:(PromptChoice | string)[]){\n if(!this.promptChoices){\n this.promptChoices = values.map(choice=>{\n if(typeof(choice)=='object'){\n return choice\n }else{\n return {title:choice,value:choice} \n }\n })\n } \n super.choices(this.promptChoices.map((item:any)=>item.value)) \n } \n\n private resetChoices(){\n super.choices(this.promptChoices!.map((item:any)=>item.value)) \n }\n\n addChoice(value:PromptChoice | string){\n if(!this.promptChoices || !Array.isArray(this.promptChoices)) this.promptChoices = []\n this.promptChoices!.push(typeof(value)=='string' ? {title:value,value} : value)\n this.resetChoices()\n }\n removeChoice(value:any){\n this.promptChoices =this.promptChoices?.filter(choice=>choice.value!==value)\n this.resetChoices()\n }\n clearChoice(){\n this.promptChoices = []\n this.resetChoices()\n }\n\n \n /**\n * 返回选项的提示对象\n * \n * @remarks\n * \n *\n * \n * @param inputValue \n * @returns \n */\n getPrompt(inputValue?:any): PromptObject | undefined {\n return this.prompt?.get(inputValue)\n } \n}","import artTemplate from \"art-template\"\r\nimport fs from \"fs-extra\"\r\nimport path from \"node:path\"\r\nimport { promisify } from \"flex-tools/func/promisify\"\r\nimport logsets from \"logsets\" \r\n/**\r\n * \r\n * 在控制台输出一个字符串\r\n * 本方法会将字符串中的每一行空格去掉\r\n * \r\n * @remarks\r\n * \r\n * outputStr(String.raw`\r\n * a\r\n * b`)\r\n * \r\n * 会输出\r\n * a\r\n * b\r\n *\r\n * 此功能可以用于输出多行字符串时,保持代码的缩进格式,而不会影响输出结果\r\n * \r\n * @param str : 要输出的字符串\r\n * @param vars : 用于替换字符串中的变量\r\n * \r\n */\r\nexport function outputStr(str:string,vars?:Record<string,any> | any[]){ \r\n logsets.log(fixIndent(str),vars)\r\n}\r\n\r\n/**\r\n * 修正多行字符串的缩进\r\n * \r\n * @param text \r\n * @param indent \r\n * @returns \r\n */\r\nexport function fixIndent(text:string,indent?:boolean | number):string{\r\n let indentValue = (indent==undefined || indent===true) ? 0 : (typeof(indent)=='number' ? indent : -1)\r\n if(indentValue==-1) return text // 不修正缩进\r\n let lines:string[] = text.split(\"\\n\")\r\n let minSpaceCount = lines.reduce<number>((minCount,line,index)=>{\r\n if(index==0) return minCount\r\n const spaceCount = line.match(/^\\s*/)?.[0].length || 0\r\n return Math.min(minCount,spaceCount)\r\n },9999)\r\n lines = lines.map(line=>line.substring(minSpaceCount))\r\n return lines.join(\"\\n\")\r\n}\r\n\r\n/**\r\n * 增加内置选项\r\n * @param command \r\n */\r\nexport function addBuiltInOptions(command:any){ \r\n command.option(\"--work-dirs <values...>\",\"指定工作目录\",{hidden:true,optional:true,required:true,prompt:false})\r\n command.option(\"--disable-prompts\",\"禁用所有交互提示\",{hidden:true,prompt:false}) \r\n command.option(\"--debug-cli\",\"显示调试信息\",{hidden:true,prompt:false})\r\n}\r\n\r\n\r\n/**\r\n * 是否命令行中包含了--debug-cli选项\r\n */\r\nexport function isDebug(){\r\n return process.argv.includes(\"--debug-cli\")\r\n}\r\nexport function isEnablePrompts(){ \r\n return !process.argv.includes(\"--disable-prompts\")\r\n}\r\n\r\n/**\r\n * 打印调试信息\r\n * @param message \r\n * @param args \r\n */\r\nexport function outputDebug(message:string,...args:any[]){ \r\n let vars = (args.length == 1 && typeof(args[0])=='function') ? args[0]() : args\r\n if(isDebug()) logsets.log(`[MixCli] ${message}`,...vars)\r\n}\r\n\r\nexport const fileExists = promisify(fs.exists,{\r\n parseCallback:(results)=>{\r\n return results[0]\r\n }\r\n})\r\nexport const readFile = promisify(fs.readFile)\r\nexport const writeFile = promisify(fs.writeFile)\r\nexport const mkdir = promisify(fs.mkdir)\r\n\r\n/**\r\n * 基于artTemplate模板生成文件\r\n * \r\n * @param {*} tmplFile \r\n * @param {*} vars \r\n */\r\nexport async function createFileByTemplate(targetFile:string,tmplFile:string,vars:Record<string,any>={}){\r\n tmplFile=path.isAbsolute(tmplFile)? tmplFile : path.join(process.cwd(),tmplFile)\r\n if(!fs.existsSync(tmplFile)){\r\n throw new Error(\"模板文件不存在:\"+tmplFile)\r\n }\r\n targetFile=path.isAbsolute(targetFile)? targetFile : path.join(process.cwd(),targetFile)\r\n const outPath = path.dirname(targetFile)\r\n if(!await fileExists(outPath)){\r\n await mkdir(outPath,{recursive:true})\r\n } \r\n const template = artTemplate(tmplFile,await readFile(tmplFile,{encoding:\"utf-8\"})); \r\n await writeFile(targetFile,template(vars),{encoding:\"utf-8\"})\r\n return targetFile\r\n}\r\n\r\n/** \r\n * 创建目录 \r\n * \r\n * \r\n * \r\n * @param {String[]} dirs 要创建的目录列表,类型为字符串数组 \r\n * @param callback 创建目录过程中的回调函数,类型为异步函数,接收一个参数 dir,表示当前正在创建的目录 \r\n * @returns 该函数返回一个 Promise 对象,表示创建目录的操作是否完成 \r\n */\r\nexport async function mkDirs(dirs:string[],{callback,base}:{callback?:Function,base?:string}){\r\n if(!Array.isArray(dirs)) throw new Error(\"dirs参数必须为字符串数组\")\r\n for(let dir of dirs){\r\n if(!path.isAbsolute(dir)) dir = path.join(base || process.cwd(),dir)\r\n if(typeof(callback)=='function') callback(dir)\r\n await mkdir(dir,{recursive:true})\r\n }\r\n}\r\n\r\nexport function showError(e:any){\r\n if(isDebug()){\r\n outputDebug(\"导入命令<>出错:{}\",e.stack)\r\n }else{\r\n console.error(e)\r\n } \r\n\r\n}\r\n\r\n\r\nexport function getId(){\r\n return Math.random().toString(36).substr(2)\r\n}\r\n\r\n\r\nexport async function importModule(file:string){\r\n let module \r\n try{\r\n module = require(file)\r\n }catch(e:any){\r\n try{\r\n const cmd = await import(`file://${file}`)\r\n module = cmd.default\r\n }catch(e:any){\r\n throw e\r\n } \r\n }\r\n return module\r\n}\r\n","import { PromptObject } from \"prompts\" \nimport { outputDebug } from \"./utils\"\n \n\nexport type PromptType = \"text\" | \"password\" | \"invisible\" | \"number\"| \"confirm\"| \"list\"| \"toggle\"| \"select\" | \"multiselect\" | \"autocomplete\" | \"date\" | \"autocompleteMultiselect\"\n\nexport type PromptParam = 'auto' | boolean | PromptType | PromptObject\nexport type InputPromptParam = PromptParam | ((value:any)=>PromptParam) | boolean\nexport type PromptParamDefaultValue = string | boolean | string[] \n\nexport const promptTypeMap:Record<string,string> = {\n boolean:\"confirm\",\n string:\"text\",\n number:\"number\", \n array:\"list\", \n} \n\nexport const supportedPromptTypes = [\"text\",\"password\",\"invisible\", \"number\", \"confirm\" , \"list\", \"toggle\" , \"select\" , \"multiselect\" , \"autocomplete\" , \"date\" , \"autocompleteMultiselect\"]\nexport interface PromptChoice {\n title: string;\n value?: any;\n disabled?: boolean | undefined;\n selected?: boolean | undefined;\n description?: string | undefined;\n}\n\n\n\nexport interface IPromptableOptions{\n required?: boolean; // A value must be supplied when the option is specified.\n optional?: boolean; // A value is optional when the option is specified.\n default?:PromptParamDefaultValue\n choices?:(PromptChoice | any)[] // 选项值的可选值\n prompt?:InputPromptParam\n validate?:(value: any) => boolean\n}\n\n\nexport interface IPromptable{\n name():string \n description?:string\n flags:string\n promptChoices?:PromptChoice[]\n argChoices?:string[]\n variadic?:boolean\n defaultValue?:PromptParamDefaultValue\n input?:any \n required?:boolean\n validate?: (value: any) => boolean \n getPrompt(inputValue?:any):PromptObject | undefined \n}\n\n/**\n * 供command.option()使用的参数对象\n */\nexport interface PromptableObject{\n \n\n}\n\n\n/**\n * 负责生成prompt对象\n * \n */\nexport class PromptManager{\n args:InputPromptParam \n private _promptable:IPromptable // 对应的FlexOption或FlexArgument\n constructor(promptable:IPromptable,promptArgs?:InputPromptParam){ \n this._promptable = promptable\n this.args= promptArgs===undefined ? 'auto' : promptArgs\n }\n\n /**\n * 返回输入的是否是有效的prompt类型\n * @param type \n * @returns \n */\n isValid(type:any){\n return supportedPromptTypes.includes(String(type))\n }\n /**\n * 推断是否需要提示\n * \n */\n isNeed(input:any,defaultValue?:any){\n \n const promptArg = this.args\n const inputValue = input || defaultValue\n // 是否有输入值,即在命令行输入了值\n const hasInput = !(inputValue === undefined)\n // 1. 显式指定了_prompt为true,则需要提示,后续进行提示类型的推断,可能不会准确\n if(promptArg===true) return true\n if(promptArg===false) return false \n\n // 2. 提供了一个prompt对象,并且没有在命令行输入值,则需要提示\n if(typeof(promptArg)=='object'){\n return !hasInput\n }\n\n // 3. 指定了内置的prompt类型,如prompt='password',则使用password类型提示输入\n if(typeof(promptArg) == 'string' && supportedPromptTypes.includes(promptArg)){\n return !hasInput\n }\n \n // 4. 判断输入是否有效,则显示提示\n if(this._promptable.argChoices && this._promptable.argChoices.indexOf(inputValue) == -1){\n return true\n } \n return !hasInput\n }\n /**\n * 返回生成prompt对象\n * \n * @param inputValue 从命令行输入的值\n */\n get(inputValue?:any){\n const {description,promptChoices,validate,defaultValue} = this._promptable\n let input = inputValue || defaultValue\n // 判断是否需要输入提示\n if(!this.isNeed(input,defaultValue)) return\n // 推断prompt类型\n let promptType = this.infer(inputValue)\n const prompt = {\n type:promptType, \n name:this._promptable.name(),\n message:description,\n initial: input,\n ...typeof(this.args) == 'object' ? this.args : {}\n } as PromptObject\n // 指定了验证函数,用来验证输入值是否有效\n prompt.validate = validate?.bind(this._promptable)\n if(promptType=='multiselect') prompt.instructions=false\n if(['select','multiselect'].includes(promptType)){\n let index = promptChoices?.findIndex(item=>item.value==input)\n prompt.initial = index==-1 ? undefined : index\n } \n // 选项值的可选值\n if(Array.isArray(promptChoices)) {\n prompt.choices =promptChoices\n }\n return prompt\n }\n /**\n * 推断prompt类型\n * \n * @param inputValue 从命令行输入的值\n */\n infer(inputValue?:any){\n const {argChoices,variadic,defaultValue} = this._promptable\n let input = inputValue || defaultValue\n // 如果选择指定了\"-p [value]或[value...]\",则使用text类型,如果没有要求输入值,则使用confirm类型\n let promptType = /(\\<[\\w\\.]+\\>)|(\\[[\\w\\.]+\\])/.test(this._promptable.flags) ? 'text' : 'confirm'\n let promptArg = this.args\n if(this.isValid(promptArg)){ // 显式指定了prompt类型\n promptType = promptArg as string\n }else{ // 未显式指定prompt类型,需要按一定规则推断类型\n if(typeof(promptArg)=='object'){\n promptType = promptArg.type as string\n }else{\n if(argChoices){ // 提供多个可选值时\n promptType = variadic ? 'multiselect' : 'select'\n }else{\n const datatype:string = Array.isArray(defaultValue) ? 'array' : typeof(defaultValue) \n // 如果输入值班是数组,则使用list类型,允许使用逗号分隔的多个值\n if(Array.isArray(input) || variadic){\n promptType = \"list\"\n }else{\n if(datatype in promptTypeMap){\n promptType = promptTypeMap[datatype]\n }\n }\n }\n }\n }\n outputDebug(\"选项<{}> -> 提示类型<{}>\",[this._promptable.name(),promptType])\n return promptType\n }\n\n}","import { getPackageJson } from \"flex-tools/package/getPackageJson\"\r\nimport { getPackageRootPath } from 'flex-tools/package/getPackageRootPath';\r\nimport type { MixCli } from './cli';\r\nimport { globSync } from 'glob'\r\nimport { MixCliCommand } from './cli';\r\nimport { importModule, isDebug, outputDebug } from './utils';\r\nimport fs from \"node:fs\"\r\nimport path from \"node:path\"\r\n\r\n\r\n/**\r\n * \r\n * 在当前工程中查找符合FlexCli.prefix约定的命令 \r\n * \r\n * - 读取当前包的package.json\r\n * - 找出所有以cli.prefix开头的依赖\r\n * - 加载这些依赖的目录下的匹配cli.pattern的命令\r\n * - 加载加载这样命令\r\n * \r\n */\r\n \r\n\r\nexport function getMatchedDependencies(this:MixCli,entry:string):string[]{\r\n const pacakgeMacher = this.options.include\r\n if(!(pacakgeMacher instanceof RegExp)) return []\r\n \r\n // 找出当前包的所有依赖\r\n const { dependencies={},devDependencies={},peerDependencies={},optionalDependencies={},bundleDependencies={} } = getPackageJson(entry)\r\n const packageNames = [\r\n ...Object.keys(dependencies),\r\n ...Object.keys(devDependencies),\r\n ...Object.keys(peerDependencies),\r\n ...Object.keys(optionalDependencies),\r\n ...Object.keys(bundleDependencies)\r\n ]\r\n return packageNames.filter(name=>name!==\"@voerka/cli\" && pacakgeMacher.test(name))\r\n}\r\n\r\nfunction isMatched(str:string,reg?:string | RegExp | string[] | RegExp[]):boolean{\r\n // let regexps:RegExp[]=[]\r\n const regexps = reg ? (Array.isArray(reg) ? reg : [reg]) : []\r\n return regexps.some(regexp=>{\r\n if(typeof regexp === \"string\"){\r\n return (new RegExp(regexp)).test(str)\r\n }else if(regexp instanceof RegExp){\r\n return regexp.test(str)\r\n }else{\r\n return false\r\n }\r\n })\r\n}\r\n\r\nexport function findCliPaths(this:MixCli,packageName?:string ,entry?:string):string[]{\r\n const includeMacher = this.options.include\r\n const excludeMacher = this.options.exclude\r\n if(!includeMacher) return []\r\n const packageRoot = getPackageRootPath(entry || process.cwd())\r\n const packagePath = packageName ? path.dirname(require.resolve(packageName,{paths:[packageRoot as string]})) : packageRoot\r\n\r\n if(!packagePath) {\r\n outputDebug(\"MixCli只能运行在Nodejs环境\" )\r\n return []\r\n }\r\n\r\n // 找出当前包的所有依赖\r\n const packageNames = getMatchedDependencies.call(this,packagePath)\r\n\r\n const cliDirs:string[]=[]\r\n \r\n if(entry!==undefined) cliDirs.push(path.join(packagePath,this.options.cliDir))\r\n packageNames.filter(name=>{\r\n return isMatched(name,includeMacher) && !isMatched(name,excludeMacher) \r\n })\r\n .forEach(name=>{\r\n outputDebug(\"匹配包:{}\",`${packageName ? name+\" <- \"+packageName : name}`)\r\n try{\r\n const packageEntry = path.dirname(require.resolve(name,{paths:packagePath ? [packagePath] : [process.cwd()]}))\r\n const packageCliDir =path.join(packageEntry,this.options.cliDir!) \r\n // 查找当前包的所属工程的依赖\r\n let dependencies = getMatchedDependencies.call(this,packageEntry)\r\n cliDirs.push(...dependencies.reduce<string[]>((result,dependencie)=>{\r\n outputDebug(\"匹配包:{}\",`${dependencie} <- ${name}`)\r\n result.push(...findCliPaths.call(this,dependencie,packageEntry))\r\n return result\r\n },[])) \r\n if(fs.existsSync(packageCliDir)){\r\n cliDirs.push(packageCliDir)\r\n }\r\n }catch(e:any){\r\n outputDebug(\"解析包<{}>路径出错:{}\",[name,e.stack])\r\n } \r\n })\r\n // 由于一些包可能存在循环依赖,所以需要去重\r\n return [...new Set(cliDirs)]\r\n}\r\n\r\n\r\n/**\r\n * \r\n * 扫描当前工程中所有符合条件的命令\r\n * \r\n * @param cli \r\n * \r\n */\r\nexport async function findCommands(cli:MixCli){ \r\n const cliDirs = findCliPaths.call(cli)\r\n const commands:MixCliCommand[] = []\r\n const files = [] as string[]\r\n cliDirs.forEach(dir=>{\r\n globSync(\"*\",{\r\n cwd:dir,\r\n absolute :true \r\n }).forEach((file:string)=>{ \r\n const baseName = path.basename(file) \r\n if(baseName.startsWith(\"_\")) return\r\n const ext = path.extname(file).toLowerCase()\r\n if([\".js\",\".cjs\",\".mjs\"].includes(ext)){\r\n files.push(file)\r\n }else if(fs.statSync(file).isDirectory()){\r\n files.push(path.join(file,\"index.js\"))\r\n files.push(path.join(file,\"index.cjs\"))\r\n files.push(path.join(file,\"index.mjs\"))\r\n }\r\n })\r\n })\r\n for(let file of files){ \r\n if(!fs.existsSync(file)) continue\r\n try{\r\n outputDebug(\"导入命令:{}\",file)\r\n if(file.endsWith(\".cjs\") || file.endsWith(\".js\")){\r\n commands.push(await importModule(file))\r\n }else if(file.endsWith(\".mjs\")){\r\n const cmd = await import(`file://${file}`)\r\n commands.push(cmd.default)\r\n } \r\n }catch(e:any){\r\n outputDebug(e) \r\n }\r\n }\r\n return commands\r\n}\r\n\r\n"],"mappings":"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","names":["logsets","e","path","fs","path","fs","command","fs","path","path","fs","logsets","cmd"]}
package/package.json CHANGED
@@ -1,30 +1,35 @@
1
1
  {
2
2
  "name": "mixcli",
3
- "version": "3.0.9",
3
+ "version": "3.2.0",
4
4
  "description": "Develop command line tool scaffolding for monorepo",
5
5
  "repository": "https://github.com/zhangfisher/mixcli.git",
6
6
  "homepage": "https://zhangfisher.github.io/mixcli/",
7
7
  "main": "./dist/index.js",
8
8
  "module": "./dist/index.mjs",
9
9
  "types": "./dist/index.d.ts",
10
+ "access": "public",
10
11
  "files": [
11
12
  "dist",
12
13
  "src",
13
14
  "readme.md",
14
15
  "package.json"
15
16
  ],
16
- "keywords": [],
17
+ "keywords": [
18
+ "commander",
19
+ "prompts",
20
+ "cli"
21
+ ],
17
22
  "author": "",
18
23
  "license": "ISC",
19
24
  "dependencies": {
20
25
  "@types/prompts": "^2.4.4",
21
- "@voerkai18n/runtime": "^2.0.8",
26
+ "@voerkai18n/runtime": "^2.1.13",
22
27
  "art-template": "^4.13.2",
23
- "commander": "^12.0.0",
24
- "flex-tools": "^1.3.71",
28
+ "commander": "^12.1.0",
29
+ "flex-tools": "^1.4.12",
25
30
  "fs-extra": "^11.1.1",
26
31
  "glob": "^10.3.12",
27
- "logsets": "^1.3.8",
32
+ "logsets": "^1.3.10",
28
33
  "prompts": "^2.4.2",
29
34
  "string.prototype.replaceall": "^1.0.7"
30
35
  },
package/src/cli.ts CHANGED
@@ -6,13 +6,11 @@ import logsets from "logsets"
6
6
 
7
7
  import { assignObject } from "flex-tools/object/assignObject"
8
8
  import { MixCommand } from "./command"
9
- import { addBuiltInOptions, fixIndent, isDebug } from './utils';
9
+ import { addBuiltInOptions, fixIndent, outputDebug } from './utils';
10
10
  import { findCommands } from "./finder"
11
11
  import { asyncSignal } from "flex-tools/async/asyncSignal"
12
12
  // @ts-ignore
13
- import replaceAll from 'string.prototype.replaceall'
14
- import { getPackageEntry, getPackageRootPath } from "flex-tools"
15
- import { getPackageJson } from 'flex-tools/package/getPackageJson';
13
+ import replaceAll from 'string.prototype.replaceall'
16
14
  replaceAll.shim()
17
15
 
18
16
  export interface MixCliOptions{
@@ -40,6 +38,7 @@ export interface MixCliOptions{
40
38
  // 默认是否启用交互提示, auto当没有值时,会根据当前是否在终端中运行来决定是否启用交互提示
41
39
  // 为false时,禁用所有交互提示,为true时,启用所有交互提示
42
40
  prompt?:'auto' | boolean
41
+ ignoreError?:boolean
43
42
  }
44
43
 
45
44
 
@@ -61,8 +60,9 @@ export class MixCli extends LiteEvent<any,MixCliEvents>{
61
60
  name:"mixcli",
62
61
  package:null,
63
62
  cliDir:"cli",
64
- prompt:'auto'
65
- },options)
63
+ prompt:'auto',
64
+ ignoreError:false
65
+ },options) as Required<MixCliOptions>
66
66
  this.createRootCommand()
67
67
  }
68
68
  get context(){return this.options.context}
@@ -82,10 +82,11 @@ export class MixCli extends LiteEvent<any,MixCliEvents>{
82
82
  try{
83
83
  if(typeof(cmder)==="function"){
84
84
  let cmds = cmder(this)
85
- cmds =cmds ? (Array.isArray(cmds) ? cmds : [cmds]) : []
85
+ cmds = cmds ? (Array.isArray(cmds) ? cmds : [cmds]) : []
86
86
  this.register(()=>cmds)
87
87
  }
88
88
  }catch(e:any){
89
+ outputDebug("注册命令失败:{}",e.stack)
89
90
  }
90
91
  }
91
92
  }
@@ -138,14 +139,20 @@ export class MixCli extends LiteEvent<any,MixCliEvents>{
138
139
  let result = cmd(this)
139
140
  let cmds = result instanceof Array ? result : (result==undefined ? [] : [result])
140
141
  for(let cmd of cmds){
141
- if(cmd instanceof MixCommand){
142
+ // 为什么不用cmd instanceof MixCommand来判断是否是一个有效的命令?
143
+ // 因为当不同的包引用了与主包不一样版本的mixcli时,判断会失效,导致不能识别
144
+ // 所以我们通过cmd.__MIX_COMMAND__来判断是否是一个有效的命令
145
+ if(cmd.__MIX_COMMAND__){
142
146
  if(this.hasCommand(cmd.name())){
143
147
  logsets.error(`Command <${cmd.name()}> has been registered!`)
144
148
  }else{
149
+ outputDebug("注册命令:{}",cmd.fullname)
145
150
  this.root.addCommand(cmd) ;
146
151
  (cmd as any)._cli = this
147
152
  this.emit("register",cmd.fullname,true)
148
153
  }
154
+ }else{
155
+ logsets.error(`Command <${cmd.toString()}> is not a valid command!`)
149
156
  }
150
157
  }
151
158
  }else{
package/src/command.ts CHANGED
@@ -67,6 +67,7 @@ export type EnhanceAction = ({
67
67
  export const BREAK = Symbol("BREAK_ACTION"); // 中止后续的action执行
68
68
 
69
69
  export class MixCommand extends Command {
70
+ __MIX_COMMAND__ = true;
70
71
  private _beforeHooks: [BeforeCommandHookListener, boolean][] = [];
71
72
  private _afterHooks: [AfterCommandHookListener, boolean][] = [];
72
73
  private _customPrompts: PromptObject[] = [];
@@ -379,7 +380,7 @@ export class MixCommand extends Command {
379
380
  private generateAutoPrompts(): PromptObject[] {
380
381
  const options = this.options as unknown as MixOption[];
381
382
  const optionPromports = options
382
- .filter((option) => !option.hidden && option instanceof MixOption)
383
+ .filter((option) => !option.hidden && option.__MIX_OPTION__)
383
384
  .map((option) => option.getPrompt(this._optionValues[option.name()]))
384
385
  .filter((prompt) => prompt) as PromptObject[];
385
386
  outputDebug("命令<{}>自动生成{}个选项提示:{}", [
package/src/option.ts CHANGED
@@ -16,6 +16,7 @@ export interface MixedOptionParams extends IPromptableOptions{
16
16
 
17
17
 
18
18
  export class MixOption extends Option implements IPromptable{
19
+ __MIX_OPTION__ = true
19
20
  // 是否提示用户输入
20
21
  prompt?: PromptManager
21
22
  promptChoices?:PromptChoice[]