@tsed/cli-core 7.0.0-alpha.9 → 7.0.0-beta.10
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/lib/esm/CliCore.js +37 -37
- package/lib/esm/decorators/command.js +1 -1
- package/lib/esm/decorators/index.js +0 -4
- package/lib/esm/fn/command.js +31 -3
- package/lib/esm/interfaces/ProjectPreferences.js +1 -0
- package/lib/esm/interfaces/index.js +1 -1
- package/lib/esm/packageManagers/PackageManagersModule.js +11 -19
- package/lib/esm/packageManagers/index.js +1 -0
- package/lib/esm/packageManagers/supports/BaseManager.js +2 -6
- package/lib/esm/packageManagers/supports/YarnBerryManager.js +4 -1
- package/lib/esm/services/CliFs.js +3 -1
- package/lib/esm/services/CliHttpClient.js +3 -2
- package/lib/esm/services/CliHttpLogClient.js +1 -1
- package/lib/esm/services/CliLoadFile.js +5 -18
- package/lib/esm/services/CliPlugins.js +2 -3
- package/lib/esm/services/CliService.js +59 -71
- package/lib/esm/services/ProjectPackageJson.js +17 -4
- package/lib/esm/utils/createInjector.js +1 -1
- package/lib/esm/utils/getCommandMetadata.js +34 -7
- package/lib/esm/utils/index.js +1 -0
- package/lib/esm/utils/loadPlugins.js +5 -18
- package/lib/esm/utils/validate.js +23 -0
- package/lib/types/CliCore.d.ts +4 -9
- package/lib/types/decorators/command.d.ts +2 -2
- package/lib/types/decorators/index.d.ts +0 -4
- package/lib/types/fn/command.d.ts +58 -3
- package/lib/types/interfaces/CommandMetadata.d.ts +17 -15
- package/lib/types/interfaces/{CommandParameters.d.ts → CommandOptions.d.ts} +20 -3
- package/lib/types/interfaces/CommandProvider.d.ts +0 -10
- package/lib/types/interfaces/ProjectPreferences.d.ts +2 -1
- package/lib/types/interfaces/index.d.ts +12 -4
- package/lib/types/packageManagers/PackageManagersModule.d.ts +1 -2
- package/lib/types/packageManagers/index.d.ts +1 -0
- package/lib/types/services/CliHttpLogClient.d.ts +1 -1
- package/lib/types/services/CliLoadFile.d.ts +2 -4
- package/lib/types/services/CliPlugins.d.ts +0 -1
- package/lib/types/services/CliService.d.ts +4 -10
- package/lib/types/services/ProjectPackageJson.d.ts +9 -0
- package/lib/types/utils/index.d.ts +1 -0
- package/lib/types/utils/mapCommanderArgs.d.ts +1 -1
- package/lib/types/utils/resolveConfiguration.d.ts +1 -1
- package/lib/types/utils/validate.d.ts +14 -0
- package/package.json +3 -3
- package/readme.md +1 -1
- package/lib/esm/decorators/on.js +0 -8
- package/lib/esm/decorators/onAdd.js +0 -5
- package/lib/esm/decorators/onExec.js +0 -5
- package/lib/esm/decorators/onPostInstall.js +0 -5
- package/lib/esm/decorators/onPrompt.js +0 -5
- package/lib/esm/domains/CommandStoreKeys.js +0 -8
- package/lib/types/decorators/on.d.ts +0 -1
- package/lib/types/decorators/onAdd.d.ts +0 -1
- package/lib/types/decorators/onExec.d.ts +0 -1
- package/lib/types/decorators/onPostInstall.d.ts +0 -1
- package/lib/types/decorators/onPrompt.d.ts +0 -1
- package/lib/types/domains/CommandStoreKeys.d.ts +0 -7
- /package/lib/esm/interfaces/{CommandParameters.js → CommandOptions.js} +0 -0
package/lib/esm/CliCore.js
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import "@tsed/logger-std";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
|
-
import {
|
|
4
|
-
import { inject, injectable, InjectorService } from "@tsed/di";
|
|
3
|
+
import { constant, inject, injector } from "@tsed/di";
|
|
5
4
|
import { $asyncEmit } from "@tsed/hooks";
|
|
6
5
|
import chalk from "chalk";
|
|
7
6
|
import { Command } from "commander";
|
|
8
7
|
import semver from "semver";
|
|
9
8
|
import updateNotifier from "update-notifier";
|
|
10
9
|
import { CliError } from "./domains/CliError.js";
|
|
11
|
-
import { CliPackageJson } from "./services/CliPackageJson.js";
|
|
12
10
|
import { CliService } from "./services/CliService.js";
|
|
13
|
-
import { ProjectPackageJson } from "./services/ProjectPackageJson.js";
|
|
14
11
|
import { createInjector } from "./utils/createInjector.js";
|
|
15
12
|
import { loadPlugins } from "./utils/loadPlugins.js";
|
|
16
13
|
import { resolveConfiguration } from "./utils/resolveConfiguration.js";
|
|
@@ -18,9 +15,21 @@ function isHelpManual(argv) {
|
|
|
18
15
|
return argv.includes("-h") || argv.includes("--help");
|
|
19
16
|
}
|
|
20
17
|
export class CliCore {
|
|
21
|
-
constructor() {
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
constructor(settings) {
|
|
19
|
+
createInjector(settings);
|
|
20
|
+
}
|
|
21
|
+
static checkPrecondition(settings) {
|
|
22
|
+
const { pkg } = settings;
|
|
23
|
+
this.checkPackage(pkg);
|
|
24
|
+
if (pkg?.engines?.node) {
|
|
25
|
+
this.checkNodeVersion(pkg.engines.node, pkg.name);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
static checkPackage(pkg) {
|
|
29
|
+
if (!pkg) {
|
|
30
|
+
console.log(chalk.red(`settings.pkg is required. Require the package.json of your CLI when you bootstrap the CLI.`));
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
24
33
|
}
|
|
25
34
|
static checkNodeVersion(wanted, id) {
|
|
26
35
|
if (!semver.satisfies(process.version, wanted)) {
|
|
@@ -35,35 +44,16 @@ export class CliCore {
|
|
|
35
44
|
}
|
|
36
45
|
return this;
|
|
37
46
|
}
|
|
38
|
-
static async
|
|
47
|
+
static async bootstrap(settings) {
|
|
48
|
+
if (settings.checkPrecondition) {
|
|
49
|
+
this.checkPrecondition(settings);
|
|
50
|
+
}
|
|
51
|
+
if (settings.updateNotifier) {
|
|
52
|
+
await this.updateNotifier(settings.pkg);
|
|
53
|
+
}
|
|
39
54
|
settings = resolveConfiguration(settings);
|
|
40
|
-
const injector = this.createInjector(settings);
|
|
41
|
-
settings.plugins && (await loadPlugins());
|
|
42
|
-
await this.loadInjector(injector, module);
|
|
43
|
-
await $asyncEmit("$onReady");
|
|
44
|
-
return inject(CliCore);
|
|
45
|
-
}
|
|
46
|
-
static async bootstrap(settings, module = CliCore) {
|
|
47
|
-
const cli = await this.create(settings, module);
|
|
48
|
-
return cli.bootstrap();
|
|
49
|
-
}
|
|
50
|
-
static async loadInjector(injector, module = CliCore) {
|
|
51
|
-
await injector.emit("$beforeInit");
|
|
52
|
-
injector.addProvider(CliCore, {
|
|
53
|
-
useClass: module
|
|
54
|
-
});
|
|
55
|
-
await injector.load();
|
|
56
|
-
await injector.invoke(module);
|
|
57
|
-
await $asyncEmit("$afterInit");
|
|
58
|
-
injector.settings.set("loaded", true);
|
|
59
|
-
}
|
|
60
|
-
static async updateNotifier(pkg) {
|
|
61
|
-
updateNotifier({ pkg, updateCheckInterval: 0 }).notify();
|
|
62
|
-
return this;
|
|
63
|
-
}
|
|
64
|
-
static createInjector(settings) {
|
|
65
55
|
const argv = settings.argv || process.argv;
|
|
66
|
-
return
|
|
56
|
+
return new CliCore({
|
|
67
57
|
...settings,
|
|
68
58
|
name: settings.name || "tsed",
|
|
69
59
|
argv,
|
|
@@ -73,7 +63,11 @@ export class CliCore {
|
|
|
73
63
|
scriptsDir: "scripts",
|
|
74
64
|
...(settings.project || {})
|
|
75
65
|
}
|
|
76
|
-
});
|
|
66
|
+
}).bootstrap();
|
|
67
|
+
}
|
|
68
|
+
static async updateNotifier(pkg) {
|
|
69
|
+
updateNotifier({ pkg, updateCheckInterval: 0 }).notify();
|
|
70
|
+
return this;
|
|
77
71
|
}
|
|
78
72
|
static getProjectRoot(argv) {
|
|
79
73
|
if (!isHelpManual(argv)) {
|
|
@@ -84,7 +78,14 @@ export class CliCore {
|
|
|
84
78
|
}
|
|
85
79
|
async bootstrap() {
|
|
86
80
|
try {
|
|
87
|
-
|
|
81
|
+
const cliService = inject(CliService);
|
|
82
|
+
constant("plugins") && (await loadPlugins());
|
|
83
|
+
await $asyncEmit("$beforeInit");
|
|
84
|
+
await injector().load();
|
|
85
|
+
await $asyncEmit("$afterInit");
|
|
86
|
+
injector().settings.set("loaded", true);
|
|
87
|
+
await $asyncEmit("$onReady");
|
|
88
|
+
await cliService.parseArgs(constant("argv"));
|
|
88
89
|
}
|
|
89
90
|
catch (er) {
|
|
90
91
|
throw new CliError({ origin: er, cli: this });
|
|
@@ -92,4 +93,3 @@ export class CliCore {
|
|
|
92
93
|
return this;
|
|
93
94
|
}
|
|
94
95
|
}
|
|
95
|
-
injectable(CliCore).imports([CliPackageJson, ProjectPackageJson, CliService]);
|
package/lib/esm/fn/command.js
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
import { injectable } from "@tsed/di";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { JsonSchema } from "@tsed/schema";
|
|
3
|
+
JsonSchema.add("prompt", function prompt(label) {
|
|
4
|
+
this.customKey("x-label", label);
|
|
5
|
+
return this;
|
|
6
|
+
})
|
|
7
|
+
.add("when", function when(fn) {
|
|
8
|
+
this.customKey("x-when", fn);
|
|
9
|
+
return this;
|
|
10
|
+
})
|
|
11
|
+
.add("opt", function opt(v) {
|
|
12
|
+
this.customKey("x-opt", v);
|
|
13
|
+
return this;
|
|
14
|
+
})
|
|
15
|
+
.add("choices", function choices(choices) {
|
|
16
|
+
this.customKey("x-choices", choices);
|
|
17
|
+
return this;
|
|
18
|
+
});
|
|
19
|
+
export function command(options) {
|
|
20
|
+
if (!options.token) {
|
|
21
|
+
return injectable(Symbol.for(`COMMAND_${options.name}`))
|
|
22
|
+
.type("command")
|
|
23
|
+
.set("command", options)
|
|
24
|
+
.factory(() => {
|
|
25
|
+
return {
|
|
26
|
+
...options,
|
|
27
|
+
$prompt: options.prompt,
|
|
28
|
+
$exec: options.handler
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return injectable(options.token).type("command").set("command", options);
|
|
5
33
|
}
|
|
@@ -2,7 +2,7 @@ import { Type } from "@tsed/core";
|
|
|
2
2
|
export * from "./CliDefaultOptions.js";
|
|
3
3
|
export * from "./CommandData.js";
|
|
4
4
|
export * from "./CommandMetadata.js";
|
|
5
|
-
export * from "./
|
|
5
|
+
export * from "./CommandOptions.js";
|
|
6
6
|
export * from "./CommandProvider.js";
|
|
7
7
|
export * from "./PackageJson.js";
|
|
8
8
|
export * from "./ProjectPreferences.js";
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Inject, injectable } from "@tsed/di";
|
|
1
|
+
import { Inject, inject, injectable, injectMany } from "@tsed/di";
|
|
3
2
|
import { EMPTY, throwError } from "rxjs";
|
|
4
3
|
import { catchError } from "rxjs/operators";
|
|
5
4
|
import { ProjectPackageJson } from "../services/ProjectPackageJson.js";
|
|
@@ -18,17 +17,19 @@ function mapPackagesWithInvalidVersion(deps) {
|
|
|
18
17
|
.filter(([, version]) => !isValidVersion(version))
|
|
19
18
|
.map(toString);
|
|
20
19
|
}
|
|
21
|
-
|
|
22
|
-
constructor(
|
|
23
|
-
this.
|
|
24
|
-
this.packageManagers =
|
|
20
|
+
export class PackageManagersModule {
|
|
21
|
+
constructor() {
|
|
22
|
+
this.projectPackageJson = inject(ProjectPackageJson);
|
|
23
|
+
this.packageManagers = injectMany("package:manager").filter((manager) => {
|
|
24
|
+
return manager.has();
|
|
25
|
+
});
|
|
25
26
|
}
|
|
26
27
|
init(options = {}) {
|
|
27
28
|
const packageManager = this.get(options.packageManager);
|
|
28
29
|
options.packageManager = packageManager.name;
|
|
29
30
|
options = {
|
|
30
31
|
...options,
|
|
31
|
-
cwd: this.projectPackageJson.
|
|
32
|
+
cwd: this.projectPackageJson.cwd,
|
|
32
33
|
env: {
|
|
33
34
|
...process.env,
|
|
34
35
|
GH_TOKEN: this.projectPackageJson.GH_TOKEN
|
|
@@ -45,7 +46,7 @@ let PackageManagersModule = class PackageManagersModule {
|
|
|
45
46
|
const deps = mapPackagesWithInvalidVersion(this.projectPackageJson.dependencies);
|
|
46
47
|
options = {
|
|
47
48
|
...options,
|
|
48
|
-
cwd: this.projectPackageJson.
|
|
49
|
+
cwd: this.projectPackageJson.cwd,
|
|
49
50
|
env: {
|
|
50
51
|
...process.env,
|
|
51
52
|
GH_TOKEN: this.projectPackageJson.GH_TOKEN
|
|
@@ -116,14 +117,5 @@ let PackageManagersModule = class PackageManagersModule {
|
|
|
116
117
|
});
|
|
117
118
|
return this.get().runScript(scriptName, options).pipe(errorPipe());
|
|
118
119
|
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
Inject(),
|
|
122
|
-
__metadata("design:type", ProjectPackageJson)
|
|
123
|
-
], PackageManagersModule.prototype, "projectPackageJson", void 0);
|
|
124
|
-
PackageManagersModule = __decorate([
|
|
125
|
-
__param(0, Inject("package:manager")),
|
|
126
|
-
__metadata("design:paramtypes", [Array])
|
|
127
|
-
], PackageManagersModule);
|
|
128
|
-
export { PackageManagersModule };
|
|
129
|
-
injectable(PackageManagersModule).imports([YarnManager, YarnBerryManager, NpmManager, PNpmManager, BunManager]);
|
|
120
|
+
}
|
|
121
|
+
injectable(PackageManagersModule).imports([YarnBerryManager, YarnManager, NpmManager, PNpmManager, BunManager]);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Inject } from "@tsed/di";
|
|
1
|
+
import { inject } from "@tsed/di";
|
|
3
2
|
import { Observable } from "rxjs";
|
|
4
3
|
import { CliExeca } from "../../services/CliExeca.js";
|
|
5
4
|
export class BaseManager {
|
|
6
5
|
constructor() {
|
|
7
6
|
this.verboseOpt = "--verbose";
|
|
7
|
+
this.cliExeca = inject(CliExeca);
|
|
8
8
|
}
|
|
9
9
|
has() {
|
|
10
10
|
try {
|
|
@@ -23,7 +23,3 @@ export class BaseManager {
|
|
|
23
23
|
return this.cliExeca.run(this.cmd, [cmd, options.verbose && this.verboseOpt, ...args].filter(Boolean), options);
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
-
__decorate([
|
|
27
|
-
Inject(CliExeca),
|
|
28
|
-
__metadata("design:type", CliExeca)
|
|
29
|
-
], BaseManager.prototype, "cliExeca", void 0);
|
|
@@ -29,7 +29,10 @@ let YarnBerryManager = class YarnBerryManager extends BaseManager {
|
|
|
29
29
|
nodeLinker: "node-modules"
|
|
30
30
|
});
|
|
31
31
|
// then switch to berry
|
|
32
|
-
|
|
32
|
+
try {
|
|
33
|
+
this.cliExeca.runSync(this.cmd, ["set", "version", "berry"]);
|
|
34
|
+
}
|
|
35
|
+
catch (er) { }
|
|
33
36
|
}
|
|
34
37
|
add(deps, options) {
|
|
35
38
|
return this.run("add", [...deps], options);
|
|
@@ -51,7 +51,9 @@ export class CliFs extends RealFileSystemHost {
|
|
|
51
51
|
return this.raw.ensureDirSync(path, options);
|
|
52
52
|
}
|
|
53
53
|
findUpFile(root, file) {
|
|
54
|
-
return [join(root, file), join(root, "..", file), join(root, "..", "..", file), join(root, "..", "..", "..", file)].find((path) =>
|
|
54
|
+
return [join(root, file), join(root, "..", file), join(root, "..", "..", file), join(root, "..", "..", "..", file)].find((path) => {
|
|
55
|
+
return this.fileExistsSync(path) || this.raw.existsSync(path);
|
|
56
|
+
});
|
|
55
57
|
}
|
|
56
58
|
async importModule(mod, root = process.cwd()) {
|
|
57
59
|
try {
|
|
@@ -41,10 +41,11 @@ export class CliHttpClient extends CliHttpLogClient {
|
|
|
41
41
|
return this.mapResponse(result, options);
|
|
42
42
|
}
|
|
43
43
|
getRequestParameters(method, endpoint, options) {
|
|
44
|
+
const url = (this.host || "") + endpoint.replace(this.host || "", "");
|
|
44
45
|
options = {
|
|
45
46
|
method,
|
|
46
|
-
url: (this.host || "") + endpoint.replace(this.host || "", ""),
|
|
47
47
|
...options,
|
|
48
|
+
url,
|
|
48
49
|
params: options.params || options.qs,
|
|
49
50
|
data: options.data,
|
|
50
51
|
headers: {
|
|
@@ -53,7 +54,7 @@ export class CliHttpClient extends CliHttpLogClient {
|
|
|
53
54
|
...(options.headers || {})
|
|
54
55
|
}
|
|
55
56
|
};
|
|
56
|
-
this.configureProxy(
|
|
57
|
+
this.configureProxy(url, options);
|
|
57
58
|
return options;
|
|
58
59
|
}
|
|
59
60
|
configureProxy(endpoint, options) {
|
|
@@ -1,21 +1,12 @@
|
|
|
1
1
|
import { extname } from "node:path";
|
|
2
2
|
import { inject, injectable } from "@tsed/di";
|
|
3
|
-
import {
|
|
3
|
+
import { validate } from "../utils/validate.js";
|
|
4
4
|
import { CliFs } from "./CliFs.js";
|
|
5
5
|
import { CliYaml } from "./CliYaml.js";
|
|
6
6
|
export class CliLoadFile {
|
|
7
|
-
// @ts-ignore
|
|
8
|
-
#ajv;
|
|
9
7
|
constructor() {
|
|
10
8
|
this.cliYaml = inject(CliYaml);
|
|
11
9
|
this.cliFs = inject(CliFs);
|
|
12
|
-
const options = {
|
|
13
|
-
verbose: false,
|
|
14
|
-
coerceTypes: true,
|
|
15
|
-
strict: false
|
|
16
|
-
};
|
|
17
|
-
// @ts-ignore
|
|
18
|
-
this.#ajv = new Ajv(options);
|
|
19
10
|
}
|
|
20
11
|
/**
|
|
21
12
|
* Load a configuration file from yaml, json
|
|
@@ -33,18 +24,14 @@ export class CliLoadFile {
|
|
|
33
24
|
throw new Error("Unsupported format file");
|
|
34
25
|
}
|
|
35
26
|
if (schema) {
|
|
36
|
-
const
|
|
37
|
-
const isValid = validate(config);
|
|
27
|
+
const { isValid, errors, value } = validate(config, schema);
|
|
38
28
|
if (!isValid) {
|
|
39
|
-
const [error] =
|
|
40
|
-
throw new Error([
|
|
41
|
-
`${error.instancePath.replace(/\//gi, ".")} `,
|
|
42
|
-
error.message,
|
|
43
|
-
error.params?.allowedValues && `. Allowed values: ${error.params?.allowedValues}`
|
|
44
|
-
]
|
|
29
|
+
const [error] = errors;
|
|
30
|
+
throw new Error([`${error.path.replace(/\//gi, ".")} `, error.message, error.expected && `. Allowed values: ${error.expected}`]
|
|
45
31
|
.filter(Boolean)
|
|
46
32
|
.join(""));
|
|
47
33
|
}
|
|
34
|
+
return value;
|
|
48
35
|
}
|
|
49
36
|
return config;
|
|
50
37
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { constant, inject, injectable } from "@tsed/di";
|
|
2
|
+
import { $asyncEmit } from "@tsed/hooks";
|
|
2
3
|
import chalk from "chalk";
|
|
3
|
-
import { CommandStoreKeys } from "../domains/CommandStoreKeys.js";
|
|
4
4
|
import { PackageManagersModule } from "../packageManagers/PackageManagersModule.js";
|
|
5
5
|
import { createSubTasks } from "../utils/createTasksRunner.js";
|
|
6
6
|
import { loadPlugins } from "../utils/loadPlugins.js";
|
|
@@ -19,7 +19,6 @@ export class CliPlugins {
|
|
|
19
19
|
this.name = constant("name", "");
|
|
20
20
|
this.loadPlugins = loadPlugins;
|
|
21
21
|
this.npmRegistryClient = inject(NpmRegistryClient);
|
|
22
|
-
this.cliHooks = inject(CliHooks);
|
|
23
22
|
this.packageJson = inject(ProjectPackageJson);
|
|
24
23
|
this.packageManagers = inject(PackageManagersModule);
|
|
25
24
|
}
|
|
@@ -33,7 +32,7 @@ export class CliPlugins {
|
|
|
33
32
|
return {
|
|
34
33
|
title: `Run plugin '${chalk.cyan(plugin)}'`,
|
|
35
34
|
task: () => {
|
|
36
|
-
return
|
|
35
|
+
return $asyncEmit("$onAddPlugin", [plugin, ctx]);
|
|
37
36
|
}
|
|
38
37
|
};
|
|
39
38
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { classOf } from "@tsed/core";
|
|
1
|
+
import { classOf, isArrowFn } from "@tsed/core";
|
|
2
2
|
import { configuration, constant, context, destroyInjector, DIContext, getContext, inject, injectable, injector, logger, Provider, runInContext } from "@tsed/di";
|
|
3
3
|
import { $asyncAlter, $asyncEmit } from "@tsed/hooks";
|
|
4
4
|
import { pascalCase } from "change-case";
|
|
@@ -6,11 +6,10 @@ import { Argument, Command } from "commander";
|
|
|
6
6
|
import Inquirer from "inquirer";
|
|
7
7
|
import inquirer_autocomplete_prompt from "inquirer-autocomplete-prompt";
|
|
8
8
|
import { v4 } from "uuid";
|
|
9
|
-
import { CommandStoreKeys } from "../domains/CommandStoreKeys.js";
|
|
10
9
|
import { PackageManagersModule } from "../packageManagers/index.js";
|
|
11
10
|
import { createSubTasks, createTasksRunner } from "../utils/createTasksRunner.js";
|
|
12
11
|
import { getCommandMetadata } from "../utils/getCommandMetadata.js";
|
|
13
|
-
import { mapCommanderOptions } from "../utils/index.js";
|
|
12
|
+
import { mapCommanderOptions, validate } from "../utils/index.js";
|
|
14
13
|
import { mapCommanderArgs } from "../utils/mapCommanderArgs.js";
|
|
15
14
|
import { parseOption } from "../utils/parseOption.js";
|
|
16
15
|
import { CliHooks } from "./CliHooks.js";
|
|
@@ -44,78 +43,57 @@ export class CliService {
|
|
|
44
43
|
*/
|
|
45
44
|
runLifecycle(cmdName, data = {}, $ctx) {
|
|
46
45
|
return runInContext($ctx, async () => {
|
|
47
|
-
await $asyncEmit("$loadPackageJson");
|
|
48
|
-
data = await this.beforePrompt(cmdName, data);
|
|
49
|
-
$ctx.set("data", data);
|
|
50
|
-
data = await this.prompt(cmdName, data);
|
|
51
|
-
await this.dispatch(cmdName, data, $ctx);
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
async dispatch(cmdName, data, $ctx) {
|
|
55
|
-
try {
|
|
56
46
|
$ctx.set("dispatchCmd", cmdName);
|
|
57
|
-
$
|
|
58
|
-
await this.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
47
|
+
await $asyncEmit("$loadPackageJson");
|
|
48
|
+
data = await this.prompt(cmdName, data, $ctx);
|
|
49
|
+
try {
|
|
50
|
+
await this.exec(cmdName, data, $ctx);
|
|
51
|
+
}
|
|
52
|
+
catch (er) {
|
|
53
|
+
await $asyncEmit("$onFinish", [data, er]);
|
|
54
|
+
await destroyInjector();
|
|
55
|
+
throw er;
|
|
56
|
+
}
|
|
57
|
+
await $asyncEmit("$onFinish", [data]);
|
|
62
58
|
await destroyInjector();
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
await $asyncEmit("$onFinish");
|
|
66
|
-
await destroyInjector();
|
|
59
|
+
});
|
|
67
60
|
}
|
|
68
61
|
async exec(cmdName, data, $ctx) {
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
{
|
|
62
|
+
const tasks = await this.getTasks(cmdName, data);
|
|
63
|
+
$ctx.set("data", data);
|
|
64
|
+
if (tasks.length) {
|
|
65
|
+
if (this.reinstallAfterRun && (this.projectPkg.rewrite || this.projectPkg.reinstall)) {
|
|
66
|
+
tasks.push({
|
|
74
67
|
title: "Install dependencies",
|
|
75
|
-
enabled: () => this.reinstallAfterRun && (this.projectPkg.rewrite || this.projectPkg.reinstall),
|
|
76
68
|
task: createSubTasks(() => this.packageManagers.install(data), { ...data, concurrent: false })
|
|
77
|
-
},
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Run prompt for a given command
|
|
85
|
-
* @param cmdName
|
|
86
|
-
* @param data Initial data
|
|
87
|
-
*/
|
|
88
|
-
async beforePrompt(cmdName, data = {}) {
|
|
89
|
-
const provider = this.commands.get(cmdName);
|
|
90
|
-
const instance = inject(provider.useClass);
|
|
91
|
-
const verbose = data.verbose;
|
|
92
|
-
if (instance.$beforePrompt) {
|
|
93
|
-
data = await instance.$beforePrompt(JSON.parse(JSON.stringify(data)));
|
|
94
|
-
data.verbose = verbose;
|
|
69
|
+
}, ...(await this.getPostInstallTasks(cmdName, data)));
|
|
70
|
+
}
|
|
71
|
+
data = this.mapData(cmdName, data, $ctx);
|
|
72
|
+
$ctx.set("data", data);
|
|
73
|
+
return createTasksRunner(tasks, data);
|
|
95
74
|
}
|
|
96
|
-
return data;
|
|
97
75
|
}
|
|
98
76
|
/**
|
|
99
77
|
* Run prompt for a given command
|
|
100
78
|
* @param cmdName
|
|
101
|
-
* @param
|
|
79
|
+
* @param data
|
|
80
|
+
* @param $ctx
|
|
102
81
|
*/
|
|
103
|
-
async prompt(cmdName,
|
|
82
|
+
async prompt(cmdName, data = {}, $ctx) {
|
|
104
83
|
const provider = this.commands.get(cmdName);
|
|
105
|
-
const instance = inject(provider.
|
|
84
|
+
const instance = inject(provider.token);
|
|
85
|
+
$ctx.set("data", data);
|
|
106
86
|
if (instance.$prompt) {
|
|
107
|
-
const questions = [
|
|
108
|
-
...(await instance.$prompt(ctx)),
|
|
109
|
-
...(await this.hooks.emit(CommandStoreKeys.PROMPT_HOOKS, cmdName, ctx))
|
|
110
|
-
];
|
|
87
|
+
const questions = [...(await instance.$prompt(data))];
|
|
111
88
|
if (questions.length) {
|
|
112
|
-
|
|
113
|
-
...
|
|
89
|
+
data = {
|
|
90
|
+
...data,
|
|
114
91
|
...(await Inquirer.prompt(questions))
|
|
115
92
|
};
|
|
116
93
|
}
|
|
117
94
|
}
|
|
118
|
-
|
|
95
|
+
$ctx.set("data", data);
|
|
96
|
+
return data;
|
|
119
97
|
}
|
|
120
98
|
/**
|
|
121
99
|
* Run lifecycle
|
|
@@ -127,14 +105,10 @@ export class CliService {
|
|
|
127
105
|
const provider = this.commands.get(cmdName);
|
|
128
106
|
const instance = inject(provider.token);
|
|
129
107
|
data = this.mapData(cmdName, data, $ctx);
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
return
|
|
134
|
-
...(await instance.$exec(data)),
|
|
135
|
-
...(await this.hooks.emit(CommandStoreKeys.EXEC_HOOKS, cmdName, data)),
|
|
136
|
-
...(await $asyncAlter(`$alter${pascalCase(cmdName)}Tasks`, [], [data]))
|
|
137
|
-
].map((opts) => {
|
|
108
|
+
const tasks = [];
|
|
109
|
+
tasks.push(...((await instance.$exec(data)) || []));
|
|
110
|
+
tasks.push(...(await $asyncAlter(`$alter${pascalCase(cmdName)}Tasks`, [], [data])));
|
|
111
|
+
return tasks.map((opts) => {
|
|
138
112
|
return {
|
|
139
113
|
...opts,
|
|
140
114
|
task: async (arg, task) => {
|
|
@@ -148,32 +122,45 @@ export class CliService {
|
|
|
148
122
|
}
|
|
149
123
|
async getPostInstallTasks(cmdName, data) {
|
|
150
124
|
const provider = this.commands.get(cmdName);
|
|
151
|
-
const instance = inject(provider.
|
|
125
|
+
const instance = inject(provider.token);
|
|
152
126
|
data = this.mapData(cmdName, data, getContext());
|
|
153
127
|
return [
|
|
154
128
|
...(instance.$postInstall ? await instance.$postInstall(data) : []),
|
|
155
|
-
...(await this.hooks.emit(CommandStoreKeys.POST_INSTALL_HOOKS, cmdName, data)),
|
|
156
129
|
...(await $asyncAlter(`$alter${pascalCase(cmdName)}PostInstallTasks`, [], [data])),
|
|
157
130
|
...(instance.$afterPostInstall ? await instance.$afterPostInstall(data) : [])
|
|
158
131
|
];
|
|
159
132
|
}
|
|
160
133
|
createCommand(metadata) {
|
|
161
|
-
const {
|
|
134
|
+
const { name, description, alias, inputSchema } = metadata;
|
|
162
135
|
if (this.commands.has(name)) {
|
|
163
136
|
return this.commands.get(name).command;
|
|
164
137
|
}
|
|
165
|
-
|
|
138
|
+
const { args, options, allowUnknownOption } = metadata.getOptions();
|
|
166
139
|
const onAction = (commandName) => {
|
|
167
140
|
const [, ...rawArgs] = cmd.args;
|
|
168
141
|
const mappedArgs = mapCommanderArgs(args, this.program.args.filter((arg) => commandName === arg));
|
|
169
142
|
const allOpts = mapCommanderOptions(commandName, this.program.commands);
|
|
170
|
-
|
|
143
|
+
let data = {
|
|
171
144
|
...allOpts,
|
|
172
145
|
verbose: !!this.program.opts().verbose,
|
|
173
146
|
...mappedArgs,
|
|
174
147
|
...cmd.opts(),
|
|
175
148
|
rawArgs
|
|
176
149
|
};
|
|
150
|
+
if (inputSchema) {
|
|
151
|
+
const schema = isArrowFn(inputSchema) ? inputSchema() : inputSchema;
|
|
152
|
+
const { isValid, errors, value } = validate(data, schema);
|
|
153
|
+
if (isValid) {
|
|
154
|
+
data = value;
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
logger().error({
|
|
158
|
+
event: "VALIDATION_ERROR",
|
|
159
|
+
errors
|
|
160
|
+
});
|
|
161
|
+
throw new Error("Validation error");
|
|
162
|
+
}
|
|
163
|
+
}
|
|
177
164
|
const $ctx = new DIContext({
|
|
178
165
|
id: v4(),
|
|
179
166
|
injector: injector(),
|
|
@@ -187,6 +174,7 @@ export class CliService {
|
|
|
187
174
|
configuration().set("command.metadata", metadata);
|
|
188
175
|
return this.runLifecycle(name, data, $ctx);
|
|
189
176
|
};
|
|
177
|
+
let cmd = this.program.command(name);
|
|
190
178
|
if (alias) {
|
|
191
179
|
cmd = cmd.alias(alias);
|
|
192
180
|
}
|
|
@@ -205,7 +193,7 @@ export class CliService {
|
|
|
205
193
|
}
|
|
206
194
|
mapData(cmdName, data, $ctx) {
|
|
207
195
|
const provider = this.commands.get(cmdName);
|
|
208
|
-
const instance = inject(provider.
|
|
196
|
+
const instance = inject(provider.token);
|
|
209
197
|
const verbose = data.verbose;
|
|
210
198
|
data.commandName ||= cmdName;
|
|
211
199
|
if (instance.$mapContext) {
|
|
@@ -227,7 +215,7 @@ export class CliService {
|
|
|
227
215
|
* @param provider
|
|
228
216
|
*/
|
|
229
217
|
build(provider) {
|
|
230
|
-
const metadata = getCommandMetadata(provider.
|
|
218
|
+
const metadata = getCommandMetadata(provider.token);
|
|
231
219
|
if (metadata.name) {
|
|
232
220
|
if (this.commands.has(metadata.name)) {
|
|
233
221
|
throw Error(`The ${metadata.name} command is already registered. Change your command name used by the class ${classOf(provider.useClass)}`);
|