mixcli 3.2.0 → 3.2.1

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.mjs DELETED
@@ -1,1088 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
3
- var __hasOwnProp = Object.prototype.hasOwnProperty;
4
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
5
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
- var __spreadValues = (a, b) => {
7
- for (var prop in b || (b = {}))
8
- if (__hasOwnProp.call(b, prop))
9
- __defNormalProp(a, prop, b[prop]);
10
- if (__getOwnPropSymbols)
11
- for (var prop of __getOwnPropSymbols(b)) {
12
- if (__propIsEnum.call(b, prop))
13
- __defNormalProp(a, prop, b[prop]);
14
- }
15
- return a;
16
- };
17
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
18
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
19
- }) : x)(function(x) {
20
- if (typeof require !== "undefined")
21
- return require.apply(this, arguments);
22
- throw Error('Dynamic require of "' + x + '" is not supported');
23
- });
24
- var __async = (__this, __arguments, generator) => {
25
- return new Promise((resolve, reject) => {
26
- var fulfilled = (value) => {
27
- try {
28
- step(generator.next(value));
29
- } catch (e) {
30
- reject(e);
31
- }
32
- };
33
- var rejected = (value) => {
34
- try {
35
- step(generator.throw(value));
36
- } catch (e) {
37
- reject(e);
38
- }
39
- };
40
- var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
41
- step((generator = generator.apply(__this, __arguments)).next());
42
- });
43
- };
44
-
45
- // src/cli.ts
46
- import "flex-tools/string";
47
- import { LiteEvent } from "flex-tools/events/liteEvent";
48
- import logsets2 from "logsets";
49
- import { assignObject } from "flex-tools/object/assignObject";
50
-
51
- // src/command.ts
52
- import { Command } from "commander";
53
- import prompts from "prompts";
54
-
55
- // src/option.ts
56
- import { Option } from "commander";
57
-
58
- // src/utils.ts
59
- import artTemplate from "art-template";
60
- import fs from "fs-extra";
61
- import path from "path";
62
- import { promisify } from "flex-tools/func/promisify";
63
- import logsets from "logsets";
64
- function outputStr(str, vars) {
65
- logsets.log(fixIndent(str), vars);
66
- }
67
- function fixIndent(text, indent) {
68
- let indentValue = indent == void 0 || indent === true ? 0 : typeof indent == "number" ? indent : -1;
69
- if (indentValue == -1)
70
- return text;
71
- let lines = text.split("\n");
72
- let minSpaceCount = lines.reduce((minCount, line, index) => {
73
- var _a;
74
- if (index == 0)
75
- return minCount;
76
- const spaceCount = ((_a = line.match(/^\s*/)) == null ? void 0 : _a[0].length) || 0;
77
- return Math.min(minCount, spaceCount);
78
- }, 9999);
79
- lines = lines.map((line) => line.substring(minSpaceCount));
80
- return lines.join("\n");
81
- }
82
- function addBuiltInOptions(command) {
83
- command.option("--work-dirs <values...>", "\u6307\u5B9A\u5DE5\u4F5C\u76EE\u5F55", { hidden: true, optional: true, required: true, prompt: false });
84
- command.option("--disable-prompts", "\u7981\u7528\u6240\u6709\u4EA4\u4E92\u63D0\u793A", { hidden: true, prompt: false });
85
- command.option("--debug-cli", "\u663E\u793A\u8C03\u8BD5\u4FE1\u606F", { hidden: true, prompt: false });
86
- }
87
- function isDebug() {
88
- return process.argv.includes("--debug-cli");
89
- }
90
- function isEnablePrompts() {
91
- return !process.argv.includes("--disable-prompts");
92
- }
93
- function outputDebug(message, ...args) {
94
- let vars = args.length == 1 && typeof args[0] == "function" ? args[0]() : args;
95
- if (isDebug())
96
- logsets.log(`[MixCli] ${message}`, ...vars);
97
- }
98
- var fileExists = promisify(fs.exists, {
99
- parseCallback: (results) => {
100
- return results[0];
101
- }
102
- });
103
- var readFile = promisify(fs.readFile);
104
- var writeFile = promisify(fs.writeFile);
105
- var mkdir = promisify(fs.mkdir);
106
- function createFileByTemplate(_0, _1) {
107
- return __async(this, arguments, function* (targetFile, tmplFile, vars = {}) {
108
- tmplFile = path.isAbsolute(tmplFile) ? tmplFile : path.join(process.cwd(), tmplFile);
109
- if (!fs.existsSync(tmplFile)) {
110
- throw new Error("\u6A21\u677F\u6587\u4EF6\u4E0D\u5B58\u5728:" + tmplFile);
111
- }
112
- targetFile = path.isAbsolute(targetFile) ? targetFile : path.join(process.cwd(), targetFile);
113
- const outPath = path.dirname(targetFile);
114
- if (!(yield fileExists(outPath))) {
115
- yield mkdir(outPath, { recursive: true });
116
- }
117
- const template = artTemplate(tmplFile, yield readFile(tmplFile, { encoding: "utf-8" }));
118
- yield writeFile(targetFile, template(vars), { encoding: "utf-8" });
119
- return targetFile;
120
- });
121
- }
122
- function mkDirs(_0, _1) {
123
- return __async(this, arguments, function* (dirs, { callback, base }) {
124
- if (!Array.isArray(dirs))
125
- throw new Error("dirs\u53C2\u6570\u5FC5\u987B\u4E3A\u5B57\u7B26\u4E32\u6570\u7EC4");
126
- for (let dir of dirs) {
127
- if (!path.isAbsolute(dir))
128
- dir = path.join(base || process.cwd(), dir);
129
- if (typeof callback == "function")
130
- callback(dir);
131
- yield mkdir(dir, { recursive: true });
132
- }
133
- });
134
- }
135
- function showError(e) {
136
- if (isDebug()) {
137
- outputDebug("\u5BFC\u5165\u547D\u4EE4<>\u51FA\u9519:{}", e.stack);
138
- } else {
139
- console.error(e);
140
- }
141
- }
142
- function getId() {
143
- return Math.random().toString(36).substr(2);
144
- }
145
- function importModule(file) {
146
- return __async(this, null, function* () {
147
- let module;
148
- try {
149
- module = __require(file);
150
- } catch (e) {
151
- try {
152
- const cmd = yield import(`file://${file}`);
153
- module = cmd.default;
154
- } catch (e2) {
155
- throw e2;
156
- }
157
- }
158
- return module;
159
- });
160
- }
161
-
162
- // src/prompt.ts
163
- var promptTypeMap = {
164
- boolean: "confirm",
165
- string: "text",
166
- number: "number",
167
- array: "list"
168
- };
169
- var supportedPromptTypes = ["text", "password", "invisible", "number", "confirm", "list", "toggle", "select", "multiselect", "autocomplete", "date", "autocompleteMultiselect"];
170
- var PromptManager = class {
171
- // 对应的FlexOption或FlexArgument
172
- constructor(promptable, promptArgs) {
173
- this._promptable = promptable;
174
- this.args = promptArgs === void 0 ? "auto" : promptArgs;
175
- }
176
- /**
177
- * 返回输入的是否是有效的prompt类型
178
- * @param type
179
- * @returns
180
- */
181
- isValid(type) {
182
- return supportedPromptTypes.includes(String(type));
183
- }
184
- /**
185
- * 推断是否需要提示
186
- *
187
- */
188
- isNeed(input, defaultValue) {
189
- const promptArg = this.args;
190
- const inputValue = input || defaultValue;
191
- const hasInput = !(inputValue === void 0);
192
- if (promptArg === true)
193
- return true;
194
- if (promptArg === false)
195
- return false;
196
- if (typeof promptArg == "object") {
197
- return !hasInput;
198
- }
199
- if (typeof promptArg == "string" && supportedPromptTypes.includes(promptArg)) {
200
- return !hasInput;
201
- }
202
- if (this._promptable.argChoices && this._promptable.argChoices.indexOf(inputValue) == -1) {
203
- return true;
204
- }
205
- return !hasInput;
206
- }
207
- /**
208
- * 返回生成prompt对象
209
- *
210
- * @param inputValue 从命令行输入的值
211
- */
212
- get(inputValue) {
213
- const { description, promptChoices, validate, defaultValue } = this._promptable;
214
- let input = inputValue || defaultValue;
215
- if (!this.isNeed(input, defaultValue))
216
- return;
217
- let promptType = this.infer(inputValue);
218
- const prompt = __spreadValues({
219
- type: promptType,
220
- name: this._promptable.name(),
221
- message: description,
222
- initial: input
223
- }, typeof this.args == "object" ? this.args : {});
224
- prompt.validate = validate == null ? void 0 : validate.bind(this._promptable);
225
- if (promptType == "multiselect")
226
- prompt.instructions = false;
227
- if (["select", "multiselect"].includes(promptType)) {
228
- let index = promptChoices == null ? void 0 : promptChoices.findIndex((item) => item.value == input);
229
- prompt.initial = index == -1 ? void 0 : index;
230
- }
231
- if (Array.isArray(promptChoices)) {
232
- prompt.choices = promptChoices;
233
- }
234
- return prompt;
235
- }
236
- /**
237
- * 推断prompt类型
238
- *
239
- * @param inputValue 从命令行输入的值
240
- */
241
- infer(inputValue) {
242
- const { argChoices, variadic, defaultValue } = this._promptable;
243
- let input = inputValue || defaultValue;
244
- let promptType = /(\<[\w\.]+\>)|(\[[\w\.]+\])/.test(this._promptable.flags) ? "text" : "confirm";
245
- let promptArg = this.args;
246
- if (this.isValid(promptArg)) {
247
- promptType = promptArg;
248
- } else {
249
- if (typeof promptArg == "object") {
250
- promptType = promptArg.type;
251
- } else {
252
- if (argChoices) {
253
- promptType = variadic ? "multiselect" : "select";
254
- } else {
255
- const datatype = Array.isArray(defaultValue) ? "array" : typeof defaultValue;
256
- if (Array.isArray(input) || variadic) {
257
- promptType = "list";
258
- } else {
259
- if (datatype in promptTypeMap) {
260
- promptType = promptTypeMap[datatype];
261
- }
262
- }
263
- }
264
- }
265
- }
266
- outputDebug("\u9009\u9879<{}> -> \u63D0\u793A\u7C7B\u578B<{}>", [this._promptable.name(), promptType]);
267
- return promptType;
268
- }
269
- };
270
-
271
- // src/option.ts
272
- var MixOption = class extends Option {
273
- constructor(flags, description, optsOrDefault) {
274
- super(flags, description);
275
- this.__MIX_OPTION__ = true;
276
- let params = {};
277
- if (arguments.length == 3 && typeof arguments[2] == "object") {
278
- params = Object.assign({}, arguments[2]);
279
- } else if (arguments.length == 3) {
280
- params.default = arguments[2];
281
- }
282
- if (params.prompt === void 0)
283
- params.prompt = "auto";
284
- if (params.default)
285
- this.default(params.default, params.defaultDescription);
286
- if (params.choices)
287
- this.choices(params.choices);
288
- if (params.conflicts)
289
- this.conflicts(params.conflicts);
290
- if (params.env)
291
- this.env(params.env);
292
- if (params.argParser)
293
- this.argParser(params.argParser);
294
- if (params.hideHelp)
295
- this.hideHelp(params.hideHelp);
296
- if (params.hidden)
297
- this.hidden = params.hidden;
298
- if (params.mandatory)
299
- this.makeOptionMandatory(params.mandatory);
300
- if (params.implies)
301
- this.implies(params.implies);
302
- if (params.optional)
303
- this.optional = params.optional;
304
- if (typeof params.validate == "function")
305
- this._validate = params.validate.bind(this);
306
- if (params.required) {
307
- this.required = params.required;
308
- if (!this._validate)
309
- this._validate = (value) => String(value).length > 0;
310
- }
311
- this.prompt = new PromptManager(this, params.prompt);
312
- }
313
- validate(value) {
314
- if (typeof this._validate == "function") {
315
- return this._validate(value);
316
- } else {
317
- return true;
318
- }
319
- }
320
- // @ts-ignore
321
- choices(values) {
322
- if (!this.promptChoices) {
323
- this.promptChoices = values.map((choice) => {
324
- if (typeof choice == "object") {
325
- return choice;
326
- } else {
327
- return { title: choice, value: choice };
328
- }
329
- });
330
- }
331
- super.choices(this.promptChoices.map((item) => item.value));
332
- }
333
- resetChoices() {
334
- super.choices(this.promptChoices.map((item) => item.value));
335
- }
336
- addChoice(value) {
337
- if (!this.promptChoices || !Array.isArray(this.promptChoices))
338
- this.promptChoices = [];
339
- this.promptChoices.push(typeof value == "string" ? { title: value, value } : value);
340
- this.resetChoices();
341
- }
342
- removeChoice(value) {
343
- var _a;
344
- this.promptChoices = (_a = this.promptChoices) == null ? void 0 : _a.filter((choice) => choice.value !== value);
345
- this.resetChoices();
346
- }
347
- clearChoice() {
348
- this.promptChoices = [];
349
- this.resetChoices();
350
- }
351
- /**
352
- * 返回选项的提示对象
353
- *
354
- * @remarks
355
- *
356
- *
357
- *
358
- * @param inputValue
359
- * @returns
360
- */
361
- getPrompt(inputValue) {
362
- var _a;
363
- return (_a = this.prompt) == null ? void 0 : _a.get(inputValue);
364
- }
365
- };
366
-
367
- // src/command.ts
368
- import path2 from "path";
369
- import fs2 from "fs";
370
- var BREAK = Symbol("BREAK_ACTION");
371
- var MixCommand = class extends Command {
372
- // 是否启用交互提示
373
- constructor(name) {
374
- super(name);
375
- this.__MIX_COMMAND__ = true;
376
- this._beforeHooks = [];
377
- this._afterHooks = [];
378
- this._customPrompts = [];
379
- this._optionValues = {};
380
- // 命令行输入的选项值
381
- this._actions = [];
382
- // 允许多个action
383
- this._enable_prompts = true;
384
- const self = this;
385
- if (!this.isRoot)
386
- addBuiltInOptions(this);
387
- this.hook("preAction", function() {
388
- return __async(this, arguments, function* () {
389
- self._optionValues = self.getOptionValues(this.hookedCommand);
390
- try {
391
- yield self.preActionHook.apply(self, arguments);
392
- } catch (e) {
393
- }
394
- });
395
- });
396
- }
397
- /**
398
- * 是否是根命令
399
- */
400
- get isRoot() {
401
- return !!!this.parent;
402
- }
403
- get actions() {
404
- return this._actions;
405
- }
406
- get beforeHooks() {
407
- return this._beforeHooks;
408
- }
409
- get afterHooks() {
410
- return this._afterHooks;
411
- }
412
- get fullname() {
413
- let names = [this.name()];
414
- let parent = this.parent;
415
- while (parent) {
416
- if (parent.name() !== "root") {
417
- names.unshift(parent.name());
418
- }
419
- parent = parent.parent;
420
- }
421
- return names.join(".");
422
- }
423
- /**
424
- * 返回根命令
425
- */
426
- root() {
427
- let root = this;
428
- while (root && root.parent != null) {
429
- root = root.parent;
430
- }
431
- return root;
432
- }
433
- action(fn) {
434
- const actionFunc = arguments[0];
435
- if (arguments.length == 1 && typeof actionFunc == "function") {
436
- this._actions.push({
437
- id: Math.random().toString(36).substring(2),
438
- enhance: false,
439
- fn: actionFunc
440
- });
441
- } else if (arguments.length == 2 && typeof actionFunc == "function" && typeof arguments[1] == "object") {
442
- const actionFn = arguments[0];
443
- const actionOpts = Object.assign({ at: "append" }, arguments[1]);
444
- if (actionOpts.at == "replace")
445
- this._actions = [];
446
- const actionItem = {
447
- id: actionOpts.id || Math.random().toString(36).substring(2),
448
- enhance: actionOpts.enhance == void 0 ? true : actionOpts.enhance,
449
- fn: actionFn
450
- };
451
- if (typeof actionOpts.at == "number") {
452
- this._actions.splice(Number(actionOpts.at), 0, actionItem);
453
- } else if (["append", "before"].includes(actionOpts.at)) {
454
- this._actions.push(actionItem);
455
- } else if (["preappend", "after"].includes(actionOpts.at)) {
456
- this._actions.splice(0, 0, actionItem);
457
- } else {
458
- this._actions.push(actionItem);
459
- }
460
- } else {
461
- console.log("[mixcli] action params error");
462
- }
463
- return super.action(this.getWrapperedAction());
464
- }
465
- /**
466
- * 读取命令配置值,包括父命令提供的配置选项
467
- * @param command
468
- */
469
- getOptionValues(command) {
470
- let opts = {};
471
- let parent = command;
472
- while (parent) {
473
- Object.assign(opts, parent._optionValues);
474
- parent = parent.parent;
475
- }
476
- return opts;
477
- }
478
- /**
479
- * 本函数在运行时子类进行action生成该命令的action
480
- */
481
- getWrapperedAction() {
482
- return this.wrapperWorkDirsAction(this.wrapperChainActions());
483
- }
484
- /**
485
- * 向上查找所有祖先命令
486
- */
487
- getAncestorCommands() {
488
- let cmds = [];
489
- let cmd = this;
490
- while (cmd) {
491
- cmd = cmd.parent;
492
- if (cmd) {
493
- cmds.push(cmd);
494
- }
495
- }
496
- return cmds;
497
- }
498
- /***
499
- * 将所有actions包装成一个链式调用的函数
500
- */
501
- wrapperChainActions() {
502
- const self = this;
503
- return function() {
504
- return __async(this, arguments, function* () {
505
- const args = Array.from(arguments);
506
- let preValue;
507
- let actionOpts = {}, actionArgs = [], cmd;
508
- if (args.length >= 2) {
509
- cmd = args[args.length - 1];
510
- actionOpts = args[args.length - 2];
511
- actionArgs = args.slice(0, args.length - 2);
512
- }
513
- yield self.executeBeforeHooks({ args: actionArgs, options: actionOpts, command: cmd });
514
- try {
515
- for (let action of self._actions) {
516
- try {
517
- if (action.enhance) {
518
- outputDebug("\u6267\u884C<{}>: args={}, options={}", () => [
519
- self.name(),
520
- actionArgs,
521
- actionOpts
522
- ]);
523
- preValue = yield action.fn.call(this, {
524
- command: cmd,
525
- value: preValue,
526
- args: actionArgs,
527
- options: actionOpts
528
- });
529
- } else {
530
- preValue = yield action.fn.apply(this, args);
531
- }
532
- if (preValue === BREAK)
533
- break;
534
- } catch (e) {
535
- outputDebug("\u547D\u4EE4{}\u7684Action({})\u6267\u884C\u51FA\u9519:{}", [self.name, action.id, e]);
536
- throw e;
537
- }
538
- }
539
- } finally {
540
- yield self.executeAfterHooks({
541
- value: preValue,
542
- args: actionArgs,
543
- options: actionOpts,
544
- command: cmd
545
- });
546
- }
547
- });
548
- };
549
- }
550
- /**
551
- * 当传入--work-dirs时用来处理工作目录
552
- */
553
- wrapperWorkDirsAction(fn) {
554
- const self = this;
555
- return function() {
556
- return __async(this, arguments, function* () {
557
- let workDirs = self._optionValues.workDirs;
558
- if (!workDirs) {
559
- return yield fn.apply(this, Array.from(arguments));
560
- }
561
- if (!Array.isArray(workDirs))
562
- workDirs = workDirs.split(",");
563
- workDirs = workDirs.reduce((dirs, dir) => {
564
- if (typeof dir == "string")
565
- dirs.push(...dir.split(","));
566
- return dirs;
567
- }, []);
568
- for (let workDir of workDirs) {
569
- const cwd = process.cwd();
570
- try {
571
- if (!path2.isAbsolute(workDir))
572
- workDir = path2.join(cwd, workDir);
573
- if (fs2.existsSync(workDir) && fs2.statSync(workDir).isDirectory()) {
574
- outputDebug("\u5207\u6362\u5230\u5DE5\u4F5C\u76EE\u5F55:{}", workDir);
575
- process.chdir(workDir);
576
- yield fn.apply(this, Array.from(arguments));
577
- } else {
578
- outputDebug("\u65E0\u6548\u7684\u5DE5\u4F5C\u76EE\u5F55:{}", workDir);
579
- }
580
- } catch (e) {
581
- throw e;
582
- } finally {
583
- process.chdir(cwd);
584
- }
585
- }
586
- });
587
- };
588
- }
589
- getOption(name) {
590
- return this.options.find((option) => option.name() == name);
591
- }
592
- /**
593
- * 添加一个Before钩子
594
- * @param listener
595
- * @param scope =false时代表只在本命令执行,=true时代表在本命令及其子命令执行
596
- * @returns
597
- */
598
- before(listener, scope = true) {
599
- this._beforeHooks.push([listener, scope]);
600
- return this;
601
- }
602
- executeBeforeHooks(args) {
603
- return __async(this, null, function* () {
604
- const hooks = this.beforeHooks.map(
605
- ([hook, scope]) => [hook, scope, this]
606
- );
607
- this.getAncestorCommands().forEach((cmd) => {
608
- hooks.unshift(
609
- ...cmd.beforeHooks.map(([hook, scope]) => {
610
- return [hook, scope, cmd];
611
- })
612
- );
613
- });
614
- for (let [hook, scope, cmd] of hooks) {
615
- if (!scope)
616
- continue;
617
- yield hook.call(cmd, args);
618
- }
619
- });
620
- }
621
- /**
622
- * 添加一个After钩子
623
- * @param listener
624
- * @param scope =false时代表只在本命令执行,=true时代表在本命令及其子命令执行
625
- * @returns
626
- */
627
- after(listener, scope = true) {
628
- this._afterHooks.push([listener, scope]);
629
- return this;
630
- }
631
- executeAfterHooks(args) {
632
- return __async(this, null, function* () {
633
- const hooks = this.afterHooks.map(
634
- ([hook, scope]) => [hook, scope, this]
635
- );
636
- this.getAncestorCommands().forEach((cmd) => {
637
- hooks.push(
638
- ...cmd.afterHooks.map(([hook, scope]) => {
639
- return [hook, scope, cmd];
640
- })
641
- );
642
- });
643
- for (let [hook, scope, cmd] of hooks) {
644
- if (!scope)
645
- continue;
646
- yield hook.call(cmd, args);
647
- }
648
- });
649
- }
650
- preActionHook(thisCommand, actionCommand) {
651
- return __async(this, null, function* () {
652
- if (this.isEnablePrompts()) {
653
- const questions = [
654
- ...this.generateAutoPrompts(),
655
- ...this._customPrompts
656
- ];
657
- if (questions.length > 0) {
658
- const results = yield prompts(questions);
659
- Object.entries(results).forEach(([key, value]) => {
660
- thisCommand.setOptionValue(key, value);
661
- });
662
- }
663
- }
664
- });
665
- }
666
- isEnablePrompts() {
667
- if (isEnablePrompts() === false) {
668
- return false;
669
- } else {
670
- return this._enable_prompts;
671
- }
672
- }
673
- /**
674
- * 生成选项自动提示
675
- *
676
- * @remarks
677
- * FlexCli要求所有未提供默认值的Option自动生成提示
678
- *
679
- * - 未提供默认值,并且是必选的参数Option
680
- * - 指定了choices但未提供有效值的Option
681
- *
682
- */
683
- generateAutoPrompts() {
684
- const options = this.options;
685
- const optionPromports = options.filter((option) => !option.hidden && option.__MIX_OPTION__).map((option) => option.getPrompt(this._optionValues[option.name()])).filter((prompt) => prompt);
686
- outputDebug("\u547D\u4EE4<{}>\u81EA\u52A8\u751F\u6210{}\u4E2A\u9009\u9879\u63D0\u793A:{}", [
687
- this.name(),
688
- optionPromports.length,
689
- optionPromports.map((prompt) => `${prompt.name}(${prompt.type})`).join(",")
690
- ]);
691
- return optionPromports;
692
- }
693
- option(flags, description, options) {
694
- const option = new MixOption(...arguments);
695
- if (option.required && !this.isEnablePrompts())
696
- option.mandatory = true;
697
- return this.addOption(option);
698
- }
699
- /**
700
- * 添加提示
701
- *
702
- * @remarks
703
- *
704
- * 添加一些自定义提示
705
- *
706
- *
707
- * @param questions
708
- * @param show 是否显示提示信息,auto表示只有在用户没有提供option的值时才显示提示信息,always表示总是显示提示信息,never表示不显示提示信息
709
- * @returns
710
- */
711
- prompt(questions) {
712
- this._customPrompts.push(...Array.isArray(questions) ? questions : [questions]);
713
- return this;
714
- }
715
- /**
716
- *
717
- * 选择命令并执行
718
- *
719
- * @remorks
720
- *
721
- * 当命令具有多个子命令时,并且没有提供默认子命令时,提示用户选择一个子命令
722
- *
723
- */
724
- selectCommands() {
725
- return __async(this, null, function* () {
726
- const choices = this.commands.map((command2) => ({
727
- title: `${command2.description()}(${command2.name()})`,
728
- value: command2.name()
729
- }));
730
- const result = yield prompts({
731
- type: "select",
732
- name: "command",
733
- message: "\u8BF7\u9009\u62E9\u547D\u4EE4:",
734
- choices
735
- });
736
- const command = this.commands.find((command2) => command2.name() === result.command);
737
- yield command == null ? void 0 : command.parseAsync([result.command], { from: "user" });
738
- });
739
- }
740
- /**
741
- * 禁用/启用所有提示
742
- */
743
- disablePrompts() {
744
- this._enable_prompts = false;
745
- return this;
746
- }
747
- enablePrompts() {
748
- this._enable_prompts = true;
749
- return this;
750
- }
751
- };
752
-
753
- // src/finder.ts
754
- import { getPackageJson } from "flex-tools/package/getPackageJson";
755
- import { getPackageRootPath } from "flex-tools/package/getPackageRootPath";
756
- import { globSync } from "glob";
757
- import fs3 from "fs";
758
- import path3 from "path";
759
- function getMatchedDependencies(entry) {
760
- const pacakgeMacher = this.options.include;
761
- if (!(pacakgeMacher instanceof RegExp))
762
- return [];
763
- const { dependencies = {}, devDependencies = {}, peerDependencies = {}, optionalDependencies = {}, bundleDependencies = {} } = getPackageJson(entry);
764
- const packageNames = [
765
- ...Object.keys(dependencies),
766
- ...Object.keys(devDependencies),
767
- ...Object.keys(peerDependencies),
768
- ...Object.keys(optionalDependencies),
769
- ...Object.keys(bundleDependencies)
770
- ];
771
- return packageNames.filter((name) => name !== "@voerka/cli" && pacakgeMacher.test(name));
772
- }
773
- function isMatched(str, reg) {
774
- const regexps = reg ? Array.isArray(reg) ? reg : [reg] : [];
775
- return regexps.some((regexp) => {
776
- if (typeof regexp === "string") {
777
- return new RegExp(regexp).test(str);
778
- } else if (regexp instanceof RegExp) {
779
- return regexp.test(str);
780
- } else {
781
- return false;
782
- }
783
- });
784
- }
785
- function findCliPaths(packageName, entry) {
786
- const includeMacher = this.options.include;
787
- const excludeMacher = this.options.exclude;
788
- if (!includeMacher)
789
- return [];
790
- const packageRoot = getPackageRootPath(entry || process.cwd());
791
- const packagePath = packageName ? path3.dirname(__require.resolve(packageName, { paths: [packageRoot] })) : packageRoot;
792
- if (!packagePath) {
793
- outputDebug("MixCli\u53EA\u80FD\u8FD0\u884C\u5728Nodejs\u73AF\u5883");
794
- return [];
795
- }
796
- const packageNames = getMatchedDependencies.call(this, packagePath);
797
- const cliDirs = [];
798
- if (entry !== void 0)
799
- cliDirs.push(path3.join(packagePath, this.options.cliDir));
800
- packageNames.filter((name) => {
801
- return isMatched(name, includeMacher) && !isMatched(name, excludeMacher);
802
- }).forEach((name) => {
803
- outputDebug("\u5339\u914D\u5305:{}", `${packageName ? name + " <- " + packageName : name}`);
804
- try {
805
- const packageEntry = path3.dirname(__require.resolve(name, { paths: packagePath ? [packagePath] : [process.cwd()] }));
806
- const packageCliDir = path3.join(packageEntry, this.options.cliDir);
807
- let dependencies = getMatchedDependencies.call(this, packageEntry);
808
- cliDirs.push(...dependencies.reduce((result, dependencie) => {
809
- outputDebug("\u5339\u914D\u5305:{}", `${dependencie} <- ${name}`);
810
- result.push(...findCliPaths.call(this, dependencie, packageEntry));
811
- return result;
812
- }, []));
813
- if (fs3.existsSync(packageCliDir)) {
814
- cliDirs.push(packageCliDir);
815
- }
816
- } catch (e) {
817
- outputDebug("\u89E3\u6790\u5305<{}>\u8DEF\u5F84\u51FA\u9519\uFF1A{}", [name, e.stack]);
818
- }
819
- });
820
- return [...new Set(cliDirs)];
821
- }
822
- function findCommands(cli) {
823
- return __async(this, null, function* () {
824
- const cliDirs = findCliPaths.call(cli);
825
- const commands = [];
826
- const files = [];
827
- cliDirs.forEach((dir) => {
828
- globSync("*", {
829
- cwd: dir,
830
- absolute: true
831
- }).forEach((file) => {
832
- const baseName = path3.basename(file);
833
- if (baseName.startsWith("_"))
834
- return;
835
- const ext = path3.extname(file).toLowerCase();
836
- if ([".js", ".cjs", ".mjs"].includes(ext)) {
837
- files.push(file);
838
- } else if (fs3.statSync(file).isDirectory()) {
839
- files.push(path3.join(file, "index.js"));
840
- files.push(path3.join(file, "index.cjs"));
841
- files.push(path3.join(file, "index.mjs"));
842
- }
843
- });
844
- });
845
- for (let file of files) {
846
- if (!fs3.existsSync(file))
847
- continue;
848
- try {
849
- outputDebug("\u5BFC\u5165\u547D\u4EE4:{}", file);
850
- if (file.endsWith(".cjs") || file.endsWith(".js")) {
851
- commands.push(yield importModule(file));
852
- } else if (file.endsWith(".mjs")) {
853
- const cmd = yield import(`file://${file}`);
854
- commands.push(cmd.default);
855
- }
856
- } catch (e) {
857
- outputDebug(e);
858
- }
859
- }
860
- return commands;
861
- });
862
- }
863
-
864
- // src/cli.ts
865
- import { asyncSignal } from "flex-tools/async/asyncSignal";
866
- import replaceAll from "string.prototype.replaceall";
867
- replaceAll.shim();
868
- var MixCli = class extends LiteEvent {
869
- constructor(options) {
870
- super();
871
- this.findSignals = [];
872
- this.options = assignObject({
873
- name: "mixcli",
874
- package: null,
875
- cliDir: "cli",
876
- prompt: "auto",
877
- ignoreError: false
878
- }, options);
879
- this.createRootCommand();
880
- }
881
- get context() {
882
- return this.options.context;
883
- }
884
- get name() {
885
- return this.options.name;
886
- }
887
- /**
888
- * 是否禁用了所有的交互提示
889
- */
890
- get isDisabledPrompts() {
891
- return this.root.rawArgs.includes("--no-prompts");
892
- }
893
- /**
894
- * 扫描当前工程的依赖,加载匹配include的依赖下的命令
895
- */
896
- installCommands() {
897
- return __async(this, null, function* () {
898
- const cmders = yield findCommands(this);
899
- for (let cmder of cmders) {
900
- try {
901
- if (typeof cmder === "function") {
902
- let cmds = cmder(this);
903
- cmds = cmds ? Array.isArray(cmds) ? cmds : [cmds] : [];
904
- this.register(() => cmds);
905
- }
906
- } catch (e) {
907
- outputDebug("\u6CE8\u518C\u547D\u4EE4\u5931\u8D25:{}", e.stack);
908
- }
909
- }
910
- });
911
- }
912
- /**
913
- * 创建根命令
914
- *
915
- */
916
- createRootCommand() {
917
- this.root = new MixCommand(this.name);
918
- this.root.helpOption("-h, --help").action(() => {
919
- if (this.options.logo)
920
- logsets2.log(fixIndent(this.options.logo, 2));
921
- console.log();
922
- let title = this.options.title || this.options.name;
923
- if (Array.isArray(title)) {
924
- logsets2.log(String(title[0]).firstUpper(), [...title.slice(1)]);
925
- } else {
926
- logsets2.log(`${title.firstUpper()} Version: {}`, this.options.version);
927
- }
928
- if (this.options.description)
929
- logsets2.log(logsets2.colors.darkGray(this.options.description));
930
- console.log();
931
- this.root.help();
932
- });
933
- addBuiltInOptions(this.root);
934
- if (this.options.before)
935
- this.root.hook("preAction", this.options.before);
936
- if (this.options.after)
937
- this.root.hook("postAction", this.options.after);
938
- }
939
- /**
940
- * 添加帮助选项
941
- *
942
- * @param text 帮助文本
943
- * @param position 显示位置,可选值:before|after|beforeAll|afterAll
944
- * @param fixIndent 是否自动修正缩进,如果为true,则会自动修正缩进,当显示多行时文本时,会自动修正缩进
945
- *
946
- */
947
- addHelp(text, { pos = "beforeAll", alignIndent = true }) {
948
- if (alignIndent)
949
- text = fixIndent(text, alignIndent);
950
- this.root.addHelpText(pos, text);
951
- }
952
- /**
953
- * 注册一个命令
954
- * @param cmd
955
- */
956
- register(cmd) {
957
- if (typeof cmd == "function") {
958
- let result = cmd(this);
959
- let cmds = result instanceof Array ? result : result == void 0 ? [] : [result];
960
- for (let cmd2 of cmds) {
961
- if (cmd2.__MIX_COMMAND__) {
962
- if (this.hasCommand(cmd2.name())) {
963
- logsets2.error(`Command <${cmd2.name()}> has been registered!`);
964
- } else {
965
- outputDebug("\u6CE8\u518C\u547D\u4EE4:{}", cmd2.fullname);
966
- this.root.addCommand(cmd2);
967
- cmd2._cli = this;
968
- this.emit("register", cmd2.fullname, true);
969
- }
970
- } else {
971
- logsets2.error(`Command <${cmd2.toString()}> is not a valid command!`);
972
- }
973
- }
974
- } else {
975
- logsets2.error("Invalid command");
976
- }
977
- }
978
- hasCommand(name) {
979
- return this.root.commands.some((c) => c.name() == name);
980
- }
981
- /**
982
- * 根据命令名称查找命令
983
- *
984
- * @remarks
985
- *
986
- * find("dev")
987
- * find("dev.microservice") 支持多级命令
988
- * find("abc",DevCommand) 允许指定从DevCommand下开始查找abc命令
989
- *
990
- * @param name
991
- */
992
- get(name) {
993
- const names = name.split(".");
994
- let curCmd = this.root;
995
- let resultCmd;
996
- while (names.length > 0) {
997
- const topName = names.shift();
998
- const r = curCmd.commands.find((c) => c.name() == topName);
999
- if (r && names.length == 0) {
1000
- resultCmd = r;
1001
- }
1002
- curCmd = r;
1003
- }
1004
- return resultCmd;
1005
- }
1006
- /**
1007
- * 查找一个命令
1008
- *
1009
- * 如果命令不存在,则等待命令注册后再返回
1010
- *
1011
- * 在多包场景下,如果命令在其他包中注册并且该包中的命令还没注册,则会等待命令注册后再返回
1012
- *
1013
- * @param name
1014
- * @returns
1015
- */
1016
- find(name) {
1017
- const cmd = this.get(name);
1018
- if (cmd) {
1019
- return Promise.resolve(cmd);
1020
- } else {
1021
- const signal = asyncSignal();
1022
- this.findSignals.push(signal);
1023
- return new Promise((resolve) => {
1024
- let listener;
1025
- listener = this.on("register", (fullname) => {
1026
- if (fullname == `${this.name}.${name}`) {
1027
- listener.off();
1028
- signal.resolve();
1029
- this.findSignals = this.findSignals.filter((s) => s != signal);
1030
- resolve(this.get(name));
1031
- }
1032
- }, { objectify: true });
1033
- });
1034
- }
1035
- }
1036
- /**
1037
- * 判断命令是否存在
1038
- *
1039
- * @param name
1040
- * @returns
1041
- */
1042
- exists(name) {
1043
- if (name in this.root.commands) {
1044
- return true;
1045
- } else {
1046
- return this.get(name) != void 0;
1047
- }
1048
- }
1049
- /**
1050
- * 运行命令行程序
1051
- */
1052
- run() {
1053
- this.installCommands().then(() => {
1054
- return Promise.all(this.findSignals.map((signal) => signal(1e4))).then(() => {
1055
- this.root.parseAsync(process.argv);
1056
- });
1057
- });
1058
- }
1059
- /**
1060
- * 创建一个命令
1061
- *
1062
- *
1063
- */
1064
- create() {
1065
- }
1066
- };
1067
- export {
1068
- BREAK,
1069
- MixCli,
1070
- MixCommand,
1071
- MixOption,
1072
- addBuiltInOptions,
1073
- createFileByTemplate,
1074
- fileExists,
1075
- fixIndent,
1076
- getId,
1077
- importModule,
1078
- isDebug,
1079
- isEnablePrompts,
1080
- mkDirs,
1081
- mkdir,
1082
- outputDebug,
1083
- outputStr,
1084
- readFile,
1085
- showError,
1086
- writeFile
1087
- };
1088
- //# sourceMappingURL=index.mjs.map