@tsed/cli 7.0.0-alpha.3 → 7.0.0-alpha.5
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/Cli.js +1 -0
- package/lib/esm/bin/tsed.js +1 -0
- package/lib/esm/commands/generate/GenerateCmd.js +6 -5
- package/lib/esm/commands/index.js +2 -1
- package/lib/esm/commands/init/InitCmd.js +1 -1
- package/lib/esm/commands/init/config/FeaturesPrompt.js +12 -13
- package/lib/esm/commands/init/mappers/mapToContext.js +4 -0
- package/lib/esm/commands/init/prompts/getFeaturesPrompt.js +0 -12
- package/lib/esm/commands/init/utils/hasFeature.js +3 -0
- package/lib/esm/commands/template/CreateTemplateCommand.js +99 -0
- package/lib/esm/services/CliProjectService.js +4 -5
- package/lib/esm/services/CliTemplatesService.js +57 -9
- package/lib/esm/services/ProjectClient.js +22 -22
- package/lib/esm/services/mappers/addContextMethods.js +17 -0
- package/lib/esm/services/mappers/mapDefaultTemplateOptions.js +7 -1
- package/lib/esm/templates/barrels.template.js +3 -2
- package/lib/esm/templates/controller.template.js +24 -25
- package/lib/esm/templates/decorator.template.js +26 -24
- package/lib/esm/templates/docker-compose.template.js +2 -2
- package/lib/esm/templates/dockerfile.template.js +5 -5
- package/lib/esm/templates/index.command.template.js +1 -0
- package/lib/esm/templates/index.config.utils.template.js +1 -1
- package/lib/esm/templates/index.js +1 -0
- package/lib/esm/templates/index.logger.template.js +2 -1
- package/lib/esm/templates/middleware.template.js +16 -14
- package/lib/esm/templates/new-template.template.js +67 -0
- package/lib/esm/templates/readme.template.js +3 -3
- package/lib/esm/templates/tsconfig.spec.template.js +5 -4
- package/lib/esm/templates/tsconfig.template.js +3 -2
- package/lib/esm/utils/defineTemplate.js +2 -2
- package/lib/tsconfig.esm.tsbuildinfo +1 -1
- package/lib/types/Cli.d.ts +2 -1
- package/lib/types/bin/tsed.d.ts +1 -1
- package/lib/types/commands/generate/GenerateCmd.d.ts +1 -36
- package/lib/types/commands/index.d.ts +2 -1
- package/lib/types/commands/init/config/FeaturesPrompt.d.ts +13 -6
- package/lib/types/commands/init/prompts/getFeaturesPrompt.d.ts +0 -6
- package/lib/types/commands/init/utils/hasFeature.d.ts +1 -0
- package/lib/types/commands/template/CreateTemplateCommand.d.ts +62 -0
- package/lib/types/interfaces/GenerateCmdContext.d.ts +2 -0
- package/lib/types/interfaces/RenderDataContext.d.ts +1 -0
- package/lib/types/pipes/SymbolNamePipe.d.ts +1 -1
- package/lib/types/services/CliProjectService.d.ts +2 -2
- package/lib/types/services/CliTemplatesService.d.ts +7 -3
- package/lib/types/services/ProjectClient.d.ts +3 -3
- package/lib/types/services/mappers/addContextMethods.d.ts +12 -0
- package/lib/types/templates/asyncFactory.template.d.ts +15 -1
- package/lib/types/templates/barrels.template.d.ts +15 -1
- package/lib/types/templates/command.template.d.ts +15 -1
- package/lib/types/templates/config.template.d.ts +15 -1
- package/lib/types/templates/controller.template.d.ts +16 -1
- package/lib/types/templates/decorator.template.d.ts +16 -1
- package/lib/types/templates/docker-compose.template.d.ts +15 -1
- package/lib/types/templates/exception-filter.template.d.ts +15 -1
- package/lib/types/templates/factory.template.d.ts +15 -1
- package/lib/types/templates/index.command.template.d.ts +15 -1
- package/lib/types/templates/index.config.utils.template.d.ts +15 -1
- package/lib/types/templates/index.controller.template.d.ts +15 -1
- package/lib/types/templates/index.d.ts +1 -0
- package/lib/types/templates/index.logger.template.d.ts +15 -1
- package/lib/types/templates/index.template.d.ts +15 -1
- package/lib/types/templates/interceptor.template.d.ts +15 -1
- package/lib/types/templates/interface.template.d.ts +15 -1
- package/lib/types/templates/middleware.template.d.ts +16 -1
- package/lib/types/templates/model.template.d.ts +15 -1
- package/lib/types/templates/module.template.d.ts +15 -1
- package/lib/types/templates/new-template.template.d.ts +9 -0
- package/lib/types/templates/pipe.template.d.ts +15 -1
- package/lib/types/templates/prisma.service.template.d.ts +15 -1
- package/lib/types/templates/readme.template.d.ts +15 -1
- package/lib/types/templates/repository.template.d.ts +15 -1
- package/lib/types/templates/response-filter.template.d.ts +15 -1
- package/lib/types/templates/server.template.d.ts +15 -1
- package/lib/types/templates/service.template.d.ts +15 -1
- package/lib/types/templates/tsconfig.spec.template.d.ts +15 -1
- package/lib/types/templates/tsconfig.template.d.ts +15 -1
- package/lib/types/templates/value.template.d.ts +15 -1
- package/lib/types/utils/defineTemplate.d.ts +31 -3
- package/package.json +3 -3
package/lib/esm/Cli.js
CHANGED
package/lib/esm/bin/tsed.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { command, inject, ProjectPackageJson } from "@tsed/cli-core";
|
|
2
|
-
import { pascalCase } from "change-case";
|
|
3
2
|
import { CliProjectService } from "../../services/CliProjectService.js";
|
|
4
3
|
import { CliTemplatesService } from "../../services/CliTemplatesService.js";
|
|
4
|
+
import { addContextMethods } from "../../services/mappers/addContextMethods.js";
|
|
5
5
|
import { mapDefaultTemplateOptions } from "../../services/mappers/mapDefaultTemplateOptions.js";
|
|
6
6
|
const searchFactory = (list) => {
|
|
7
|
+
const items = list.map((item) => ({ name: item.label, value: item.id }));
|
|
7
8
|
return (_, keyword) => {
|
|
8
9
|
if (keyword) {
|
|
9
|
-
return
|
|
10
|
+
return items.filter((item) => item.name.toLowerCase().includes(keyword.toLowerCase()));
|
|
10
11
|
}
|
|
11
|
-
return
|
|
12
|
+
return items;
|
|
12
13
|
};
|
|
13
14
|
};
|
|
14
15
|
export class GenerateCmd {
|
|
@@ -18,7 +19,7 @@ export class GenerateCmd {
|
|
|
18
19
|
this.templates = inject(CliTemplatesService);
|
|
19
20
|
}
|
|
20
21
|
async $prompt(data) {
|
|
21
|
-
data
|
|
22
|
+
data = addContextMethods(data);
|
|
22
23
|
const templates = this.templates.find();
|
|
23
24
|
const templatesPrompts = await Promise.all(templates
|
|
24
25
|
.filter((template) => template.prompts)
|
|
@@ -29,7 +30,7 @@ export class GenerateCmd {
|
|
|
29
30
|
{
|
|
30
31
|
type: "autocomplete",
|
|
31
32
|
name: "type",
|
|
32
|
-
message: "Which
|
|
33
|
+
message: "Which template you want to use?",
|
|
33
34
|
default: data.type,
|
|
34
35
|
when: () => templates.length > 1,
|
|
35
36
|
source: searchFactory(this.templates.find(data.type))
|
|
@@ -2,5 +2,6 @@ import { AddCmd } from "./add/AddCmd.js";
|
|
|
2
2
|
import { GenerateCmd } from "./generate/GenerateCmd.js";
|
|
3
3
|
import { InitCmd } from "./init/InitCmd.js";
|
|
4
4
|
import { RunCmd } from "./run/RunCmd.js";
|
|
5
|
+
import { CreateTemplateCommand } from "./template/CreateTemplateCommand.js";
|
|
5
6
|
import { UpdateCmd } from "./update/UpdateCmd.js";
|
|
6
|
-
export default [AddCmd, InitCmd, GenerateCmd, UpdateCmd, RunCmd];
|
|
7
|
+
export default [AddCmd, InitCmd, GenerateCmd, UpdateCmd, RunCmd, CreateTemplateCommand];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ArchitectureConvention, PlatformType, ProjectConvention } from "../../../interfaces/index.js";
|
|
2
|
-
import { hasFeature, hasValue } from "../utils/hasFeature.js";
|
|
2
|
+
import { hasFeature, hasValue, hasValuePremium } from "../utils/hasFeature.js";
|
|
3
3
|
import { isPlatform } from "../utils/isPlatform.js";
|
|
4
4
|
export var FeatureType;
|
|
5
5
|
(function (FeatureType) {
|
|
@@ -16,11 +16,11 @@ export var FeatureType;
|
|
|
16
16
|
FeatureType["CONFIG_DOTENV"] = "config:dotenv";
|
|
17
17
|
FeatureType["CONFIG_JSON"] = "config:json";
|
|
18
18
|
FeatureType["CONFIG_YAML"] = "config:yaml";
|
|
19
|
-
FeatureType["CONFIG_AWS_SECRETS"] = "config:aws_secrets";
|
|
20
|
-
FeatureType["CONFIG_IOREDIS"] = "config:ioredis";
|
|
21
|
-
FeatureType["CONFIG_MONGO"] = "config:mongo";
|
|
22
|
-
FeatureType["CONFIG_VAULT"] = "config:vault";
|
|
23
|
-
FeatureType["CONFIG_POSTGRES"] = "config:postgres";
|
|
19
|
+
FeatureType["CONFIG_AWS_SECRETS"] = "config:aws_secrets:premium";
|
|
20
|
+
FeatureType["CONFIG_IOREDIS"] = "config:ioredis:premium";
|
|
21
|
+
FeatureType["CONFIG_MONGO"] = "config:mongo:premium";
|
|
22
|
+
FeatureType["CONFIG_VAULT"] = "config:vault:premium";
|
|
23
|
+
FeatureType["CONFIG_POSTGRES"] = "config:postgres:premium";
|
|
24
24
|
// DOC
|
|
25
25
|
FeatureType["SWAGGER"] = "swagger";
|
|
26
26
|
FeatureType["SCALAR"] = "scalar";
|
|
@@ -453,13 +453,12 @@ export const FeaturesPrompt = (availableRuntimes, availablePackageManagers) => [
|
|
|
453
453
|
],
|
|
454
454
|
when: hasValue("featuresDB", FeatureType.TYPEORM)
|
|
455
455
|
},
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
// },
|
|
456
|
+
{
|
|
457
|
+
type: "password",
|
|
458
|
+
name: "GH_TOKEN",
|
|
459
|
+
message: "Enter GH_TOKEN to use the premium @tsedio package or leave blank (see https://tsed.dev/plugins/premium/install-premium-plugins.html)",
|
|
460
|
+
when: hasValuePremium()
|
|
461
|
+
},
|
|
463
462
|
{
|
|
464
463
|
message: "Choose unit framework",
|
|
465
464
|
type: "list",
|
|
@@ -4,6 +4,10 @@ export function mapToContext(options) {
|
|
|
4
4
|
options = mapUniqFeatures(options);
|
|
5
5
|
options.features.forEach((feature) => {
|
|
6
6
|
const [base, type] = feature.split(":");
|
|
7
|
+
if (feature?.endsWith(":premium")) {
|
|
8
|
+
feature = feature.replace(":premium", "");
|
|
9
|
+
options.premium = true;
|
|
10
|
+
}
|
|
7
11
|
options[camelCase(base)] = true;
|
|
8
12
|
type && (options[camelCase(type)] = true);
|
|
9
13
|
feature && (options[camelCase(feature)] = true);
|
|
@@ -18,15 +18,3 @@ export function getFeaturesPrompt(runtimes, availablePackageManagers, options) {
|
|
|
18
18
|
});
|
|
19
19
|
});
|
|
20
20
|
}
|
|
21
|
-
export function getFrameworksPrompt() {
|
|
22
|
-
return {
|
|
23
|
-
...FrameworksPrompt,
|
|
24
|
-
choices: FrameworksPrompt.choices.map((choice, index) => {
|
|
25
|
-
return cleanObject({
|
|
26
|
-
...FeaturesMap[choice],
|
|
27
|
-
checked: index === 0,
|
|
28
|
-
value: choice
|
|
29
|
-
});
|
|
30
|
-
})
|
|
31
|
-
};
|
|
32
|
-
}
|
|
@@ -5,3 +5,6 @@ export function hasValue(expression, value) {
|
|
|
5
5
|
export function hasFeature(feature) {
|
|
6
6
|
return (ctx) => !!ctx.features.find((item) => item === feature);
|
|
7
7
|
}
|
|
8
|
+
export function hasValuePremium() {
|
|
9
|
+
return (ctx) => !!ctx.features.find((item) => item.endsWith(":premium"));
|
|
10
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { command, inject, ProjectPackageJson } from "@tsed/cli-core";
|
|
2
|
+
import { snakeCase } from "change-case";
|
|
3
|
+
import { render } from "../../fn/render.js";
|
|
4
|
+
import { CliTemplatesService } from "../../services/CliTemplatesService.js";
|
|
5
|
+
const searchFactory = (list) => {
|
|
6
|
+
const items = list.map((item) => ({ name: item.label, value: item.id }));
|
|
7
|
+
return (_, keyword) => {
|
|
8
|
+
if (keyword) {
|
|
9
|
+
return items.filter((item) => item.name.toLowerCase().includes(keyword.toLowerCase()));
|
|
10
|
+
}
|
|
11
|
+
return items;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
export class CreateTemplateCommand {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.projectPackageJson = inject(ProjectPackageJson);
|
|
17
|
+
this.templates = inject(CliTemplatesService);
|
|
18
|
+
}
|
|
19
|
+
async $prompt(data) {
|
|
20
|
+
return [
|
|
21
|
+
{
|
|
22
|
+
type: "list",
|
|
23
|
+
name: "from",
|
|
24
|
+
message: "Create a template from existing one?",
|
|
25
|
+
default: "new",
|
|
26
|
+
when: !data.from,
|
|
27
|
+
choices: [
|
|
28
|
+
{ name: "No, create a new template", value: "new" },
|
|
29
|
+
{ name: "Yes, from existing template", value: "existing" }
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
type: "autocomplete",
|
|
34
|
+
name: "templateId",
|
|
35
|
+
message: "Select the template to use as base",
|
|
36
|
+
default: data.from,
|
|
37
|
+
when: (ctx) => {
|
|
38
|
+
return ctx.from === "existing";
|
|
39
|
+
},
|
|
40
|
+
source: searchFactory(this.templates.find())
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
type: "confirm",
|
|
44
|
+
name: "override",
|
|
45
|
+
message: "Would you like to override the selected Ts.ED default template?",
|
|
46
|
+
when: (ctx) => ctx.from !== "new",
|
|
47
|
+
default: !!data.override
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
type: "input",
|
|
51
|
+
name: "name",
|
|
52
|
+
message: "Which name?",
|
|
53
|
+
default: data.name,
|
|
54
|
+
when: !data.name
|
|
55
|
+
}
|
|
56
|
+
];
|
|
57
|
+
}
|
|
58
|
+
$mapContext(ctx) {
|
|
59
|
+
const symbolName = snakeCase(ctx.name).replace(/_/g, "-");
|
|
60
|
+
return {
|
|
61
|
+
...ctx,
|
|
62
|
+
symbolPath: `./.templates/${symbolName}.template`,
|
|
63
|
+
symbolPathBasename: ".",
|
|
64
|
+
symbolName: symbolName,
|
|
65
|
+
templateId: ctx.orverride ? ctx.templateId : symbolName,
|
|
66
|
+
template: ctx.templateId && this.templates.get(ctx.templateId)
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
$exec(ctx) {
|
|
70
|
+
return [
|
|
71
|
+
{
|
|
72
|
+
title: "Generate " + ctx.from === "new" ? `new template ${ctx.templateId}` : `template ${ctx.templateId} from ${ctx.from}`,
|
|
73
|
+
task: async () => {
|
|
74
|
+
await render("new-template", ctx);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
command(CreateTemplateCommand, {
|
|
81
|
+
name: "template",
|
|
82
|
+
description: "Create a custom template that can be selected in tsed generate command",
|
|
83
|
+
args: {
|
|
84
|
+
name: {
|
|
85
|
+
description: "Name of the class",
|
|
86
|
+
type: String
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
options: {
|
|
90
|
+
"--from <from>": {
|
|
91
|
+
type: String,
|
|
92
|
+
description: "Select the template to use as base"
|
|
93
|
+
},
|
|
94
|
+
"--override": {
|
|
95
|
+
type: Boolean,
|
|
96
|
+
description: "Override the existing selected template"
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
});
|
|
@@ -32,7 +32,7 @@ export class CliProjectService {
|
|
|
32
32
|
this.project = new ProjectClient({
|
|
33
33
|
rootDir: this.rootDir
|
|
34
34
|
});
|
|
35
|
-
const files = fs.globSync([join(constant("project.rootDir", process.cwd()), "**/*.ts")]);
|
|
35
|
+
const files = fs.globSync(["!**/node_modules/**", join(constant("project.rootDir", process.cwd()), "**/*.ts")]);
|
|
36
36
|
files.forEach((file) => {
|
|
37
37
|
this.project.createSourceFile(file, fs.readFileSync(file, "utf8"), {
|
|
38
38
|
overwrite: true
|
|
@@ -66,15 +66,14 @@ export class CliProjectService {
|
|
|
66
66
|
return sourceFile.save();
|
|
67
67
|
}));
|
|
68
68
|
}
|
|
69
|
-
async createFromTemplate(templateId,
|
|
70
|
-
const
|
|
71
|
-
const obj = await this.templates.render(templateId, ctx);
|
|
72
|
-
taskOutput(`Template ${templateId} rendered in ${Date.now() - startTime}ms`);
|
|
69
|
+
async createFromTemplate(templateId, data) {
|
|
70
|
+
const obj = await this.templates.render(templateId, data);
|
|
73
71
|
const project = this.get();
|
|
74
72
|
if (obj) {
|
|
75
73
|
const sourceFile = await project.createSource(obj.outputPath, obj.content, {
|
|
76
74
|
overwrite: true
|
|
77
75
|
});
|
|
76
|
+
sourceFile && this.templates.get(templateId)?.hooks?.$afterCreateSourceFile?.(sourceFile, data);
|
|
78
77
|
return {
|
|
79
78
|
...obj,
|
|
80
79
|
source: sourceFile
|
|
@@ -1,27 +1,75 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import { CliFs } from "@tsed/cli-core";
|
|
3
|
-
import { constant, inject, injectable, injectMany } from "@tsed/di";
|
|
3
|
+
import { constant, inject, injectable, injectMany, logger } from "@tsed/di";
|
|
4
|
+
import { globby } from "globby";
|
|
4
5
|
import { TEMPLATE_DIR } from "../constants/index.js";
|
|
5
6
|
import { mapDefaultTemplateOptions } from "./mappers/mapDefaultTemplateOptions.js";
|
|
6
7
|
export class CliTemplatesService {
|
|
7
8
|
constructor() {
|
|
8
9
|
this.rootDir = constant("project.rootDir", process.cwd());
|
|
9
10
|
this.fs = inject(CliFs);
|
|
11
|
+
this.#templates = new Map();
|
|
10
12
|
}
|
|
13
|
+
#customTemplates;
|
|
14
|
+
#templates;
|
|
11
15
|
get srcDir() {
|
|
12
16
|
return join(...[this.rootDir, constant("project.srcDir")].filter(Boolean));
|
|
13
17
|
}
|
|
18
|
+
get templatesDir() {
|
|
19
|
+
return join(this.rootDir, ".templates");
|
|
20
|
+
}
|
|
21
|
+
$onInit() {
|
|
22
|
+
return this.loadTemplates();
|
|
23
|
+
}
|
|
24
|
+
async loadTemplates() {
|
|
25
|
+
if (!this.#customTemplates?.length) {
|
|
26
|
+
const files = await globby("**/*.ts", {
|
|
27
|
+
cwd: this.templatesDir
|
|
28
|
+
});
|
|
29
|
+
const promises = files.map(async (file) => {
|
|
30
|
+
try {
|
|
31
|
+
const files = join(this.templatesDir, file);
|
|
32
|
+
const { default: token } = await import(files.replace(".ts", ".js"));
|
|
33
|
+
if (token) {
|
|
34
|
+
return inject(token);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch (er) {
|
|
38
|
+
logger().warn("Unable to load custom template %s: %s", file, er.message);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
let customs = await Promise.all(promises);
|
|
42
|
+
this.#customTemplates = customs.map((template) => {
|
|
43
|
+
return {
|
|
44
|
+
...template,
|
|
45
|
+
label: template.label + " (custom)"
|
|
46
|
+
};
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
getAll() {
|
|
51
|
+
const templates = injectMany("CLI_TEMPLATES");
|
|
52
|
+
const map = (this.#customTemplates || []).concat(templates).reduce((acc, template) => {
|
|
53
|
+
if (acc.has(template.id)) {
|
|
54
|
+
return acc;
|
|
55
|
+
}
|
|
56
|
+
return acc.set(template.id, template);
|
|
57
|
+
}, new Map());
|
|
58
|
+
return [...map.values()];
|
|
59
|
+
}
|
|
14
60
|
find(id) {
|
|
15
|
-
const templates =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
61
|
+
const templates = this.getAll().filter((template) => !template.hidden);
|
|
62
|
+
if (id) {
|
|
63
|
+
id = id?.toLowerCase();
|
|
64
|
+
const foundTemplates = templates.filter((template) => {
|
|
65
|
+
return template.label.toLowerCase().includes(id) || template.id.includes(id);
|
|
66
|
+
});
|
|
67
|
+
return foundTemplates.length ? foundTemplates : templates;
|
|
68
|
+
}
|
|
69
|
+
return templates;
|
|
21
70
|
}
|
|
22
71
|
get(id) {
|
|
23
|
-
|
|
24
|
-
return templates.find((template) => template.id === id);
|
|
72
|
+
return this.getAll().find((template) => template.id === id);
|
|
25
73
|
}
|
|
26
74
|
async render(templateId, data) {
|
|
27
75
|
const template = this.get(templateId);
|
|
@@ -113,6 +113,28 @@ export class ProjectClient extends Project {
|
|
|
113
113
|
})
|
|
114
114
|
.getInitializerIfKindOrThrow(kind));
|
|
115
115
|
}
|
|
116
|
+
addConfigSource(name, { content = name, moduleSpecifier }) {
|
|
117
|
+
const sourceFile = this.configSourceFile;
|
|
118
|
+
const options = this.findConfiguration("config");
|
|
119
|
+
if (!options) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const extendsConfig = this.getPropertyAssignment(options, {
|
|
123
|
+
name: "extends",
|
|
124
|
+
kind: SyntaxKind.ArrayLiteralExpression,
|
|
125
|
+
initializer: "[]"
|
|
126
|
+
});
|
|
127
|
+
const has = extendsConfig.getElements().some((expression) => {
|
|
128
|
+
return expression.getText().includes(name);
|
|
129
|
+
});
|
|
130
|
+
if (!has) {
|
|
131
|
+
sourceFile.addImportDeclaration({
|
|
132
|
+
moduleSpecifier,
|
|
133
|
+
namedImports: [{ name: name }]
|
|
134
|
+
});
|
|
135
|
+
extendsConfig.addElement("\n" + content);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
116
138
|
findConfigurationDecorationOptions() {
|
|
117
139
|
if (!this.serverSourceFile) {
|
|
118
140
|
return;
|
|
@@ -137,26 +159,4 @@ export class ProjectClient extends Project {
|
|
|
137
159
|
}
|
|
138
160
|
return undefined;
|
|
139
161
|
}
|
|
140
|
-
addConfigSource(name, { content = name, moduleSpecifier }) {
|
|
141
|
-
const sourceFile = this.configSourceFile;
|
|
142
|
-
const options = this.findConfiguration("config");
|
|
143
|
-
if (!options) {
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
const extendsConfig = this.getPropertyAssignment(options, {
|
|
147
|
-
name: "extends",
|
|
148
|
-
kind: SyntaxKind.ArrayLiteralExpression,
|
|
149
|
-
initializer: "[]"
|
|
150
|
-
});
|
|
151
|
-
const has = extendsConfig.getElements().some((expression) => {
|
|
152
|
-
return expression.getText().includes(name);
|
|
153
|
-
});
|
|
154
|
-
if (!has) {
|
|
155
|
-
sourceFile.addImportDeclaration({
|
|
156
|
-
moduleSpecifier,
|
|
157
|
-
namedImports: [{ name: name }]
|
|
158
|
-
});
|
|
159
|
-
extendsConfig.addElement("\n" + content);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
162
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { inject } from "@tsed/cli-core";
|
|
2
|
+
import { isString } from "@tsed/core";
|
|
3
|
+
import { pascalCase } from "change-case";
|
|
4
|
+
import { RoutePipe } from "../../pipes/RoutePipe.js";
|
|
5
|
+
import { CliProjectService } from "../CliProjectService.js";
|
|
6
|
+
export function addContextMethods(context) {
|
|
7
|
+
const getName = (state) => context.name || pascalCase(state.name || context.name || state.type || context.type || "");
|
|
8
|
+
return {
|
|
9
|
+
getName,
|
|
10
|
+
getRoute: (state) => {
|
|
11
|
+
return inject(RoutePipe).transform(isString(state) ? state : getName(state));
|
|
12
|
+
},
|
|
13
|
+
getDirectories: (dir) => {
|
|
14
|
+
return inject(CliProjectService).getDirectories(dir);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { inject, ProjectPackageJson } from "@tsed/cli-core";
|
|
2
|
+
import { isString } from "@tsed/core";
|
|
2
3
|
import { normalizePath } from "@tsed/normalize-path";
|
|
4
|
+
import { pascalCase } from "change-case";
|
|
3
5
|
import { ProjectConvention } from "../../interfaces/ProjectConvention.js";
|
|
4
6
|
import { OutputFilePathPipe } from "../../pipes/OutputFilePathPipe.js";
|
|
7
|
+
import { RoutePipe } from "../../pipes/RoutePipe.js";
|
|
5
8
|
import { SymbolNamePipe } from "../../pipes/SymbolNamePipe.js";
|
|
9
|
+
import { CliProjectService } from "../CliProjectService.js";
|
|
10
|
+
import { addContextMethods } from "./addContextMethods.js";
|
|
6
11
|
export function mapDefaultTemplateOptions(opts) {
|
|
7
12
|
const classNamePipe = inject(SymbolNamePipe);
|
|
8
13
|
const outputFilePathPipe = inject(OutputFilePathPipe);
|
|
@@ -25,6 +30,7 @@ export function mapDefaultTemplateOptions(opts) {
|
|
|
25
30
|
type,
|
|
26
31
|
symbolName,
|
|
27
32
|
symbolPath,
|
|
28
|
-
symbolPathBasename: opts.symbolPathBasename || normalizePath(classNamePipe.transform({ name, type }))
|
|
33
|
+
symbolPathBasename: opts.symbolPathBasename || normalizePath(classNamePipe.transform({ name, type })),
|
|
34
|
+
...addContextMethods(opts)
|
|
29
35
|
};
|
|
30
36
|
}
|
|
@@ -7,13 +7,14 @@ export default defineTemplate({
|
|
|
7
7
|
fileName: ".barrels",
|
|
8
8
|
ext: "json",
|
|
9
9
|
outputDir: ".",
|
|
10
|
+
hidden: true,
|
|
10
11
|
preserveCase: true,
|
|
11
12
|
prompts() {
|
|
12
13
|
return [];
|
|
13
14
|
},
|
|
14
|
-
render(_,
|
|
15
|
+
render(_, context) {
|
|
15
16
|
const barrels = $alter("$alterBarrels", {
|
|
16
|
-
directory: ["./src/controllers/rest",
|
|
17
|
+
directory: ["./src/controllers/rest", (context.swagger || context.oidc) && "./src/controllers/pages"].filter(Boolean),
|
|
17
18
|
exclude: ["**/__mock__", "**/__mocks__", "**/*.spec.ts"],
|
|
18
19
|
delete: true
|
|
19
20
|
});
|
|
@@ -1,36 +1,35 @@
|
|
|
1
1
|
import { defineTemplate } from "../utils/defineTemplate.js";
|
|
2
|
-
import { RoutePipe } from "../pipes/index.js";
|
|
3
|
-
import { CliProjectService } from "../services/CliProjectService.js";
|
|
4
|
-
import { inject } from "@tsed/di";
|
|
5
2
|
export default defineTemplate({
|
|
6
3
|
id: "controller",
|
|
7
4
|
label: "Controller",
|
|
8
5
|
fileName: "{{symbolName}}.controller",
|
|
9
6
|
outputDir: "{{srcDir}}/controllers",
|
|
10
|
-
prompts
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
prompts(context) {
|
|
8
|
+
return [
|
|
9
|
+
{
|
|
10
|
+
type: "list",
|
|
11
|
+
name: "directory",
|
|
12
|
+
message: "Which directory?",
|
|
13
|
+
when(state) {
|
|
14
|
+
return !!(["controller"].includes(state.type || context.type) || context.directory);
|
|
15
|
+
},
|
|
16
|
+
choices: context.getDirectories("controllers")
|
|
17
17
|
},
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return inject(RoutePipe).transform(data.getName(state));
|
|
18
|
+
{
|
|
19
|
+
type: "input",
|
|
20
|
+
name: "route",
|
|
21
|
+
message: "Which route?",
|
|
22
|
+
when(state) {
|
|
23
|
+
return !!(["controller"].includes(state.type || context.type) || context.route);
|
|
24
|
+
},
|
|
25
|
+
default: (state) => {
|
|
26
|
+
return context.getRoute(state);
|
|
27
|
+
}
|
|
29
28
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
render(symbolName,
|
|
33
|
-
const route =
|
|
29
|
+
];
|
|
30
|
+
},
|
|
31
|
+
render(symbolName, context) {
|
|
32
|
+
const route = context.getRoute(context.route);
|
|
34
33
|
return `import {Controller} from "@tsed/di";
|
|
35
34
|
import {Get} from "@tsed/schema";
|
|
36
35
|
|
|
@@ -4,30 +4,32 @@ export default defineTemplate({
|
|
|
4
4
|
label: "Decorator",
|
|
5
5
|
fileName: "{{symbolName}}",
|
|
6
6
|
outputDir: "{{srcDir}}/decorators",
|
|
7
|
-
prompts
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
7
|
+
prompts(context) {
|
|
8
|
+
return [
|
|
9
|
+
{
|
|
10
|
+
type: "list",
|
|
11
|
+
name: "templateType",
|
|
12
|
+
message: "What kind of decorator do you want to create?",
|
|
13
|
+
when(state) {
|
|
14
|
+
return !!(["decorator"].includes(state.type || context.type) || context.templateType);
|
|
15
|
+
},
|
|
16
|
+
choices: [
|
|
17
|
+
{ name: "Class Decorator", value: "class" },
|
|
18
|
+
{ name: "Generic Decorator (class, property)", value: "generic" },
|
|
19
|
+
{ name: "Method Decorator", value: "method" },
|
|
20
|
+
{ name: "Parameter Decorator", value: "param" },
|
|
21
|
+
{ name: "Property Decorator", value: "property" },
|
|
22
|
+
{ name: "Property Decorator (with @Property)", value: "prop" },
|
|
23
|
+
{ name: "Parameters Decorator", value: "parameters" },
|
|
24
|
+
{ name: "Endpoint Decorator", value: "endpoint" },
|
|
25
|
+
{ name: "Middleware Decorator", value: "middleware" }
|
|
26
|
+
],
|
|
27
|
+
default: "class"
|
|
28
|
+
}
|
|
29
|
+
];
|
|
30
|
+
},
|
|
31
|
+
render(symbolName, context) {
|
|
32
|
+
const type = context.templateType || "class";
|
|
31
33
|
switch (type) {
|
|
32
34
|
case "class":
|
|
33
35
|
return `
|
|
@@ -7,7 +7,7 @@ export default defineTemplate({
|
|
|
7
7
|
outputDir: ".",
|
|
8
8
|
ext: "yml",
|
|
9
9
|
preserveCase: true,
|
|
10
|
-
render(_,
|
|
10
|
+
render(_, context) {
|
|
11
11
|
return `services:
|
|
12
12
|
server:
|
|
13
13
|
build:
|
|
@@ -17,7 +17,7 @@ export default defineTemplate({
|
|
|
17
17
|
- http_proxy
|
|
18
18
|
- https_proxy
|
|
19
19
|
- no_proxy
|
|
20
|
-
image: ${
|
|
20
|
+
image: ${context.projectName}/server:latest
|
|
21
21
|
ports:
|
|
22
22
|
- "8081:8081"
|
|
23
23
|
`;
|