@tsed/cli
Version:
CLI to bootstrap your Ts.ED project
251 lines (250 loc) • 9.98 kB
JavaScript
var GenerateCmd_1;
import { __decorate, __metadata } from "tslib";
import { basename, dirname, join } from "node:path";
import { Command, Inject, inject, ProjectPackageJson } from "@tsed/cli-core";
import { normalizePath } from "@tsed/normalize-path";
import { kebabCase, pascalCase } from "change-case";
import { globbySync } from "globby";
import { ProjectConvention } from "../../interfaces/ProjectConvention.js";
import { ClassNamePipe } from "../../pipes/ClassNamePipe.js";
import { OutputFilePathPipe } from "../../pipes/OutputFilePathPipe.js";
import { RoutePipe } from "../../pipes/RoutePipe.js";
import { ProvidersInfoService } from "../../services/ProvidersInfoService.js";
import { SrcRendererService } from "../../services/Renderer.js";
import { fillImports } from "../../utils/fillImports.js";
import { getFrameworksPrompt } from "../init/prompts/getFeaturesPrompt.js";
import { PROVIDER_TYPES } from "./ProviderTypes.js";
const DECORATOR_TYPES = [
{ name: "Class decorator", value: "class" },
{ name: "Ts.ED middleware and its decorator", value: "middleware" },
{ name: "Ts.ED endpoint decorator", value: "endpoint" },
{ name: "Ts.ED property decorator", value: "prop" },
{ name: "Ts.ED parameter decorator", value: "param" },
{ name: "Vanilla Method decorator", value: "method" },
{ name: "Vanilla Property decorator", value: "property" },
{ name: "Vanilla Parameter decorator", value: "parameter" },
{ name: "Generic decorator", value: "generic" }
];
const searchFactory = (list) => {
return (state, keyword) => {
if (keyword) {
return list.filter((item) => item.name.toLowerCase().includes(keyword.toLowerCase()));
}
return list;
};
};
let GenerateCmd = GenerateCmd_1 = class GenerateCmd {
constructor(providersList) {
this.providersList = providersList;
this.srcRenderService = inject(SrcRendererService);
this.projectPackageJson = inject(ProjectPackageJson);
PROVIDER_TYPES.forEach((info) => {
this.providersList.add({
...info
}, GenerateCmd_1);
});
}
$prompt(initialOptions) {
const getName = (state) => initialOptions.name || pascalCase(state.name || initialOptions.name || state.type || initialOptions.type);
const proposedProviders = this.providersList.findProviders(initialOptions.type);
return [
{
type: "autocomplete",
name: "type",
message: "Which type of provider?",
default: initialOptions.type,
when: () => proposedProviders.length > 1,
source: searchFactory(proposedProviders)
},
{
type: "input",
name: "name",
message: "Which name?",
default: getName,
when: !initialOptions.name
},
{
...getFrameworksPrompt(),
message: "Which platform?",
type: "list",
name: "platform",
when(state) {
return ["server"].includes(state.type || initialOptions.type);
}
},
{
type: "input",
name: "route",
message: "Which route?",
when(state) {
return !!(["controller", "server"].includes(state.type || initialOptions.type) || initialOptions.route);
},
default: (state) => {
return state.type === "server" ? "/rest" : this.routePipe.transform(getName(state));
}
},
{
type: "list",
name: "directory",
message: "Which directory?",
when(state) {
return ["controller"].includes(state.type || initialOptions.type) || initialOptions.directory;
},
choices: this.getDirectories("controllers")
},
{
type: "autocomplete",
name: "templateType",
message: (state) => `Which type of ${state.type || initialOptions.type}?`,
when(state) {
return !!(["decorator"].includes(state.type || initialOptions.type) || initialOptions.templateType);
},
source: searchFactory(DECORATOR_TYPES)
},
{
type: "list",
name: "middlewarePosition",
message: () => `The middleware should be called:`,
choices: [
{ name: "Before the endpoint", value: "before" },
{ name: "After the endpoint", value: "after" }
],
when(state) {
return !!((["decorator"].includes(state.type || initialOptions.type) && ["middleware"].includes(state.templateType)) ||
initialOptions.middlewarePosition);
}
}
];
}
$mapContext(ctx) {
const { name = "" } = ctx;
let { type = "" } = ctx;
type = type.toLowerCase();
if (ctx.name === "prisma" && ctx.name) {
type = "prisma.service";
}
const symbolName = this.classNamePipe.transform({ name, type, format: ProjectConvention.DEFAULT });
const symbolParamName = kebabCase(symbolName);
return fillImports({
...ctx,
type,
route: ctx.route ? this.routePipe.transform(ctx.route) : "",
symbolName,
symbolParamName,
symbolPath: normalizePath(this.outputFilePathPipe.transform({
name,
type,
subDir: ctx.directory
})),
symbolPathBasename: normalizePath(this.classNamePipe.transform({ name, type })),
platformSymbol: ctx.platform && pascalCase(`Platform ${ctx.platform}`)
});
}
$exec(ctx) {
const { symbolPath } = ctx;
if (this.providersList.isMyProvider(ctx.type, GenerateCmd_1)) {
const type = [ctx.type, ctx.templateType].filter(Boolean).join(".");
let template = `generate/${type}.hbs`;
if (ctx.type === "server") {
template = `generate/server/${ctx.platform}/server.hbs`;
}
return [
{
title: `Generate ${ctx.type} file to '${symbolPath}.ts'`,
task: () => {
if (ctx.type === "server") {
return this.srcRenderService.render(template, ctx, {
baseDir: "generate",
basename: `${symbolPath}.ts`,
replaces: [`server/${ctx.platform}`]
});
}
return this.srcRenderService.render(template, ctx, {
output: `${symbolPath}.ts`
});
}
},
{
title: `Update bin/index`,
skip() {
return ctx.type !== "command";
},
task: () => {
return this.srcRenderService.update("bin/index.ts", [
{
type: "import",
content: `import {${ctx.symbolName}} from "./${basename(symbolPath)}.js";`
},
{
type: "insert-after",
pattern: /commands: \[/,
content: ` ${ctx.symbolName}`
}
]);
}
}
];
}
return [];
}
getDirectories(dir) {
const directories = globbySync("**/*", {
cwd: join(this.srcRenderService.rootDir, dir),
ignore: ["__*"]
});
const set = new Set(directories.map((dir) => {
return dirname(dir);
}));
set.delete(".");
return [...set];
}
};
__decorate([
Inject(),
__metadata("design:type", ClassNamePipe)
], GenerateCmd.prototype, "classNamePipe", void 0);
__decorate([
Inject(),
__metadata("design:type", OutputFilePathPipe)
], GenerateCmd.prototype, "outputFilePathPipe", void 0);
__decorate([
Inject(),
__metadata("design:type", RoutePipe)
], GenerateCmd.prototype, "routePipe", void 0);
GenerateCmd = GenerateCmd_1 = __decorate([
Command({
name: "generate",
alias: "g",
description: "Generate a new provider class",
args: {
type: {
description: "Type of the provider (Injectable, Controller, Pipe, etc...)",
type: String
},
name: {
description: "Name of the class",
type: String
}
},
options: {
"--route <route>": {
type: String,
description: "The route for the controller generated file"
},
"-d, --directory <directory>": {
description: "Directory where the file must be generated",
type: String
},
"-t, --template-type <templateType>": {
description: "Directory where the file must be generated",
type: String
},
"-m, --middleware-position <templateType>": {
description: "Middleware position (before, after)",
type: String
}
}
}),
__metadata("design:paramtypes", [ProvidersInfoService])
], GenerateCmd);
export { GenerateCmd };