Skip to content

Commit 80135ba

Browse files
committed
feat: introduce CommandData interface and enhance command handling with optional properties
1 parent 615a61d commit 80135ba

File tree

8 files changed

+62
-18
lines changed

8 files changed

+62
-18
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
declare global {
2+
namespace TsED {
3+
interface InitialCommandData {}
4+
}
5+
}
6+
7+
export interface CommandData extends TsED.InitialCommandData {
8+
commandName?: string;
9+
verbose?: boolean;
10+
bindLogger?: boolean;
11+
rawArgs?: string[];
12+
}

packages/cli-core/src/interfaces/CommandMetadata.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export interface CommandMetadata extends CommandParameters {
1414
[key: string]: CommandOptions;
1515
};
1616

17-
allowUnknownOption: boolean;
17+
allowUnknownOption?: boolean;
1818

1919
enableFeatures: string[];
2020

packages/cli-core/src/interfaces/CommandProvider.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
1+
import "inquirer-autocomplete-prompt";
2+
13
import type {Answers, QuestionCollection} from "inquirer";
4+
import AutocompletePrompt from "inquirer-autocomplete-prompt";
25

36
import type {Tasks} from "./Tasks.js";
47

8+
declare module "inquirer" {
9+
export interface QuestionMap<T extends Answers = Answers> {
10+
autocomplete: AutocompletePrompt.AutocompleteQuestionOptions<T>;
11+
}
12+
}
13+
514
export type QuestionOptions<T extends Answers = Answers> = QuestionCollection<T>;
615

716
export interface CommandProvider<Ctx = any> {

packages/cli-core/src/interfaces/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {CommandProvider} from "./CommandProvider.js";
44
import type {PackageJson} from "./PackageJson.js";
55

66
export * from "./CliDefaultOptions.js";
7+
export * from "./CommandData.js";
78
export * from "./CommandMetadata.js";
89
export * from "./CommandParameters.js";
910
export * from "./CommandProvider.js";

packages/cli-core/src/services/CliDockerComposeYaml.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import {CliFs} from "./CliFs.js";
88
import {CliYaml} from "./CliYaml.js";
99
import {ProjectPackageJson} from "./ProjectPackageJson.js";
1010

11+
export type CliDatabases = "mysql" | "mariadb" | "sqlite" | "better-sqlite3" | "postgres" | "cockroachdb" | "mssql" | "oracle" | "mongodb";
12+
1113
export class CliDockerComposeYaml {
1214
protected cliYaml = inject(CliYaml);
1315
protected fs = inject(CliFs);
@@ -31,7 +33,7 @@ export class CliDockerComposeYaml {
3133
return this.cliYaml.write(file, obj);
3234
}
3335

34-
async addDatabaseService(name: string, database: string) {
36+
async addDatabaseService(name: string, database: CliDatabases | undefined) {
3537
const dockerCompose: any = await this.read();
3638
if (dockerCompose) {
3739
let value: any;

packages/cli-core/src/services/CliService.ts

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,19 @@ import {
1212
Provider,
1313
runInContext
1414
} from "@tsed/di";
15-
import {$asyncEmit} from "@tsed/hooks";
15+
import {$asyncAlter, $asyncEmit} from "@tsed/hooks";
16+
import {pascalCase} from "change-case";
1617
import {Argument, Command} from "commander";
1718
import Inquirer from "inquirer";
18-
// @ts-ignore
1919
import inquirer_autocomplete_prompt from "inquirer-autocomplete-prompt";
2020
import {v4} from "uuid";
2121

2222
import {CommandStoreKeys} from "../domains/CommandStoreKeys.js";
23+
import type {CommandData} from "../interfaces/CommandData.js";
2324
import type {CommandMetadata} from "../interfaces/CommandMetadata.js";
2425
import type {CommandArg, CommandOptions} from "../interfaces/CommandParameters.js";
2526
import type {CommandProvider} from "../interfaces/CommandProvider.js";
27+
import type {Task} from "../interfaces/index.js";
2628
import {PackageManagersModule} from "../packageManagers/index.js";
2729
import {createSubTasks, createTasksRunner} from "../utils/createTasksRunner.js";
2830
import {getCommandMetadata} from "../utils/getCommandMetadata.js";
@@ -63,7 +65,7 @@ export class CliService {
6365
* @param data
6466
* @param $ctx
6567
*/
66-
public runLifecycle(cmdName: string, data: any = {}, $ctx: DIContext) {
68+
public runLifecycle(cmdName: string, data: CommandData = {}, $ctx: DIContext) {
6769
return runInContext($ctx, async () => {
6870
await $asyncEmit("$loadPackageJson");
6971

@@ -76,7 +78,7 @@ export class CliService {
7678
});
7779
}
7880

79-
public async dispatch(cmdName: string, data: any, $ctx: DIContext) {
81+
public async dispatch(cmdName: string, data: CommandData, $ctx: DIContext) {
8082
try {
8183
$ctx.set("dispatchCmd", cmdName);
8284
$ctx.set("data", data);
@@ -113,27 +115,27 @@ export class CliService {
113115
/**
114116
* Run prompt for a given command
115117
* @param cmdName
116-
* @param ctx Initial data
118+
* @param data Initial data
117119
*/
118-
public async beforePrompt(cmdName: string, ctx: any = {}) {
120+
public async beforePrompt(cmdName: string, data: CommandData = {}) {
119121
const provider = this.commands.get(cmdName);
120122
const instance = inject<CommandProvider>(provider.useClass)!;
121-
const verbose = ctx.verbose;
123+
const verbose = data.verbose;
122124

123125
if (instance.$beforePrompt) {
124-
ctx = await instance.$beforePrompt(JSON.parse(JSON.stringify(ctx)));
125-
ctx.verbose = verbose;
126+
data = await instance.$beforePrompt(JSON.parse(JSON.stringify(data)));
127+
data.verbose = verbose;
126128
}
127129

128-
return ctx;
130+
return data;
129131
}
130132

131133
/**
132134
* Run prompt for a given command
133135
* @param cmdName
134136
* @param ctx Initial data
135137
*/
136-
public async prompt(cmdName: string, ctx: any = {}) {
138+
public async prompt(cmdName: string, ctx: CommandData = {}) {
137139
const provider = this.commands.get(cmdName);
138140
const instance = inject<CommandProvider>(provider.useClass)!;
139141

@@ -159,7 +161,7 @@ export class CliService {
159161
* @param cmdName
160162
* @param data
161163
*/
162-
public async getTasks(cmdName: string, data: any) {
164+
public async getTasks(cmdName: string, data: any): Promise<Task[]> {
163165
const $ctx = getContext()!;
164166
const provider = this.commands.get(cmdName);
165167
const instance = inject<CommandProvider>(provider.token)!;
@@ -170,7 +172,11 @@ export class CliService {
170172
await instance.$beforeExec(data);
171173
}
172174

173-
return [...(await instance.$exec(data)), ...(await this.hooks.emit(CommandStoreKeys.EXEC_HOOKS, cmdName, data))];
175+
return [
176+
...(await instance.$exec(data)),
177+
...(await this.hooks.emit(CommandStoreKeys.EXEC_HOOKS, cmdName, data)),
178+
...(await $asyncAlter(`$alter${pascalCase(cmdName)}Tasks`, [], [data]))
179+
];
174180
}
175181

176182
public async getPostInstallTasks(cmdName: string, data: any) {
@@ -182,6 +188,7 @@ export class CliService {
182188
return [
183189
...(instance.$postInstall ? await instance.$postInstall(data) : []),
184190
...(await this.hooks.emit(CommandStoreKeys.POST_INSTALL_HOOKS, cmdName, data)),
191+
...(await $asyncAlter(`$alter${pascalCase(cmdName)}PostInstallTasks`, [] as Task[], [data])),
185192
...(instance.$afterPostInstall ? await instance.$afterPostInstall(data) : [])
186193
];
187194
}
@@ -203,7 +210,7 @@ export class CliService {
203210
);
204211
const allOpts = mapCommanderOptions(commandName, this.program.commands);
205212

206-
const data = {
213+
const data: CommandData = {
207214
...allOpts,
208215
verbose: !!this.program.opts().verbose,
209216
...mappedArgs,
@@ -250,11 +257,13 @@ export class CliService {
250257
.forEach((provider) => this.build(provider));
251258
}
252259

253-
private mapData(cmdName: string, data: any, $ctx: DIContext) {
260+
private mapData(cmdName: string, data: CommandData, $ctx: DIContext) {
254261
const provider = this.commands.get(cmdName);
255262
const instance = inject<CommandProvider>(provider.useClass)!;
256263
const verbose = data.verbose;
257264

265+
data.commandName ||= cmdName;
266+
258267
if (instance.$mapContext) {
259268
data = instance.$mapContext(JSON.parse(JSON.stringify(data)));
260269
data.verbose = verbose;
@@ -266,7 +275,7 @@ export class CliService {
266275
logger().level = "info";
267276
}
268277

269-
data.bindLogger = $ctx.get("command").bindLogger;
278+
data.bindLogger = $ctx.get("command")?.bindLogger;
270279

271280
$ctx.set("data", data);
272281

packages/cli-core/src/services/ProjectPackageJson.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,16 @@ export class ProjectPackageJson {
110110
return this.raw[constant<string>("name")!];
111111
}
112112

113+
fillWithPreferences<T extends {}>(ctx: T) {
114+
return {
115+
...ctx,
116+
packageManager: this.preferences.packageManager,
117+
runtime: this.preferences.runtime,
118+
architecture: this.preferences.architecture,
119+
convention: this.preferences.convention
120+
};
121+
}
122+
113123
$loadPackageJson() {
114124
return this.read();
115125
}

packages/cli-core/test/integrations/command.integration.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ describe("Command", () => {
4040
});
4141

4242
expect(TestCommand.prototype.$exec).toHaveBeenCalledWith({
43+
commandName: "test",
4344
bindLogger: true,
4445
argument: "subcmd",
4546
rawArgs: [],

0 commit comments

Comments
 (0)