Skip to content

Commit

Permalink
feat(cli): add Yarn berry support and support DIContext
Browse files Browse the repository at this point in the history
  • Loading branch information
Romakita committed Apr 26, 2023
1 parent 3c9dee4 commit 9a9b970
Show file tree
Hide file tree
Showing 50 changed files with 1,010 additions and 840 deletions.
4 changes: 3 additions & 1 deletion packages/cli-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"@tsed/normalize-path": ">=7.14.2",
"@types/fs-extra": "^9.0.13",
"@types/inquirer": "^8.2.4",
"uuid": "^8.3.2",
"ajv": "8.11.0",
"axios": "0.26.1",
"chalk": "4.1.2",
Expand Down Expand Up @@ -66,6 +67,7 @@
},
"devDependencies": {
"@types/axios": "0.14.0",
"@types/uuid": "8.3.4",
"@types/commander": "2.12.2",
"@types/consolidate": "0.14.1",
"@types/figures": "3.0.1",
Expand All @@ -83,4 +85,4 @@
"@tsed/core": ">=7.14.2",
"@tsed/di": ">=7.14.2"
}
}
}
3 changes: 3 additions & 0 deletions packages/cli-core/src/CliCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {createInjector} from "./utils/createInjector";
import {loadPlugins} from "./utils/loadPlugins";
import {CliError} from "./domains/CliError";
import semver from "semver";
import {resolveConfiguration} from "./utils/resolveConfiguration";

function isHelpManual(argv: string[]) {
return argv.includes("-h") || argv.includes("--help");
Expand Down Expand Up @@ -47,6 +48,8 @@ export class CliCore {
}

static async create<Cli extends CliCore = CliCore>(settings: Partial<TsED.Configuration>, module: Type = CliCore): Promise<Cli> {
settings = resolveConfiguration(settings);

const injector = this.createInjector(settings);

settings.plugins && (await loadPlugins(injector));
Expand Down
20 changes: 7 additions & 13 deletions packages/cli-core/src/interfaces/CommandMetadata.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
import {CommandArg, CommandOptions} from "./CommandParameters";
import {CommandArg, CommandOptions, CommandParameters} from "./CommandParameters";

export interface CommandMetadata {
/**
* name commands
*/
name: string;

alias?: string;
/**
* CommandProvider description
*/
description: string;
export interface CommandMetadata extends CommandParameters {
/**
* CommandProvider arguments
*/
Expand All @@ -24,5 +14,9 @@ export interface CommandMetadata {
[key: string]: CommandOptions;
};

allowUnknownOption?: boolean;
allowUnknownOption: boolean;

enableFeatures: string[];

disableReadUpPkg: boolean;
}
6 changes: 6 additions & 0 deletions packages/cli-core/src/interfaces/CommandParameters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ export interface CommandParameters {
* name commands
*/
name: string;

alias?: string;
/**
* CommandProvider description
*/
Expand All @@ -75,5 +77,9 @@ export interface CommandParameters {

allowUnknownOption?: boolean;

enableFeatures?: string[];

disableReadUpPkg?: boolean;

[key: string]: any;
}
16 changes: 16 additions & 0 deletions packages/cli-core/src/services/CliFs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,22 @@ export class CliFs {
return this.raw.readFile(file, encoding) as any;
}

readFileSync(file: string | Buffer | number, encoding?: any) {
return this.raw.readFileSync(file, encoding) as any;
}

async readJson(file: string, encoding?: any) {
const content = await this.readFile(file, encoding);

return JSON.parse(content);
}

async readJsonSync(file: string, encoding?: any) {
const content = this.readFileSync(file, encoding) as any;

return JSON.parse(content);
}

async writeJson(file: string | Buffer | number, data: any, options?: WriteFileOptions | string): Promise<any> {
await this.raw.writeFile(file, JSON.stringify(data, null, 2), options || ({encoding: "utf8"} as any));
}
Expand Down
7 changes: 6 additions & 1 deletion packages/cli-core/src/services/CliPlugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,12 @@ export class CliPlugins {
...tasks,
{
title: "Install",
task: createSubTasks(() => this.packageJson.install(ctx), {...ctx, concurrent: false})
task: createSubTasks(
() => {
return this.packageJson.install(ctx);
},
{...ctx, concurrent: false}
)
}
];
}
Expand Down
81 changes: 51 additions & 30 deletions packages/cli-core/src/services/CliService.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {classOf} from "@tsed/core";
import {Constant, Inject, Injectable, InjectorService, Provider} from "@tsed/di";
import {Constant, DIContext, getContext, Inject, Injectable, InjectorService, Provider, runInContext} from "@tsed/di";
import {Argument, Command} from "commander";
import Inquirer from "inquirer";
import {v4} from "uuid";
import {CommandStoreKeys} from "../domains/CommandStoreKeys";
import {CommandProvider} from "../interfaces/CommandProvider";
import {CommandMetadata} from "../interfaces/CommandMetadata";
import {CommandArg, CommandOptions} from "../interfaces/CommandParameters";
import {PROVIDER_TYPE_COMMAND} from "../registries/CommandRegistry";
import {createSubTasks, createTasksRunner} from "../utils/createTasksRunner";
Expand All @@ -17,6 +17,7 @@ import {ProjectPackageJson} from "./ProjectPackageJson";
// @ts-ignore
import inquirer_autocomplete_prompt from "inquirer-autocomplete-prompt";
import {mapCommanderOptions} from "../utils/mapCommanderOptions";
import {CommandMetadata} from "@tsed/cli-core";

Inquirer.registerPrompt("autocomplete", inquirer_autocomplete_prompt);

Expand Down Expand Up @@ -59,17 +60,25 @@ export class CliService {
* Run lifecycle
* @param cmdName
* @param data
* @param $ctx
*/
public async runLifecycle(cmdName: string, data: any = {}) {
data = await this.beforePrompt(cmdName, data);
data = await this.prompt(cmdName, data);
public async runLifecycle(cmdName: string, data: any = {}, $ctx: DIContext) {
return runInContext($ctx, async () => {
data = await this.beforePrompt(cmdName, data);

await this.dispatch(cmdName, data);
$ctx.set("data", data);

data = await this.prompt(cmdName, data);
await this.dispatch(cmdName, data, $ctx);
});
}

public async dispatch(cmdName: string, data: any) {
public async dispatch(cmdName: string, data: any, $ctx: DIContext) {
try {
await this.exec(cmdName, data);
$ctx.set("dispatchCmd", cmdName);
$ctx.set("data", data);

await this.exec(cmdName, data, $ctx);
} catch (er) {
await this.injector.emit("$onFinish", er);
await this.injector.destroy();
Expand All @@ -80,21 +89,21 @@ export class CliService {
await this.injector.destroy();
}

public async exec(cmdName: string, ctx: any) {
const initialTasks = await this.getTasks(cmdName, ctx);
public async exec(cmdName: string, data: any, $ctx: DIContext) {
const initialTasks = await this.getTasks(cmdName, data);

if (initialTasks.length) {
const tasks = [
...initialTasks,
{
title: "Install dependencies",
enabled: () => this.reinstallAfterRun && (this.projectPkg.rewrite || this.projectPkg.reinstall),
task: createSubTasks(() => this.projectPkg.install(ctx), {...ctx, concurrent: false})
task: createSubTasks(() => this.projectPkg.install(data), {...data, concurrent: false})
},
...(await this.getPostInstallTasks(cmdName, ctx))
...(await this.getPostInstallTasks(cmdName, data))
];

return createTasksRunner(tasks, this.mapContext(cmdName, ctx));
return createTasksRunner(tasks, this.mapData(cmdName, data, $ctx));
}
}

Expand Down Expand Up @@ -144,31 +153,32 @@ export class CliService {
/**
* Run lifecycle
* @param cmdName
* @param ctx
* @param data
*/
public async getTasks(cmdName: string, ctx: any) {
public async getTasks(cmdName: string, data: any) {
const $ctx = getContext()!;
const provider = this.commands.get(cmdName);
const instance = this.injector.get<CommandProvider>(provider.token)!;

ctx = this.mapContext(cmdName, ctx);
data = this.mapData(cmdName, data, $ctx);

if (instance.$beforeExec) {
await instance.$beforeExec(ctx);
await instance.$beforeExec(data);
}

return [...(await instance.$exec(ctx)), ...(await this.hooks.emit(CommandStoreKeys.EXEC_HOOKS, cmdName, ctx))];
return [...(await instance.$exec(data)), ...(await this.hooks.emit(CommandStoreKeys.EXEC_HOOKS, cmdName, data))];
}

public async getPostInstallTasks(cmdName: string, ctx: any) {
public async getPostInstallTasks(cmdName: string, data: any) {
const provider = this.commands.get(cmdName);
const instance = this.injector.get<CommandProvider>(provider.useClass)!;

ctx = this.mapContext(cmdName, ctx);
data = this.mapData(cmdName, data, getContext()!);

return [
...(instance.$postInstall ? await instance.$postInstall(ctx) : []),
...(await this.hooks.emit(CommandStoreKeys.POST_INSTALL_HOOKS, cmdName, ctx)),
...(instance.$afterPostInstall ? await instance.$afterPostInstall(ctx) : [])
...(instance.$postInstall ? await instance.$postInstall(data) : []),
...(await this.hooks.emit(CommandStoreKeys.POST_INSTALL_HOOKS, cmdName, data)),
...(instance.$afterPostInstall ? await instance.$afterPostInstall(data) : [])
];
}

Expand All @@ -194,7 +204,16 @@ export class CliService {
rawArgs
};

return this.runLifecycle(name, data);
const $ctx = new DIContext({
id: v4(),
injector: this.injector,
logger: this.injector.logger
});

$ctx.set("data", data);
$ctx.set("command", metadata);

return this.runLifecycle(name, data, $ctx);
};

if (alias) {
Expand All @@ -217,23 +236,25 @@ export class CliService {
this.injector.getProviders(PROVIDER_TYPE_COMMAND).forEach((provider) => this.build(provider));
}

private mapContext(cmdName: string, ctx: any) {
private mapData(cmdName: string, data: any, $ctx: DIContext) {
const provider = this.commands.get(cmdName);
const instance = this.injector.get<CommandProvider>(provider.useClass)!;
const verbose = ctx.verbose;
const verbose = data.verbose;

if (instance.$mapContext) {
ctx = instance.$mapContext(JSON.parse(JSON.stringify(ctx)));
ctx.verbose = verbose;
data = instance.$mapContext(JSON.parse(JSON.stringify(data)));
data.verbose = verbose;
}

if (ctx.verbose) {
if (data.verbose) {
this.injector.logger.level = "debug";
} else {
this.injector.logger.level = "info";
}

return ctx;
$ctx.set("data", data);

return data;
}

/**
Expand Down
Loading

0 comments on commit 9a9b970

Please sign in to comment.