@forgerapi/codegen 0.0.1
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/dist/codemod.d.ts +3 -0
- package/dist/codemod.js +181 -0
- package/dist/generators/action/controller.d.ts +5 -0
- package/dist/generators/action/controller.js +51 -0
- package/dist/generators/action/dto.d.ts +2 -0
- package/dist/generators/action/dto.js +15 -0
- package/dist/generators/action/event.d.ts +1 -0
- package/dist/generators/action/event.js +10 -0
- package/dist/generators/action/impl.d.ts +5 -0
- package/dist/generators/action/impl.js +25 -0
- package/dist/generators/action/index.d.ts +6 -0
- package/dist/generators/action/index.js +15 -0
- package/dist/generators/action/module.d.ts +4 -0
- package/dist/generators/action/module.js +25 -0
- package/dist/generators/action/service.d.ts +2 -0
- package/dist/generators/action/service.js +24 -0
- package/dist/generators/controller.d.ts +3 -0
- package/dist/generators/controller.js +66 -0
- package/dist/generators/dto.d.ts +9 -0
- package/dist/generators/dto.js +128 -0
- package/dist/generators/enum.d.ts +2 -0
- package/dist/generators/enum.js +12 -0
- package/dist/generators/forger-module/forger-module.d.ts +6 -0
- package/dist/generators/forger-module/forger-module.js +49 -0
- package/dist/generators/forger-module/index.d.ts +1 -0
- package/dist/generators/forger-module/index.js +5 -0
- package/dist/generators/forger-modules.d.ts +2 -0
- package/dist/generators/forger-modules.js +40 -0
- package/dist/generators/guard/guard.d.ts +2 -0
- package/dist/generators/guard/guard.js +15 -0
- package/dist/generators/guard/index.d.ts +1 -0
- package/dist/generators/guard/index.js +5 -0
- package/dist/generators/module/index.d.ts +1 -0
- package/dist/generators/module/index.js +5 -0
- package/dist/generators/module/module-module.d.ts +2 -0
- package/dist/generators/module/module-module.js +46 -0
- package/dist/generators/module.d.ts +4 -0
- package/dist/generators/module.js +25 -0
- package/dist/generators/prisma-module.d.ts +1 -0
- package/dist/generators/prisma-module.js +15 -0
- package/dist/generators/prisma-service.d.ts +1 -0
- package/dist/generators/prisma-service.js +22 -0
- package/dist/generators/prisma.d.ts +2 -0
- package/dist/generators/prisma.js +101 -0
- package/dist/generators/service.d.ts +8 -0
- package/dist/generators/service.js +71 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +376 -0
- package/dist/schema-cache.d.ts +25 -0
- package/dist/schema-cache.js +98 -0
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +6 -0
- package/package.json +29 -0
package/dist/codemod.js
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.applyCodemod = applyCodemod;
|
|
4
|
+
exports.registerForgerModules = registerForgerModules;
|
|
5
|
+
const node_fs_1 = require("node:fs");
|
|
6
|
+
const node_path_1 = require("node:path");
|
|
7
|
+
const ts_morph_1 = require("ts-morph");
|
|
8
|
+
const utils_1 = require("./utils");
|
|
9
|
+
function applyCodemod(outDir, renames) {
|
|
10
|
+
const logs = [];
|
|
11
|
+
const project = new ts_morph_1.Project();
|
|
12
|
+
for (const r of renames) {
|
|
13
|
+
if (r.type === "model") {
|
|
14
|
+
const log = renameModelImpl(outDir, r.oldName, r.newName, project);
|
|
15
|
+
if (log)
|
|
16
|
+
logs.push(log);
|
|
17
|
+
const oldDir = (0, node_path_1.resolve)(outDir, (0, utils_1.toKebab)(r.oldName));
|
|
18
|
+
if ((0, node_fs_1.existsSync)(oldDir)) {
|
|
19
|
+
(0, node_fs_1.rmSync)(oldDir, { recursive: true, force: true });
|
|
20
|
+
logs.push(` removed old model directory: ${oldDir}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
else if (r.type === "action") {
|
|
24
|
+
const log = renameActionImpl(outDir, r.oldName, r.newName, project);
|
|
25
|
+
if (log)
|
|
26
|
+
logs.push(log);
|
|
27
|
+
const oldDir = (0, node_path_1.resolve)(outDir, (0, utils_1.toKebab)(r.oldName));
|
|
28
|
+
if ((0, node_fs_1.existsSync)(oldDir)) {
|
|
29
|
+
(0, node_fs_1.rmSync)(oldDir, { recursive: true, force: true });
|
|
30
|
+
logs.push(` removed old action directory: ${oldDir}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return logs;
|
|
35
|
+
}
|
|
36
|
+
function renameModelImpl(outDir, oldName, newName, project) {
|
|
37
|
+
const oldKebab = (0, utils_1.toKebab)(oldName);
|
|
38
|
+
const newKebab = (0, utils_1.toKebab)(newName);
|
|
39
|
+
const oldPath = (0, node_path_1.resolve)(outDir, oldKebab, "impl", `${oldKebab}.impl.ts`);
|
|
40
|
+
const newDir = (0, node_path_1.resolve)(outDir, newKebab, "impl");
|
|
41
|
+
const newPath = (0, node_path_1.resolve)(newDir, `${newKebab}.impl.ts`);
|
|
42
|
+
if (!(0, node_fs_1.existsSync)(oldPath))
|
|
43
|
+
return null;
|
|
44
|
+
(0, node_fs_1.mkdirSync)(newDir, { recursive: true });
|
|
45
|
+
const sourceFile = project.addSourceFileAtPath(oldPath);
|
|
46
|
+
const classes = sourceFile.getClasses();
|
|
47
|
+
for (const cls of classes) {
|
|
48
|
+
const oldClassName = `${oldName}ImplService`;
|
|
49
|
+
const newClassName = `${newName}ImplService`;
|
|
50
|
+
if (cls.getName() === oldClassName) {
|
|
51
|
+
cls.rename(newClassName);
|
|
52
|
+
}
|
|
53
|
+
const extendsDec = cls.getExtends();
|
|
54
|
+
if (extendsDec) {
|
|
55
|
+
const oldExtends = `${oldName}AbstractService`;
|
|
56
|
+
const newExtends = `${newName}AbstractService`;
|
|
57
|
+
if (extendsDec.getText() === oldExtends) {
|
|
58
|
+
extendsDec.replaceWithText(newExtends);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const importDecls = sourceFile.getImportDeclarations();
|
|
63
|
+
for (const imp of importDecls) {
|
|
64
|
+
const moduleSpecifier = imp.getModuleSpecifierValue();
|
|
65
|
+
if (moduleSpecifier.includes(oldKebab)) {
|
|
66
|
+
imp.setModuleSpecifier(moduleSpecifier.replace(oldKebab, newKebab));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
sourceFile.move(newPath);
|
|
70
|
+
sourceFile.saveSync();
|
|
71
|
+
(0, node_fs_1.unlinkSync)(oldPath);
|
|
72
|
+
return ` renamed model impl: ${oldName} → ${newName}`;
|
|
73
|
+
}
|
|
74
|
+
function registerForgerModules(outDir, hasModules) {
|
|
75
|
+
const appModulePath = (0, node_path_1.resolve)(outDir, "app.module.ts");
|
|
76
|
+
if (!(0, node_fs_1.existsSync)(appModulePath))
|
|
77
|
+
return null;
|
|
78
|
+
const project = new ts_morph_1.Project();
|
|
79
|
+
const sourceFile = project.addSourceFileAtPath(appModulePath);
|
|
80
|
+
const existingImport = sourceFile.getImportDeclaration((dec) => dec.getModuleSpecifierValue() === "./forger-modules.module");
|
|
81
|
+
if (hasModules) {
|
|
82
|
+
if (existingImport)
|
|
83
|
+
return null;
|
|
84
|
+
sourceFile.addImportDeclaration({
|
|
85
|
+
moduleSpecifier: "./forger-modules.module",
|
|
86
|
+
namedImports: ["ForgerModulesModule"],
|
|
87
|
+
});
|
|
88
|
+
const classDec = sourceFile.getClasses()[0];
|
|
89
|
+
if (!classDec)
|
|
90
|
+
return null;
|
|
91
|
+
const moduleDecorator = classDec.getDecorator("Module");
|
|
92
|
+
if (!moduleDecorator)
|
|
93
|
+
return null;
|
|
94
|
+
const arg = moduleDecorator.getArguments()[0];
|
|
95
|
+
if (!arg)
|
|
96
|
+
return null;
|
|
97
|
+
const properties = arg.getChildrenOfKind(ts_morph_1.SyntaxKind.PropertyAssignment);
|
|
98
|
+
const importsProp = properties.find((p) => p.getName() === "imports");
|
|
99
|
+
if (importsProp) {
|
|
100
|
+
const initializer = importsProp.getInitializer();
|
|
101
|
+
if (initializer?.getKind() === ts_morph_1.SyntaxKind.ArrayLiteralExpression) {
|
|
102
|
+
const arr = initializer.asKindOrThrow(ts_morph_1.SyntaxKind.ArrayLiteralExpression);
|
|
103
|
+
const existingElements = arr
|
|
104
|
+
.getElements()
|
|
105
|
+
.map((e) => e.getText());
|
|
106
|
+
if (!existingElements.includes("ForgerModulesModule")) {
|
|
107
|
+
arr.addElement("ForgerModulesModule");
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
sourceFile.saveSync();
|
|
112
|
+
return ` registered ForgerModulesModule in AppModule`;
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
if (!existingImport)
|
|
116
|
+
return null;
|
|
117
|
+
existingImport.remove();
|
|
118
|
+
const classDec = sourceFile.getClasses()[0];
|
|
119
|
+
if (!classDec)
|
|
120
|
+
return null;
|
|
121
|
+
const moduleDecorator = classDec.getDecorator("Module");
|
|
122
|
+
if (!moduleDecorator)
|
|
123
|
+
return null;
|
|
124
|
+
const arg = moduleDecorator.getArguments()[0];
|
|
125
|
+
if (!arg)
|
|
126
|
+
return null;
|
|
127
|
+
const properties = arg.getChildrenOfKind(ts_morph_1.SyntaxKind.PropertyAssignment);
|
|
128
|
+
const importsProp = properties.find((p) => p.getName() === "imports");
|
|
129
|
+
if (importsProp) {
|
|
130
|
+
const initializer = importsProp.getInitializer();
|
|
131
|
+
if (initializer?.getKind() === ts_morph_1.SyntaxKind.ArrayLiteralExpression) {
|
|
132
|
+
const arr = initializer.asKindOrThrow(ts_morph_1.SyntaxKind.ArrayLiteralExpression);
|
|
133
|
+
const elements = arr.getElements();
|
|
134
|
+
const idx = elements.findIndex((e) => e.getText() === "ForgerModulesModule");
|
|
135
|
+
if (idx !== -1) {
|
|
136
|
+
arr.removeElement(idx);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
sourceFile.saveSync();
|
|
141
|
+
return ` removed ForgerModulesModule from AppModule (no models/actions)`;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function renameActionImpl(outDir, oldName, newName, project) {
|
|
145
|
+
const oldKebab = (0, utils_1.toKebab)(oldName);
|
|
146
|
+
const newKebab = (0, utils_1.toKebab)(newName);
|
|
147
|
+
const oldPath = (0, node_path_1.resolve)(outDir, oldKebab, "impl", `${oldKebab}.action-impl.ts`);
|
|
148
|
+
const newDir = (0, node_path_1.resolve)(outDir, newKebab, "impl");
|
|
149
|
+
const newPath = (0, node_path_1.resolve)(newDir, `${newKebab}.action-impl.ts`);
|
|
150
|
+
if (!(0, node_fs_1.existsSync)(oldPath))
|
|
151
|
+
return null;
|
|
152
|
+
(0, node_fs_1.mkdirSync)(newDir, { recursive: true });
|
|
153
|
+
const sourceFile = project.addSourceFileAtPath(oldPath);
|
|
154
|
+
const classes = sourceFile.getClasses();
|
|
155
|
+
for (const cls of classes) {
|
|
156
|
+
const oldClassName = `${oldName}ActionImplService`;
|
|
157
|
+
const newClassName = `${newName}ActionImplService`;
|
|
158
|
+
if (cls.getName() === oldClassName) {
|
|
159
|
+
cls.rename(newClassName);
|
|
160
|
+
}
|
|
161
|
+
const extendsDec = cls.getExtends();
|
|
162
|
+
if (extendsDec) {
|
|
163
|
+
const oldExtends = `${oldName}ActionAbstractService`;
|
|
164
|
+
const newExtends = `${newName}ActionAbstractService`;
|
|
165
|
+
if (extendsDec.getText() === oldExtends) {
|
|
166
|
+
extendsDec.replaceWithText(newExtends);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const importDecls = sourceFile.getImportDeclarations();
|
|
171
|
+
for (const imp of importDecls) {
|
|
172
|
+
const moduleSpecifier = imp.getModuleSpecifierValue();
|
|
173
|
+
if (moduleSpecifier.includes(oldKebab)) {
|
|
174
|
+
imp.setModuleSpecifier(moduleSpecifier.replace(oldKebab, newKebab));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
sourceFile.move(newPath);
|
|
178
|
+
sourceFile.saveSync();
|
|
179
|
+
(0, node_fs_1.unlinkSync)(oldPath);
|
|
180
|
+
return ` renamed action impl: ${oldName} → ${newName}`;
|
|
181
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateActionController = generateActionController;
|
|
4
|
+
const utils_1 = require("../../utils");
|
|
5
|
+
function generateActionController(action, options) {
|
|
6
|
+
const kebab = (0, utils_1.toKebab)(action.name);
|
|
7
|
+
const lines = [];
|
|
8
|
+
lines.push(`import { Controller, Post, Body } from "@nestjs/common";`);
|
|
9
|
+
lines.push(`import { ApiTags, ApiOperation } from "@nestjs/swagger";`);
|
|
10
|
+
lines.push(`import { ${action.name}ActionAbstractService } from "./${kebab}.action-service";`);
|
|
11
|
+
lines.push(`import { ${action.name}ActionDto } from "./${kebab}.action-dto";`);
|
|
12
|
+
if (options?.guards && options.guards.length > 0) {
|
|
13
|
+
for (const guard of options.guards) {
|
|
14
|
+
if (guard.import) {
|
|
15
|
+
lines.push(`import { ${guard.name} } from "${guard.import}";`);
|
|
16
|
+
}
|
|
17
|
+
lines.push(`import { UseGuards } from "@nestjs/common";`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
lines.push("");
|
|
21
|
+
const apiTag = options?.routePrefix
|
|
22
|
+
? `"${options.routePrefix}"`
|
|
23
|
+
: '"actions"';
|
|
24
|
+
const controllerRoute = options?.routePrefix || "actions";
|
|
25
|
+
const actionRoute = action.route || kebab;
|
|
26
|
+
const mergedRoute = options?.routePrefix && action.route
|
|
27
|
+
? action.route
|
|
28
|
+
: actionRoute;
|
|
29
|
+
lines.push(`@ApiTags(${apiTag})`);
|
|
30
|
+
if (options?.routePrefix) {
|
|
31
|
+
lines.push(`@Controller("${options.routePrefix}")`);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
lines.push(`@Controller("actions")`);
|
|
35
|
+
}
|
|
36
|
+
if (options?.guards && options.guards.length > 0) {
|
|
37
|
+
const guardNames = options.guards.map((g) => g.name).join(", ");
|
|
38
|
+
lines.push(`@UseGuards(${guardNames})`);
|
|
39
|
+
}
|
|
40
|
+
lines.push(`export class ${action.name}ActionController {`);
|
|
41
|
+
lines.push(` constructor(private readonly action: ${action.name}ActionAbstractService) {}`);
|
|
42
|
+
lines.push("");
|
|
43
|
+
lines.push(` @ApiOperation({ summary: "${action.name}" })`);
|
|
44
|
+
lines.push(` @Post("${mergedRoute}")`);
|
|
45
|
+
lines.push(` execute(@Body() dto: ${action.name}ActionDto) {`);
|
|
46
|
+
lines.push(" return this.action.execute(dto);");
|
|
47
|
+
lines.push(" }");
|
|
48
|
+
lines.push("");
|
|
49
|
+
lines.push("}");
|
|
50
|
+
return lines.join("\n");
|
|
51
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateActionDto = generateActionDto;
|
|
4
|
+
const utils_1 = require("../../utils");
|
|
5
|
+
function generateActionDto(action) {
|
|
6
|
+
const kebab = (0, utils_1.toKebab)(action.name);
|
|
7
|
+
const lines = [];
|
|
8
|
+
lines.push(`export class ${action.name}ActionDto {`);
|
|
9
|
+
for (const input of action.inputs) {
|
|
10
|
+
lines.push(` ${input.name}: ${input.type};`);
|
|
11
|
+
lines.push("");
|
|
12
|
+
}
|
|
13
|
+
lines.push("}");
|
|
14
|
+
return lines.join("\n");
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function generateActionEvent(actionName: string, eventName: string): string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateActionEvent = generateActionEvent;
|
|
4
|
+
function generateActionEvent(actionName, eventName) {
|
|
5
|
+
const lines = [];
|
|
6
|
+
lines.push(`export class ${eventName} {`);
|
|
7
|
+
lines.push(" constructor(public readonly payload: any) {}");
|
|
8
|
+
lines.push("}");
|
|
9
|
+
return lines.join("\n");
|
|
10
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateActionImpl = generateActionImpl;
|
|
4
|
+
const utils_1 = require("../../utils");
|
|
5
|
+
function generateActionImpl(action, options) {
|
|
6
|
+
const kebab = (0, utils_1.toKebab)(action.name);
|
|
7
|
+
const sRel = options?.serviceRelative ?? `./${kebab}.action-service`;
|
|
8
|
+
const dRel = options?.dtoRelative ?? `./${kebab}.action-dto`;
|
|
9
|
+
const lines = [];
|
|
10
|
+
lines.push(`import { Injectable } from "@nestjs/common";`);
|
|
11
|
+
lines.push(`import { ${action.name}ActionAbstractService } from "${sRel}";`);
|
|
12
|
+
lines.push(`import { ${action.name}ActionDto } from "${dRel}";`);
|
|
13
|
+
lines.push("");
|
|
14
|
+
lines.push("@Injectable()");
|
|
15
|
+
lines.push(`export class ${action.name}ActionImplService extends ${action.name}ActionAbstractService {`);
|
|
16
|
+
lines.push("");
|
|
17
|
+
for (const step of action.steps) {
|
|
18
|
+
lines.push(` async ${step}(dto: ${action.name}ActionDto): Promise<void> {`);
|
|
19
|
+
lines.push(` throw new Error("Not implemented");`);
|
|
20
|
+
lines.push(" }");
|
|
21
|
+
lines.push("");
|
|
22
|
+
}
|
|
23
|
+
lines.push("}");
|
|
24
|
+
return lines.join("\n");
|
|
25
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { generateActionDto } from "./dto";
|
|
2
|
+
export { generateActionService } from "./service";
|
|
3
|
+
export { generateActionImpl } from "./impl";
|
|
4
|
+
export { generateActionController } from "./controller";
|
|
5
|
+
export { generateActionModule } from "./module";
|
|
6
|
+
export { generateActionEvent } from "./event";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateActionEvent = exports.generateActionModule = exports.generateActionController = exports.generateActionImpl = exports.generateActionService = exports.generateActionDto = void 0;
|
|
4
|
+
var dto_1 = require("./dto");
|
|
5
|
+
Object.defineProperty(exports, "generateActionDto", { enumerable: true, get: function () { return dto_1.generateActionDto; } });
|
|
6
|
+
var service_1 = require("./service");
|
|
7
|
+
Object.defineProperty(exports, "generateActionService", { enumerable: true, get: function () { return service_1.generateActionService; } });
|
|
8
|
+
var impl_1 = require("./impl");
|
|
9
|
+
Object.defineProperty(exports, "generateActionImpl", { enumerable: true, get: function () { return impl_1.generateActionImpl; } });
|
|
10
|
+
var controller_1 = require("./controller");
|
|
11
|
+
Object.defineProperty(exports, "generateActionController", { enumerable: true, get: function () { return controller_1.generateActionController; } });
|
|
12
|
+
var module_1 = require("./module");
|
|
13
|
+
Object.defineProperty(exports, "generateActionModule", { enumerable: true, get: function () { return module_1.generateActionModule; } });
|
|
14
|
+
var event_1 = require("./event");
|
|
15
|
+
Object.defineProperty(exports, "generateActionEvent", { enumerable: true, get: function () { return event_1.generateActionEvent; } });
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateActionModule = generateActionModule;
|
|
4
|
+
const utils_1 = require("../../utils");
|
|
5
|
+
function generateActionModule(action, options) {
|
|
6
|
+
const kebab = (0, utils_1.toKebab)(action.name);
|
|
7
|
+
const iRel = options?.implRelative ?? `./${kebab}.action-impl`;
|
|
8
|
+
const lines = [];
|
|
9
|
+
lines.push(`import { Module } from "@nestjs/common";`);
|
|
10
|
+
lines.push(`import { ${action.name}ActionAbstractService } from "./${kebab}.action-service";`);
|
|
11
|
+
lines.push(`import { ${action.name}ActionController } from "./${kebab}.action-controller";`);
|
|
12
|
+
lines.push(`import { ${action.name}ActionImplService } from "${iRel}";`);
|
|
13
|
+
lines.push("");
|
|
14
|
+
lines.push(`@Module({`);
|
|
15
|
+
lines.push(` controllers: [${action.name}ActionController],`);
|
|
16
|
+
lines.push(" providers: [");
|
|
17
|
+
lines.push(" {");
|
|
18
|
+
lines.push(` provide: ${action.name}ActionAbstractService,`);
|
|
19
|
+
lines.push(` useClass: ${action.name}ActionImplService,`);
|
|
20
|
+
lines.push(" },");
|
|
21
|
+
lines.push(" ],");
|
|
22
|
+
lines.push("})");
|
|
23
|
+
lines.push(`export class ${action.name}ActionModule {}`);
|
|
24
|
+
return lines.join("\n");
|
|
25
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateActionService = generateActionService;
|
|
4
|
+
const utils_1 = require("../../utils");
|
|
5
|
+
function generateActionService(action) {
|
|
6
|
+
const kebab = (0, utils_1.toKebab)(action.name);
|
|
7
|
+
const lines = [];
|
|
8
|
+
lines.push(`import { ${action.name}ActionDto } from "./${kebab}.action-dto";`);
|
|
9
|
+
lines.push("");
|
|
10
|
+
lines.push(`export abstract class ${action.name}ActionAbstractService {`);
|
|
11
|
+
lines.push("");
|
|
12
|
+
for (const step of action.steps) {
|
|
13
|
+
lines.push(` abstract ${step}(dto: ${action.name}ActionDto): Promise<void>;`);
|
|
14
|
+
lines.push("");
|
|
15
|
+
}
|
|
16
|
+
lines.push(` async execute(dto: ${action.name}ActionDto): Promise<void> {`);
|
|
17
|
+
for (const step of action.steps) {
|
|
18
|
+
lines.push(` await this.${step}(dto);`);
|
|
19
|
+
}
|
|
20
|
+
lines.push(" }");
|
|
21
|
+
lines.push("");
|
|
22
|
+
lines.push("}");
|
|
23
|
+
return lines.join("\n");
|
|
24
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateController = generateController;
|
|
4
|
+
const utils_1 = require("../utils");
|
|
5
|
+
function generateController(model, swagger) {
|
|
6
|
+
const kebab = (0, utils_1.toKebab)(model.name);
|
|
7
|
+
const kebabPlural = `${kebab}s`;
|
|
8
|
+
const lines = [];
|
|
9
|
+
lines.push(`import { Controller, Get, Post, Body, Patch, Param, Delete } from "@nestjs/common";`);
|
|
10
|
+
if (swagger.enabled) {
|
|
11
|
+
lines.push(`import { ApiTags, ApiOperation } from "@nestjs/swagger";`);
|
|
12
|
+
}
|
|
13
|
+
lines.push(`import { ${model.name}AbstractService } from "./${kebab}.service";`);
|
|
14
|
+
lines.push(`import { Create${model.name}Dto } from "./dto/create-${kebab}.dto";`);
|
|
15
|
+
lines.push(`import { Update${model.name}Dto } from "./dto/update-${kebab}.dto";`);
|
|
16
|
+
lines.push("");
|
|
17
|
+
if (swagger.enabled) {
|
|
18
|
+
lines.push(`@ApiTags("${kebabPlural}")`);
|
|
19
|
+
}
|
|
20
|
+
lines.push(`@Controller("${kebabPlural}")`);
|
|
21
|
+
lines.push(`export class ${model.name}Controller {`);
|
|
22
|
+
lines.push(` constructor(private readonly service: ${model.name}AbstractService) {}`);
|
|
23
|
+
lines.push("");
|
|
24
|
+
if (swagger.enabled) {
|
|
25
|
+
lines.push(` @ApiOperation({ summary: "Create a ${kebab}" })`);
|
|
26
|
+
}
|
|
27
|
+
lines.push(" @Post()");
|
|
28
|
+
lines.push(` create(@Body() dto: Create${model.name}Dto) {`);
|
|
29
|
+
lines.push(" return this.service.create(dto);");
|
|
30
|
+
lines.push(" }");
|
|
31
|
+
lines.push("");
|
|
32
|
+
if (swagger.enabled) {
|
|
33
|
+
lines.push(` @ApiOperation({ summary: "Get all ${kebabPlural}" })`);
|
|
34
|
+
}
|
|
35
|
+
lines.push(" @Get()");
|
|
36
|
+
lines.push(" findAll() {");
|
|
37
|
+
lines.push(" return this.service.findAll();");
|
|
38
|
+
lines.push(" }");
|
|
39
|
+
lines.push("");
|
|
40
|
+
if (swagger.enabled) {
|
|
41
|
+
lines.push(` @ApiOperation({ summary: "Get a ${kebab} by id" })`);
|
|
42
|
+
}
|
|
43
|
+
lines.push(' @Get(":id")');
|
|
44
|
+
lines.push(' findOne(@Param("id") id: string) {');
|
|
45
|
+
lines.push(" return this.service.findOne(id);");
|
|
46
|
+
lines.push(" }");
|
|
47
|
+
lines.push("");
|
|
48
|
+
if (swagger.enabled) {
|
|
49
|
+
lines.push(` @ApiOperation({ summary: "Update a ${kebab}" })`);
|
|
50
|
+
}
|
|
51
|
+
lines.push(' @Patch(":id")');
|
|
52
|
+
lines.push(` update(@Param("id") id: string, @Body() dto: Update${model.name}Dto) {`);
|
|
53
|
+
lines.push(" return this.service.update(id, dto);");
|
|
54
|
+
lines.push(" }");
|
|
55
|
+
lines.push("");
|
|
56
|
+
if (swagger.enabled) {
|
|
57
|
+
lines.push(` @ApiOperation({ summary: "Delete a ${kebab}" })`);
|
|
58
|
+
}
|
|
59
|
+
lines.push(' @Delete(":id")');
|
|
60
|
+
lines.push(' remove(@Param("id") id: string) {');
|
|
61
|
+
lines.push(" return this.service.remove(id);");
|
|
62
|
+
lines.push(" }");
|
|
63
|
+
lines.push("");
|
|
64
|
+
lines.push("}");
|
|
65
|
+
return lines.join("\n");
|
|
66
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ForgerModel, ForgerSchema } from "@forgerapi/ast";
|
|
2
|
+
export interface SwaggerConfig {
|
|
3
|
+
enabled: boolean;
|
|
4
|
+
}
|
|
5
|
+
export declare function generateCreateDto(model: ForgerModel, schema: ForgerSchema, swagger: SwaggerConfig, options?: {
|
|
6
|
+
enumBase?: string;
|
|
7
|
+
}): string;
|
|
8
|
+
export declare function generateUpdateDto(model: ForgerModel): string;
|
|
9
|
+
export declare function generateResponseDto(model: ForgerModel): string;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateCreateDto = generateCreateDto;
|
|
4
|
+
exports.generateUpdateDto = generateUpdateDto;
|
|
5
|
+
exports.generateResponseDto = generateResponseDto;
|
|
6
|
+
const utils_1 = require("../utils");
|
|
7
|
+
function generateCreateDto(model, schema, swagger, options) {
|
|
8
|
+
const lines = [];
|
|
9
|
+
const eBase = options?.enumBase ?? "../../common/enums";
|
|
10
|
+
if (swagger.enabled) {
|
|
11
|
+
lines.push(`import { ApiProperty } from "@nestjs/swagger";`);
|
|
12
|
+
}
|
|
13
|
+
const imports = collectEnumImports(model, schema);
|
|
14
|
+
for (const imp of imports) {
|
|
15
|
+
lines.push(`import { ${imp} } from "${eBase}/${(0, utils_1.toKebab)(imp)}.enum";`);
|
|
16
|
+
}
|
|
17
|
+
if (swagger.enabled || imports.length > 0)
|
|
18
|
+
lines.push("");
|
|
19
|
+
lines.push(`export class Create${model.name}Dto {`);
|
|
20
|
+
for (const field of model.fields) {
|
|
21
|
+
if (shouldSkipInDto(field))
|
|
22
|
+
continue;
|
|
23
|
+
const tsType = toDtoTsType(field, schema);
|
|
24
|
+
const optional = isOptionalInDto(field);
|
|
25
|
+
const decorators = renderDtoDecorators(field, swagger);
|
|
26
|
+
for (const dec of decorators) {
|
|
27
|
+
lines.push(` ${dec}`);
|
|
28
|
+
}
|
|
29
|
+
lines.push(` ${field.name}${optional ? "?" : ""}: ${tsType};`);
|
|
30
|
+
lines.push("");
|
|
31
|
+
}
|
|
32
|
+
lines.push("}");
|
|
33
|
+
return lines.join("\n");
|
|
34
|
+
}
|
|
35
|
+
function generateUpdateDto(model) {
|
|
36
|
+
const kebab = (0, utils_1.toKebab)(model.name);
|
|
37
|
+
return `import { PartialType } from "@nestjs/swagger";
|
|
38
|
+
import { Create${model.name}Dto } from "./create-${kebab}.dto";
|
|
39
|
+
|
|
40
|
+
export class Update${model.name}Dto extends PartialType(Create${model.name}Dto) {}
|
|
41
|
+
`;
|
|
42
|
+
}
|
|
43
|
+
function generateResponseDto(model) {
|
|
44
|
+
const lines = [];
|
|
45
|
+
lines.push(`export class ${model.name}ResponseDto {`);
|
|
46
|
+
for (const field of model.fields) {
|
|
47
|
+
if (field.relation && field.relation.isArray)
|
|
48
|
+
continue;
|
|
49
|
+
const tsType = toDtoTsType(field, {
|
|
50
|
+
enums: [],
|
|
51
|
+
models: [],
|
|
52
|
+
actions: [],
|
|
53
|
+
events: [],
|
|
54
|
+
guards: [],
|
|
55
|
+
modules: [],
|
|
56
|
+
});
|
|
57
|
+
lines.push(` ${field.name}: ${tsType};`);
|
|
58
|
+
}
|
|
59
|
+
lines.push("}");
|
|
60
|
+
return lines.join("\n");
|
|
61
|
+
}
|
|
62
|
+
function shouldSkipInDto(field) {
|
|
63
|
+
if (field.constraints.some((c) => c.type === "id"))
|
|
64
|
+
return true;
|
|
65
|
+
if (field.relation && field.relation.isArray)
|
|
66
|
+
return true;
|
|
67
|
+
if (field.relation && field.relation.field)
|
|
68
|
+
return true;
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
function isOptionalInDto(field) {
|
|
72
|
+
return field.constraints.some((c) => c.type === "default");
|
|
73
|
+
}
|
|
74
|
+
function toDtoTsType(field, schema) {
|
|
75
|
+
const isEnum = schema.enums.some((e) => e.name === field.type);
|
|
76
|
+
if (isEnum)
|
|
77
|
+
return field.type;
|
|
78
|
+
switch (field.type) {
|
|
79
|
+
case "string":
|
|
80
|
+
return "string";
|
|
81
|
+
case "number":
|
|
82
|
+
return "number";
|
|
83
|
+
case "boolean":
|
|
84
|
+
return "boolean";
|
|
85
|
+
case "uuid":
|
|
86
|
+
return "string";
|
|
87
|
+
case "datetime":
|
|
88
|
+
return "Date";
|
|
89
|
+
default:
|
|
90
|
+
return "string";
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function renderDtoDecorators(field, swagger) {
|
|
94
|
+
const decorators = [];
|
|
95
|
+
if (swagger.enabled) {
|
|
96
|
+
const swaggerType = toSwaggerType(field);
|
|
97
|
+
decorators.push(`@ApiProperty({ type: ${swaggerType} })`);
|
|
98
|
+
}
|
|
99
|
+
return decorators;
|
|
100
|
+
}
|
|
101
|
+
function toSwaggerType(field) {
|
|
102
|
+
switch (field.type) {
|
|
103
|
+
case "string":
|
|
104
|
+
return "String";
|
|
105
|
+
case "number":
|
|
106
|
+
return "Number";
|
|
107
|
+
case "boolean":
|
|
108
|
+
return "Boolean";
|
|
109
|
+
case "uuid":
|
|
110
|
+
return "String";
|
|
111
|
+
case "datetime":
|
|
112
|
+
return "Date";
|
|
113
|
+
default:
|
|
114
|
+
return "String";
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function collectEnumImports(model, schema) {
|
|
118
|
+
const names = [];
|
|
119
|
+
for (const field of model.fields) {
|
|
120
|
+
if (shouldSkipInDto(field))
|
|
121
|
+
continue;
|
|
122
|
+
const isEnum = schema.enums.some((e) => e.name === field.type);
|
|
123
|
+
if (isEnum && field.type) {
|
|
124
|
+
names.push(field.type);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return names.filter((v, i, a) => a.indexOf(v) === i);
|
|
128
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateEnum = generateEnum;
|
|
4
|
+
function generateEnum(enm) {
|
|
5
|
+
const lines = [];
|
|
6
|
+
lines.push(`export enum ${enm.name} {`);
|
|
7
|
+
for (const value of enm.values) {
|
|
8
|
+
lines.push(` ${value} = "${value}",`);
|
|
9
|
+
}
|
|
10
|
+
lines.push("}");
|
|
11
|
+
return lines.join("\n");
|
|
12
|
+
}
|