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