mixcli 3.0.10 → 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,1081 +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
- let params = {};
276
- if (arguments.length == 3 && typeof arguments[2] == "object") {
277
- params = Object.assign({}, arguments[2]);
278
- } else if (arguments.length == 3) {
279
- params.default = arguments[2];
280
- }
281
- if (params.prompt === void 0)
282
- params.prompt = "auto";
283
- if (params.default)
284
- this.default(params.default, params.defaultDescription);
285
- if (params.choices)
286
- this.choices(params.choices);
287
- if (params.conflicts)
288
- this.conflicts(params.conflicts);
289
- if (params.env)
290
- this.env(params.env);
291
- if (params.argParser)
292
- this.argParser(params.argParser);
293
- if (params.hideHelp)
294
- this.hideHelp(params.hideHelp);
295
- if (params.hidden)
296
- this.hidden = params.hidden;
297
- if (params.mandatory)
298
- this.makeOptionMandatory(params.mandatory);
299
- if (params.implies)
300
- this.implies(params.implies);
301
- if (params.optional)
302
- this.optional = params.optional;
303
- if (typeof params.validate == "function")
304
- this._validate = params.validate.bind(this);
305
- if (params.required) {
306
- this.required = params.required;
307
- if (!this._validate)
308
- this._validate = (value) => String(value).length > 0;
309
- }
310
- this.prompt = new PromptManager(this, params.prompt);
311
- }
312
- validate(value) {
313
- if (typeof this._validate == "function") {
314
- return this._validate(value);
315
- } else {
316
- return true;
317
- }
318
- }
319
- // @ts-ignore
320
- choices(values) {
321
- if (!this.promptChoices) {
322
- this.promptChoices = values.map((choice) => {
323
- if (typeof choice == "object") {
324
- return choice;
325
- } else {
326
- return { title: choice, value: choice };
327
- }
328
- });
329
- }
330
- super.choices(this.promptChoices.map((item) => item.value));
331
- }
332
- resetChoices() {
333
- super.choices(this.promptChoices.map((item) => item.value));
334
- }
335
- addChoice(value) {
336
- if (!this.promptChoices || !Array.isArray(this.promptChoices))
337
- this.promptChoices = [];
338
- this.promptChoices.push(typeof value == "string" ? { title: value, value } : value);
339
- this.resetChoices();
340
- }
341
- removeChoice(value) {
342
- var _a;
343
- this.promptChoices = (_a = this.promptChoices) == null ? void 0 : _a.filter((choice) => choice.value !== value);
344
- this.resetChoices();
345
- }
346
- clearChoice() {
347
- this.promptChoices = [];
348
- this.resetChoices();
349
- }
350
- /**
351
- * 返回选项的提示对象
352
- *
353
- * @remarks
354
- *
355
- *
356
- *
357
- * @param inputValue
358
- * @returns
359
- */
360
- getPrompt(inputValue) {
361
- var _a;
362
- return (_a = this.prompt) == null ? void 0 : _a.get(inputValue);
363
- }
364
- };
365
-
366
- // src/command.ts
367
- import path2 from "path";
368
- import fs2 from "fs";
369
- var BREAK = Symbol("BREAK_ACTION");
370
- var MixCommand = class extends Command {
371
- // 是否启用交互提示
372
- constructor(name) {
373
- super(name);
374
- this._beforeHooks = [];
375
- this._afterHooks = [];
376
- this._customPrompts = [];
377
- this._optionValues = {};
378
- // 命令行输入的选项值
379
- this._actions = [];
380
- // 允许多个action
381
- this._enable_prompts = true;
382
- const self = this;
383
- if (!this.isRoot)
384
- addBuiltInOptions(this);
385
- this.hook("preAction", function() {
386
- return __async(this, arguments, function* () {
387
- self._optionValues = self.getOptionValues(this.hookedCommand);
388
- try {
389
- yield self.preActionHook.apply(self, arguments);
390
- } catch (e) {
391
- }
392
- });
393
- });
394
- }
395
- /**
396
- * 是否是根命令
397
- */
398
- get isRoot() {
399
- return !!!this.parent;
400
- }
401
- get actions() {
402
- return this._actions;
403
- }
404
- get beforeHooks() {
405
- return this._beforeHooks;
406
- }
407
- get afterHooks() {
408
- return this._afterHooks;
409
- }
410
- get fullname() {
411
- let names = [this.name()];
412
- let parent = this.parent;
413
- while (parent) {
414
- if (parent.name() !== "root") {
415
- names.unshift(parent.name());
416
- }
417
- parent = parent.parent;
418
- }
419
- return names.join(".");
420
- }
421
- /**
422
- * 返回根命令
423
- */
424
- root() {
425
- let root = this;
426
- while (root && root.parent != null) {
427
- root = root.parent;
428
- }
429
- return root;
430
- }
431
- action(fn) {
432
- const actionFunc = arguments[0];
433
- if (arguments.length == 1 && typeof actionFunc == "function") {
434
- this._actions.push({
435
- id: Math.random().toString(36).substring(2),
436
- enhance: false,
437
- fn: actionFunc
438
- });
439
- } else if (arguments.length == 2 && typeof actionFunc == "function" && typeof arguments[1] == "object") {
440
- const actionFn = arguments[0];
441
- const actionOpts = Object.assign({ at: "append" }, arguments[1]);
442
- if (actionOpts.at == "replace")
443
- this._actions = [];
444
- const actionItem = {
445
- id: actionOpts.id || Math.random().toString(36).substring(2),
446
- enhance: actionOpts.enhance == void 0 ? true : actionOpts.enhance,
447
- fn: actionFn
448
- };
449
- if (typeof actionOpts.at == "number") {
450
- this._actions.splice(Number(actionOpts.at), 0, actionItem);
451
- } else if (["append", "before"].includes(actionOpts.at)) {
452
- this._actions.push(actionItem);
453
- } else if (["preappend", "after"].includes(actionOpts.at)) {
454
- this._actions.splice(0, 0, actionItem);
455
- } else {
456
- this._actions.push(actionItem);
457
- }
458
- } else {
459
- console.log("[mixcli] action params error");
460
- }
461
- return super.action(this.getWrapperedAction());
462
- }
463
- /**
464
- * 读取命令配置值,包括父命令提供的配置选项
465
- * @param command
466
- */
467
- getOptionValues(command) {
468
- let opts = {};
469
- let parent = command;
470
- while (parent) {
471
- Object.assign(opts, parent._optionValues);
472
- parent = parent.parent;
473
- }
474
- return opts;
475
- }
476
- /**
477
- * 本函数在运行时子类进行action生成该命令的action
478
- */
479
- getWrapperedAction() {
480
- return this.wrapperWorkDirsAction(this.wrapperChainActions());
481
- }
482
- /**
483
- * 向上查找所有祖先命令
484
- */
485
- getAncestorCommands() {
486
- let cmds = [];
487
- let cmd = this;
488
- while (cmd) {
489
- cmd = cmd.parent;
490
- if (cmd) {
491
- cmds.push(cmd);
492
- }
493
- }
494
- return cmds;
495
- }
496
- /***
497
- * 将所有actions包装成一个链式调用的函数
498
- */
499
- wrapperChainActions() {
500
- const self = this;
501
- return function() {
502
- return __async(this, arguments, function* () {
503
- const args = Array.from(arguments);
504
- let preValue;
505
- let actionOpts = {}, actionArgs = [], cmd;
506
- if (args.length >= 2) {
507
- cmd = args[args.length - 1];
508
- actionOpts = args[args.length - 2];
509
- actionArgs = args.slice(0, args.length - 2);
510
- }
511
- yield self.executeBeforeHooks({ args: actionArgs, options: actionOpts, command: cmd });
512
- try {
513
- for (let action of self._actions) {
514
- try {
515
- if (action.enhance) {
516
- outputDebug("\u6267\u884C<{}>: args={}, options={}", () => [
517
- self.name(),
518
- actionArgs,
519
- actionOpts
520
- ]);
521
- preValue = yield action.fn.call(this, {
522
- command: cmd,
523
- value: preValue,
524
- args: actionArgs,
525
- options: actionOpts
526
- });
527
- } else {
528
- preValue = yield action.fn.apply(this, args);
529
- }
530
- if (preValue === BREAK)
531
- break;
532
- } catch (e) {
533
- outputDebug("\u547D\u4EE4{}\u7684Action({})\u6267\u884C\u51FA\u9519:{}", [self.name, action.id, e]);
534
- throw e;
535
- }
536
- }
537
- } finally {
538
- yield self.executeAfterHooks({
539
- value: preValue,
540
- args: actionArgs,
541
- options: actionOpts,
542
- command: cmd
543
- });
544
- }
545
- });
546
- };
547
- }
548
- /**
549
- * 当传入--work-dirs时用来处理工作目录
550
- */
551
- wrapperWorkDirsAction(fn) {
552
- const self = this;
553
- return function() {
554
- return __async(this, arguments, function* () {
555
- let workDirs = self._optionValues.workDirs;
556
- if (!workDirs) {
557
- return yield fn.apply(this, Array.from(arguments));
558
- }
559
- if (!Array.isArray(workDirs))
560
- workDirs = workDirs.split(",");
561
- workDirs = workDirs.reduce((dirs, dir) => {
562
- if (typeof dir == "string")
563
- dirs.push(...dir.split(","));
564
- return dirs;
565
- }, []);
566
- for (let workDir of workDirs) {
567
- const cwd = process.cwd();
568
- try {
569
- if (!path2.isAbsolute(workDir))
570
- workDir = path2.join(cwd, workDir);
571
- if (fs2.existsSync(workDir) && fs2.statSync(workDir).isDirectory()) {
572
- outputDebug("\u5207\u6362\u5230\u5DE5\u4F5C\u76EE\u5F55:{}", workDir);
573
- process.chdir(workDir);
574
- yield fn.apply(this, Array.from(arguments));
575
- } else {
576
- outputDebug("\u65E0\u6548\u7684\u5DE5\u4F5C\u76EE\u5F55:{}", workDir);
577
- }
578
- } catch (e) {
579
- throw e;
580
- } finally {
581
- process.chdir(cwd);
582
- }
583
- }
584
- });
585
- };
586
- }
587
- getOption(name) {
588
- return this.options.find((option) => option.name() == name);
589
- }
590
- /**
591
- * 添加一个Before钩子
592
- * @param listener
593
- * @param scope =false时代表只在本命令执行,=true时代表在本命令及其子命令执行
594
- * @returns
595
- */
596
- before(listener, scope = true) {
597
- this._beforeHooks.push([listener, scope]);
598
- return this;
599
- }
600
- executeBeforeHooks(args) {
601
- return __async(this, null, function* () {
602
- const hooks = this.beforeHooks.map(
603
- ([hook, scope]) => [hook, scope, this]
604
- );
605
- this.getAncestorCommands().forEach((cmd) => {
606
- hooks.unshift(
607
- ...cmd.beforeHooks.map(([hook, scope]) => {
608
- return [hook, scope, cmd];
609
- })
610
- );
611
- });
612
- for (let [hook, scope, cmd] of hooks) {
613
- if (!scope)
614
- continue;
615
- yield hook.call(cmd, args);
616
- }
617
- });
618
- }
619
- /**
620
- * 添加一个After钩子
621
- * @param listener
622
- * @param scope =false时代表只在本命令执行,=true时代表在本命令及其子命令执行
623
- * @returns
624
- */
625
- after(listener, scope = true) {
626
- this._afterHooks.push([listener, scope]);
627
- return this;
628
- }
629
- executeAfterHooks(args) {
630
- return __async(this, null, function* () {
631
- const hooks = this.afterHooks.map(
632
- ([hook, scope]) => [hook, scope, this]
633
- );
634
- this.getAncestorCommands().forEach((cmd) => {
635
- hooks.push(
636
- ...cmd.afterHooks.map(([hook, scope]) => {
637
- return [hook, scope, cmd];
638
- })
639
- );
640
- });
641
- for (let [hook, scope, cmd] of hooks) {
642
- if (!scope)
643
- continue;
644
- yield hook.call(cmd, args);
645
- }
646
- });
647
- }
648
- preActionHook(thisCommand, actionCommand) {
649
- return __async(this, null, function* () {
650
- if (this.isEnablePrompts()) {
651
- const questions = [
652
- ...this.generateAutoPrompts(),
653
- ...this._customPrompts
654
- ];
655
- if (questions.length > 0) {
656
- const results = yield prompts(questions);
657
- Object.entries(results).forEach(([key, value]) => {
658
- thisCommand.setOptionValue(key, value);
659
- });
660
- }
661
- }
662
- });
663
- }
664
- isEnablePrompts() {
665
- if (isEnablePrompts() === false) {
666
- return false;
667
- } else {
668
- return this._enable_prompts;
669
- }
670
- }
671
- /**
672
- * 生成选项自动提示
673
- *
674
- * @remarks
675
- * FlexCli要求所有未提供默认值的Option自动生成提示
676
- *
677
- * - 未提供默认值,并且是必选的参数Option
678
- * - 指定了choices但未提供有效值的Option
679
- *
680
- */
681
- generateAutoPrompts() {
682
- 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);
684
- outputDebug("\u547D\u4EE4<{}>\u81EA\u52A8\u751F\u6210{}\u4E2A\u9009\u9879\u63D0\u793A:{}", [
685
- this.name(),
686
- optionPromports.length,
687
- optionPromports.map((prompt) => `${prompt.name}(${prompt.type})`).join(",")
688
- ]);
689
- return optionPromports;
690
- }
691
- option(flags, description, options) {
692
- const option = new MixOption(...arguments);
693
- if (option.required && !this.isEnablePrompts())
694
- option.mandatory = true;
695
- return this.addOption(option);
696
- }
697
- /**
698
- * 添加提示
699
- *
700
- * @remarks
701
- *
702
- * 添加一些自定义提示
703
- *
704
- *
705
- * @param questions
706
- * @param show 是否显示提示信息,auto表示只有在用户没有提供option的值时才显示提示信息,always表示总是显示提示信息,never表示不显示提示信息
707
- * @returns
708
- */
709
- prompt(questions) {
710
- this._customPrompts.push(...Array.isArray(questions) ? questions : [questions]);
711
- return this;
712
- }
713
- /**
714
- *
715
- * 选择命令并执行
716
- *
717
- * @remorks
718
- *
719
- * 当命令具有多个子命令时,并且没有提供默认子命令时,提示用户选择一个子命令
720
- *
721
- */
722
- selectCommands() {
723
- return __async(this, null, function* () {
724
- const choices = this.commands.map((command2) => ({
725
- title: `${command2.description()}(${command2.name()})`,
726
- value: command2.name()
727
- }));
728
- const result = yield prompts({
729
- type: "select",
730
- name: "command",
731
- message: "\u8BF7\u9009\u62E9\u547D\u4EE4:",
732
- choices
733
- });
734
- const command = this.commands.find((command2) => command2.name() === result.command);
735
- yield command == null ? void 0 : command.parseAsync([result.command], { from: "user" });
736
- });
737
- }
738
- /**
739
- * 禁用/启用所有提示
740
- */
741
- disablePrompts() {
742
- this._enable_prompts = false;
743
- return this;
744
- }
745
- enablePrompts() {
746
- this._enable_prompts = true;
747
- return this;
748
- }
749
- };
750
-
751
- // src/finder.ts
752
- import { getPackageJson } from "flex-tools/package/getPackageJson";
753
- import { getPackageRootPath } from "flex-tools/package/getPackageRootPath";
754
- import { globSync } from "glob";
755
- import fs3 from "fs";
756
- import path3 from "path";
757
- function getMatchedDependencies(entry) {
758
- const pacakgeMacher = this.options.include;
759
- if (!(pacakgeMacher instanceof RegExp))
760
- return [];
761
- const { dependencies = {}, devDependencies = {}, peerDependencies = {}, optionalDependencies = {}, bundleDependencies = {} } = getPackageJson(entry);
762
- const packageNames = [
763
- ...Object.keys(dependencies),
764
- ...Object.keys(devDependencies),
765
- ...Object.keys(peerDependencies),
766
- ...Object.keys(optionalDependencies),
767
- ...Object.keys(bundleDependencies)
768
- ];
769
- return packageNames.filter((name) => name !== "@voerka/cli" && pacakgeMacher.test(name));
770
- }
771
- function isMatched(str, reg) {
772
- const regexps = reg ? Array.isArray(reg) ? reg : [reg] : [];
773
- return regexps.some((regexp) => {
774
- if (typeof regexp === "string") {
775
- return new RegExp(regexp).test(str);
776
- } else if (regexp instanceof RegExp) {
777
- return regexp.test(str);
778
- } else {
779
- return false;
780
- }
781
- });
782
- }
783
- function findCliPaths(packageName, entry) {
784
- const includeMacher = this.options.include;
785
- const excludeMacher = this.options.exclude;
786
- if (!includeMacher)
787
- return [];
788
- const packageRoot = getPackageRootPath(entry || process.cwd());
789
- const packagePath = packageName ? path3.dirname(__require.resolve(packageName, { paths: [packageRoot] })) : packageRoot;
790
- if (!packagePath) {
791
- outputDebug("MixCli\u53EA\u80FD\u8FD0\u884C\u5728Nodejs\u73AF\u5883");
792
- return [];
793
- }
794
- const packageNames = getMatchedDependencies.call(this, packagePath);
795
- const cliDirs = [];
796
- if (entry !== void 0)
797
- cliDirs.push(path3.join(packagePath, this.options.cliDir));
798
- packageNames.filter((name) => {
799
- return isMatched(name, includeMacher) && !isMatched(name, excludeMacher);
800
- }).forEach((name) => {
801
- outputDebug("\u5339\u914D\u5305:{}", `${packageName ? name + " <- " + packageName : name}`);
802
- try {
803
- const packageEntry = path3.dirname(__require.resolve(name, { paths: packagePath ? [packagePath] : [process.cwd()] }));
804
- const packageCliDir = path3.join(packageEntry, this.options.cliDir);
805
- let dependencies = getMatchedDependencies.call(this, packageEntry);
806
- cliDirs.push(...dependencies.reduce((result, dependencie) => {
807
- outputDebug("\u5339\u914D\u5305:{}", `${dependencie} <- ${name}`);
808
- result.push(...findCliPaths.call(this, dependencie, packageEntry));
809
- return result;
810
- }, []));
811
- if (fs3.existsSync(packageCliDir)) {
812
- cliDirs.push(packageCliDir);
813
- }
814
- } catch (e) {
815
- outputDebug("\u89E3\u6790\u5305<{}>\u8DEF\u5F84\u51FA\u9519\uFF1A{}", [name, e.stack]);
816
- }
817
- });
818
- return [...new Set(cliDirs)];
819
- }
820
- function findCommands(cli) {
821
- return __async(this, null, function* () {
822
- const cliDirs = findCliPaths.call(cli);
823
- const commands = [];
824
- const files = [];
825
- cliDirs.forEach((dir) => {
826
- globSync("*", {
827
- cwd: dir,
828
- absolute: true
829
- }).forEach((file) => {
830
- const baseName = path3.basename(file);
831
- if (baseName.startsWith("_"))
832
- return;
833
- const ext = path3.extname(file).toLowerCase();
834
- if ([".js", ".cjs", ".mjs"].includes(ext)) {
835
- files.push(file);
836
- } else if (fs3.statSync(file).isDirectory()) {
837
- files.push(path3.join(file, "index.js"));
838
- files.push(path3.join(file, "index.cjs"));
839
- files.push(path3.join(file, "index.mjs"));
840
- }
841
- });
842
- });
843
- for (let file of files) {
844
- if (!fs3.existsSync(file))
845
- continue;
846
- try {
847
- outputDebug("\u5BFC\u5165\u547D\u4EE4:{}", file);
848
- if (file.endsWith(".cjs") || file.endsWith(".js")) {
849
- commands.push(yield importModule(file));
850
- } else if (file.endsWith(".mjs")) {
851
- const cmd = yield import(`file://${file}`);
852
- commands.push(cmd.default);
853
- }
854
- } catch (e) {
855
- outputDebug(e);
856
- }
857
- }
858
- return commands;
859
- });
860
- }
861
-
862
- // src/cli.ts
863
- import { asyncSignal } from "flex-tools/async/asyncSignal";
864
- import replaceAll from "string.prototype.replaceall";
865
- replaceAll.shim();
866
- var MixCli = class extends LiteEvent {
867
- constructor(options) {
868
- super();
869
- this.findSignals = [];
870
- this.options = assignObject({
871
- name: "mixcli",
872
- package: null,
873
- cliDir: "cli",
874
- prompt: "auto"
875
- }, options);
876
- this.createRootCommand();
877
- }
878
- get context() {
879
- return this.options.context;
880
- }
881
- get name() {
882
- return this.options.name;
883
- }
884
- /**
885
- * 是否禁用了所有的交互提示
886
- */
887
- get isDisabledPrompts() {
888
- return this.root.rawArgs.includes("--no-prompts");
889
- }
890
- /**
891
- * 扫描当前工程的依赖,加载匹配include的依赖下的命令
892
- */
893
- installCommands() {
894
- return __async(this, null, function* () {
895
- const cmders = yield findCommands(this);
896
- for (let cmder of cmders) {
897
- try {
898
- if (typeof cmder === "function") {
899
- let cmds = cmder(this);
900
- cmds = cmds ? Array.isArray(cmds) ? cmds : [cmds] : [];
901
- this.register(() => cmds);
902
- }
903
- } catch (e) {
904
- }
905
- }
906
- });
907
- }
908
- /**
909
- * 创建根命令
910
- *
911
- */
912
- createRootCommand() {
913
- this.root = new MixCommand(this.name);
914
- this.root.helpOption("-h, --help").action(() => {
915
- if (this.options.logo)
916
- logsets2.log(fixIndent(this.options.logo, 2));
917
- console.log();
918
- let title = this.options.title || this.options.name;
919
- if (Array.isArray(title)) {
920
- logsets2.log(String(title[0]).firstUpper(), [...title.slice(1)]);
921
- } else {
922
- logsets2.log(`${title.firstUpper()} Version: {}`, this.options.version);
923
- }
924
- if (this.options.description)
925
- logsets2.log(logsets2.colors.darkGray(this.options.description));
926
- console.log();
927
- this.root.help();
928
- });
929
- addBuiltInOptions(this.root);
930
- if (this.options.before)
931
- this.root.hook("preAction", this.options.before);
932
- if (this.options.after)
933
- this.root.hook("postAction", this.options.after);
934
- }
935
- /**
936
- * 添加帮助选项
937
- *
938
- * @param text 帮助文本
939
- * @param position 显示位置,可选值:before|after|beforeAll|afterAll
940
- * @param fixIndent 是否自动修正缩进,如果为true,则会自动修正缩进,当显示多行时文本时,会自动修正缩进
941
- *
942
- */
943
- addHelp(text, { pos = "beforeAll", alignIndent = true }) {
944
- if (alignIndent)
945
- text = fixIndent(text, alignIndent);
946
- this.root.addHelpText(pos, text);
947
- }
948
- /**
949
- * 注册一个命令
950
- * @param cmd
951
- */
952
- register(cmd) {
953
- if (typeof cmd == "function") {
954
- let result = cmd(this);
955
- let cmds = result instanceof Array ? result : result == void 0 ? [] : [result];
956
- for (let cmd2 of cmds) {
957
- if (cmd2 instanceof MixCommand) {
958
- if (this.hasCommand(cmd2.name())) {
959
- logsets2.error(`Command <${cmd2.name()}> has been registered!`);
960
- } else {
961
- this.root.addCommand(cmd2);
962
- cmd2._cli = this;
963
- this.emit("register", cmd2.fullname, true);
964
- }
965
- }
966
- }
967
- } else {
968
- logsets2.error("Invalid command");
969
- }
970
- }
971
- hasCommand(name) {
972
- return this.root.commands.some((c) => c.name() == name);
973
- }
974
- /**
975
- * 根据命令名称查找命令
976
- *
977
- * @remarks
978
- *
979
- * find("dev")
980
- * find("dev.microservice") 支持多级命令
981
- * find("abc",DevCommand) 允许指定从DevCommand下开始查找abc命令
982
- *
983
- * @param name
984
- */
985
- get(name) {
986
- const names = name.split(".");
987
- let curCmd = this.root;
988
- let resultCmd;
989
- while (names.length > 0) {
990
- const topName = names.shift();
991
- const r = curCmd.commands.find((c) => c.name() == topName);
992
- if (r && names.length == 0) {
993
- resultCmd = r;
994
- }
995
- curCmd = r;
996
- }
997
- return resultCmd;
998
- }
999
- /**
1000
- * 查找一个命令
1001
- *
1002
- * 如果命令不存在,则等待命令注册后再返回
1003
- *
1004
- * 在多包场景下,如果命令在其他包中注册并且该包中的命令还没注册,则会等待命令注册后再返回
1005
- *
1006
- * @param name
1007
- * @returns
1008
- */
1009
- find(name) {
1010
- const cmd = this.get(name);
1011
- if (cmd) {
1012
- return Promise.resolve(cmd);
1013
- } else {
1014
- const signal = asyncSignal();
1015
- this.findSignals.push(signal);
1016
- return new Promise((resolve) => {
1017
- let listener;
1018
- listener = this.on("register", (fullname) => {
1019
- if (fullname == `${this.name}.${name}`) {
1020
- listener.off();
1021
- signal.resolve();
1022
- this.findSignals = this.findSignals.filter((s) => s != signal);
1023
- resolve(this.get(name));
1024
- }
1025
- }, { objectify: true });
1026
- });
1027
- }
1028
- }
1029
- /**
1030
- * 判断命令是否存在
1031
- *
1032
- * @param name
1033
- * @returns
1034
- */
1035
- exists(name) {
1036
- if (name in this.root.commands) {
1037
- return true;
1038
- } else {
1039
- return this.get(name) != void 0;
1040
- }
1041
- }
1042
- /**
1043
- * 运行命令行程序
1044
- */
1045
- run() {
1046
- this.installCommands().then(() => {
1047
- return Promise.all(this.findSignals.map((signal) => signal(1e4))).then(() => {
1048
- this.root.parseAsync(process.argv);
1049
- });
1050
- });
1051
- }
1052
- /**
1053
- * 创建一个命令
1054
- *
1055
- *
1056
- */
1057
- create() {
1058
- }
1059
- };
1060
- export {
1061
- BREAK,
1062
- MixCli,
1063
- MixCommand,
1064
- MixOption,
1065
- addBuiltInOptions,
1066
- createFileByTemplate,
1067
- fileExists,
1068
- fixIndent,
1069
- getId,
1070
- importModule,
1071
- isDebug,
1072
- isEnablePrompts,
1073
- mkDirs,
1074
- mkdir,
1075
- outputDebug,
1076
- outputStr,
1077
- readFile,
1078
- showError,
1079
- writeFile
1080
- };
1081
- //# sourceMappingURL=index.mjs.map