@currentjs/gen 0.1.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/CHANGELOG.md +7 -0
- package/LICENSE +56 -0
- package/README.md +686 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +143 -0
- package/dist/commands/commit.d.ts +1 -0
- package/dist/commands/commit.js +153 -0
- package/dist/commands/createApp.d.ts +1 -0
- package/dist/commands/createApp.js +64 -0
- package/dist/commands/createModule.d.ts +1 -0
- package/dist/commands/createModule.js +121 -0
- package/dist/commands/diff.d.ts +1 -0
- package/dist/commands/diff.js +164 -0
- package/dist/commands/generateAll.d.ts +4 -0
- package/dist/commands/generateAll.js +305 -0
- package/dist/commands/infer.d.ts +1 -0
- package/dist/commands/infer.js +179 -0
- package/dist/generators/controllerGenerator.d.ts +20 -0
- package/dist/generators/controllerGenerator.js +280 -0
- package/dist/generators/domainModelGenerator.d.ts +33 -0
- package/dist/generators/domainModelGenerator.js +175 -0
- package/dist/generators/serviceGenerator.d.ts +39 -0
- package/dist/generators/serviceGenerator.js +379 -0
- package/dist/generators/storeGenerator.d.ts +31 -0
- package/dist/generators/storeGenerator.js +191 -0
- package/dist/generators/templateGenerator.d.ts +11 -0
- package/dist/generators/templateGenerator.js +143 -0
- package/dist/generators/templates/appTemplates.d.ts +27 -0
- package/dist/generators/templates/appTemplates.js +1621 -0
- package/dist/generators/templates/controllerTemplates.d.ts +43 -0
- package/dist/generators/templates/controllerTemplates.js +82 -0
- package/dist/generators/templates/index.d.ts +5 -0
- package/dist/generators/templates/index.js +21 -0
- package/dist/generators/templates/serviceTemplates.d.ts +15 -0
- package/dist/generators/templates/serviceTemplates.js +54 -0
- package/dist/generators/templates/storeTemplates.d.ts +9 -0
- package/dist/generators/templates/storeTemplates.js +260 -0
- package/dist/generators/templates/validationTemplates.d.ts +25 -0
- package/dist/generators/templates/validationTemplates.js +66 -0
- package/dist/generators/templates/viewTemplates.d.ts +16 -0
- package/dist/generators/templates/viewTemplates.js +359 -0
- package/dist/generators/validationGenerator.d.ts +24 -0
- package/dist/generators/validationGenerator.js +199 -0
- package/dist/utils/cliUtils.d.ts +6 -0
- package/dist/utils/cliUtils.js +71 -0
- package/dist/utils/colors.d.ts +26 -0
- package/dist/utils/colors.js +80 -0
- package/dist/utils/commitUtils.d.ts +46 -0
- package/dist/utils/commitUtils.js +377 -0
- package/dist/utils/constants.d.ts +52 -0
- package/dist/utils/constants.js +64 -0
- package/dist/utils/generationRegistry.d.ts +25 -0
- package/dist/utils/generationRegistry.js +192 -0
- package/howto.md +556 -0
- package/package.json +44 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ControllerGenerator = void 0;
|
|
37
|
+
const yaml_1 = require("yaml");
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const controllerTemplates_1 = require("./templates/controllerTemplates");
|
|
41
|
+
const generationRegistry_1 = require("../utils/generationRegistry");
|
|
42
|
+
const colors_1 = require("../utils/colors");
|
|
43
|
+
const constants_1 = require("../utils/constants");
|
|
44
|
+
class ControllerGenerator {
|
|
45
|
+
hasPermissions(config) {
|
|
46
|
+
if (config.modules) {
|
|
47
|
+
return Object.values(config.modules).some(module => module.permissions && module.permissions.length > 0);
|
|
48
|
+
}
|
|
49
|
+
const module = config;
|
|
50
|
+
return !!(module.permissions && module.permissions.length > 0);
|
|
51
|
+
}
|
|
52
|
+
getActionPermissions(moduleName, moduleConfig) {
|
|
53
|
+
if (!moduleConfig.permissions || !moduleConfig.actions) {
|
|
54
|
+
return {};
|
|
55
|
+
}
|
|
56
|
+
const actionPermissions = {};
|
|
57
|
+
Object.keys(moduleConfig.actions).forEach(action => {
|
|
58
|
+
actionPermissions[action] = [];
|
|
59
|
+
});
|
|
60
|
+
moduleConfig.permissions.forEach(permission => {
|
|
61
|
+
permission.actions.forEach(action => {
|
|
62
|
+
if (actionPermissions[action]) {
|
|
63
|
+
actionPermissions[action].push(permission.role);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
return actionPermissions;
|
|
68
|
+
}
|
|
69
|
+
shouldGenerateMethod(action, roles) {
|
|
70
|
+
return !roles.includes('none');
|
|
71
|
+
}
|
|
72
|
+
needsUserParam(roles) {
|
|
73
|
+
return roles.length > 0 && !roles.includes('all');
|
|
74
|
+
}
|
|
75
|
+
getHttpMethodName(_httpMethod, action) {
|
|
76
|
+
return action;
|
|
77
|
+
}
|
|
78
|
+
getHttpDecorator(httpMethod) {
|
|
79
|
+
switch ((httpMethod || 'GET').toUpperCase()) {
|
|
80
|
+
case 'GET':
|
|
81
|
+
return 'Get';
|
|
82
|
+
case 'POST':
|
|
83
|
+
return 'Post';
|
|
84
|
+
case 'PUT':
|
|
85
|
+
return 'Put';
|
|
86
|
+
case 'PATCH':
|
|
87
|
+
return 'Patch';
|
|
88
|
+
case 'DELETE':
|
|
89
|
+
return 'Delete';
|
|
90
|
+
default:
|
|
91
|
+
return 'Get';
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
generateMethodImplementation(action, entityName, hasUserParam) {
|
|
95
|
+
const template = controllerTemplates_1.controllerTemplates.methodImplementations[action];
|
|
96
|
+
if (!template) {
|
|
97
|
+
return ` // TODO: Implement ${action} method\n return {} as any;`;
|
|
98
|
+
}
|
|
99
|
+
const userExtraction = hasUserParam ? controllerTemplates_1.controllerTemplates.userExtraction : '';
|
|
100
|
+
const userParam = hasUserParam ? ', user' : '';
|
|
101
|
+
return template
|
|
102
|
+
.replace(/{{ENTITY_NAME}}/g, entityName)
|
|
103
|
+
.replace(/{{ENTITY_LOWER}}/g, entityName.toLowerCase())
|
|
104
|
+
.replace(/{{USER_EXTRACTION}}/g, userExtraction)
|
|
105
|
+
.replace(/{{USER_PARAM}}/g, userParam);
|
|
106
|
+
}
|
|
107
|
+
replaceTemplateVars(template, variables) {
|
|
108
|
+
let result = template;
|
|
109
|
+
Object.entries(variables).forEach(([key, value]) => {
|
|
110
|
+
const regex = new RegExp(`{{${key}}}`, 'g');
|
|
111
|
+
result = result.replace(regex, String(value));
|
|
112
|
+
});
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
generateControllerMethod(endpoint, entityName, roles, hasPermissions, kind) {
|
|
116
|
+
const methodName = kind === 'web' ? this.getWebMethodName(endpoint) : this.getHttpMethodName(endpoint.method, endpoint.action);
|
|
117
|
+
const httpDecorator = kind === 'web' ? 'Get' : this.getHttpDecorator(endpoint.method);
|
|
118
|
+
const needsUser = this.needsUserParam(roles);
|
|
119
|
+
const methodImplementation = this.generateMethodImplementation(endpoint.action, entityName, needsUser);
|
|
120
|
+
const returnType = this.getReturnType(endpoint.action, entityName);
|
|
121
|
+
const renderDecorator = kind === 'web' && endpoint.view
|
|
122
|
+
? `\n @Render("${endpoint.view}"${endpoint.layout ? `, "${endpoint.layout}"` : ', "main_view"'})`
|
|
123
|
+
: '';
|
|
124
|
+
const variables = {
|
|
125
|
+
METHOD_NAME: methodName,
|
|
126
|
+
HTTP_DECORATOR: httpDecorator,
|
|
127
|
+
ENDPOINT_PATH: endpoint.path,
|
|
128
|
+
METHOD_IMPLEMENTATION: methodImplementation,
|
|
129
|
+
RETURN_TYPE: returnType,
|
|
130
|
+
RENDER_DECORATOR: renderDecorator
|
|
131
|
+
};
|
|
132
|
+
return this.replaceTemplateVars(controllerTemplates_1.controllerTemplates.controllerMethod, variables);
|
|
133
|
+
}
|
|
134
|
+
getWebMethodName(endpoint) {
|
|
135
|
+
const base = this.getHttpMethodName(endpoint.method, endpoint.action);
|
|
136
|
+
const suffix = this.getPathSuffix(endpoint.path);
|
|
137
|
+
return `${base}${suffix}`;
|
|
138
|
+
}
|
|
139
|
+
getPathSuffix(routePath) {
|
|
140
|
+
if (!routePath || routePath === '/')
|
|
141
|
+
return 'Index';
|
|
142
|
+
const segments = routePath.split('/').filter(Boolean);
|
|
143
|
+
const parts = segments.map(seg => {
|
|
144
|
+
if (seg.startsWith(':')) {
|
|
145
|
+
const name = seg.slice(1);
|
|
146
|
+
return 'By' + name.charAt(0).toUpperCase() + name.slice(1);
|
|
147
|
+
}
|
|
148
|
+
const cleaned = seg.replace(/[^a-zA-Z0-9]+/g, ' ')
|
|
149
|
+
.split(' ')
|
|
150
|
+
.filter(Boolean)
|
|
151
|
+
.map(s => s.charAt(0).toUpperCase() + s.slice(1))
|
|
152
|
+
.join('');
|
|
153
|
+
return cleaned || 'Index';
|
|
154
|
+
});
|
|
155
|
+
return parts.join('');
|
|
156
|
+
}
|
|
157
|
+
getReturnType(action, entityName) {
|
|
158
|
+
switch (action) {
|
|
159
|
+
case 'list':
|
|
160
|
+
return `${entityName}[]`;
|
|
161
|
+
case 'get':
|
|
162
|
+
case 'create':
|
|
163
|
+
case 'update':
|
|
164
|
+
case 'empty':
|
|
165
|
+
return entityName;
|
|
166
|
+
case 'delete':
|
|
167
|
+
return '{ success: boolean; message: string }';
|
|
168
|
+
default:
|
|
169
|
+
return 'any';
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
generateController(moduleName, moduleConfig, hasGlobalPermissions, kind) {
|
|
173
|
+
if (!moduleConfig.models || moduleConfig.models.length === 0) {
|
|
174
|
+
return '';
|
|
175
|
+
}
|
|
176
|
+
const isApi = kind === 'api';
|
|
177
|
+
const cfgRaw = isApi ? moduleConfig.api : moduleConfig.routes;
|
|
178
|
+
let cfg = cfgRaw;
|
|
179
|
+
if (!isApi) {
|
|
180
|
+
// Ensure sensible defaults for Web routes: list, detail, create (empty), edit (get)
|
|
181
|
+
const entityName = moduleConfig.models[0].name;
|
|
182
|
+
const entityLower = entityName.toLowerCase();
|
|
183
|
+
if (!cfgRaw || !cfgRaw.endpoints || cfgRaw.endpoints.length === 0) {
|
|
184
|
+
cfg = {
|
|
185
|
+
prefix: `/${entityLower}`,
|
|
186
|
+
endpoints: [
|
|
187
|
+
{ path: '/', action: 'list', method: 'GET', view: `${entityLower}List` },
|
|
188
|
+
{ path: '/:id', action: 'get', method: 'GET', view: `${entityLower}Detail` },
|
|
189
|
+
{ path: '/create', action: 'empty', method: 'GET', view: `${entityLower}Create` },
|
|
190
|
+
{ path: '/:id/edit', action: 'get', method: 'GET', view: `${entityLower}Update` }
|
|
191
|
+
]
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
// Force GET for all web endpoints; forms should submit to API using custom form handling
|
|
196
|
+
cfg = {
|
|
197
|
+
prefix: cfgRaw.prefix || `/${entityLower}`,
|
|
198
|
+
endpoints: (cfgRaw.endpoints || []).map(e => ({ ...e, method: 'GET' }))
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (!cfg)
|
|
203
|
+
return '';
|
|
204
|
+
const entityName = moduleConfig.models[0].name;
|
|
205
|
+
const entityLower = entityName.toLowerCase();
|
|
206
|
+
const controllerBase = (cfg.prefix || `/${isApi ? 'api/' : ''}${entityLower}`).replace(/\/$/, '');
|
|
207
|
+
const actionPermissions = this.getActionPermissions(moduleName, moduleConfig);
|
|
208
|
+
const hasPermissions = hasGlobalPermissions && !!(moduleConfig.permissions && moduleConfig.permissions.length > 0);
|
|
209
|
+
const controllerMethods = (cfg.endpoints || [])
|
|
210
|
+
.filter(endpoint => {
|
|
211
|
+
const roles = actionPermissions[endpoint.action] || [];
|
|
212
|
+
return this.shouldGenerateMethod(endpoint.action, roles);
|
|
213
|
+
})
|
|
214
|
+
.map(endpoint => {
|
|
215
|
+
const roles = actionPermissions[endpoint.action] || [];
|
|
216
|
+
return this.generateControllerMethod(endpoint, entityName, roles, hasPermissions, kind);
|
|
217
|
+
})
|
|
218
|
+
.join('\n\n');
|
|
219
|
+
const controllerClass = this.replaceTemplateVars(controllerTemplates_1.controllerTemplates.controllerClass, {
|
|
220
|
+
CONTROLLER_NAME: `${entityName}${isApi ? 'ApiController' : 'WebController'}`,
|
|
221
|
+
ENTITY_NAME: entityName,
|
|
222
|
+
ENTITY_LOWER: entityLower,
|
|
223
|
+
CONTROLLER_BASE: controllerBase,
|
|
224
|
+
CONTROLLER_METHODS: controllerMethods
|
|
225
|
+
});
|
|
226
|
+
return this.replaceTemplateVars(controllerTemplates_1.controllerFileTemplate, {
|
|
227
|
+
ENTITY_NAME: entityName,
|
|
228
|
+
JWT_IMPORT: '',
|
|
229
|
+
CONTROLLER_CLASS: controllerClass
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
generateFromYamlFile(yamlFilePath) {
|
|
233
|
+
const yamlContent = fs.readFileSync(yamlFilePath, 'utf8');
|
|
234
|
+
const config = (0, yaml_1.parse)(yamlContent);
|
|
235
|
+
const result = {};
|
|
236
|
+
const hasGlobalPermissions = this.hasPermissions(config);
|
|
237
|
+
if (config.modules) {
|
|
238
|
+
Object.entries(config.modules).forEach(([moduleName, moduleConfig]) => {
|
|
239
|
+
const entityName = moduleConfig.models && moduleConfig.models[0] ? moduleConfig.models[0].name : 'Module';
|
|
240
|
+
const apiControllerCode = this.generateController(moduleName, moduleConfig, hasGlobalPermissions, 'api');
|
|
241
|
+
if (apiControllerCode)
|
|
242
|
+
result[`${entityName}Api`] = apiControllerCode;
|
|
243
|
+
const webControllerCode = this.generateController(moduleName, moduleConfig, hasGlobalPermissions, 'web');
|
|
244
|
+
if (webControllerCode)
|
|
245
|
+
result[`${entityName}Web`] = webControllerCode;
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
const moduleConfig = config;
|
|
250
|
+
const moduleName = moduleConfig.models && moduleConfig.models[0] ? moduleConfig.models[0].name : 'Module';
|
|
251
|
+
const apiControllerCode = this.generateController(moduleName, moduleConfig, hasGlobalPermissions, 'api');
|
|
252
|
+
if (apiControllerCode)
|
|
253
|
+
result[`${moduleName}Api`] = apiControllerCode;
|
|
254
|
+
const webControllerCode = this.generateController(moduleName, moduleConfig, hasGlobalPermissions, 'web');
|
|
255
|
+
if (webControllerCode)
|
|
256
|
+
result[`${moduleName}Web`] = webControllerCode;
|
|
257
|
+
}
|
|
258
|
+
return result;
|
|
259
|
+
}
|
|
260
|
+
async generateAndSaveFiles(yamlFilePath = constants_1.COMMON_FILES.APP_YAML, outputDir = 'infrastructure', opts) {
|
|
261
|
+
const yamlContent = fs.readFileSync(yamlFilePath, 'utf8');
|
|
262
|
+
const config = (0, yaml_1.parse)(yamlContent);
|
|
263
|
+
const hasGlobalPermissions = this.hasPermissions(config);
|
|
264
|
+
const controllers = this.generateFromYamlFile(yamlFilePath);
|
|
265
|
+
const generatedControllerPaths = [];
|
|
266
|
+
const controllersDir = path.join(outputDir, 'controllers');
|
|
267
|
+
fs.mkdirSync(controllersDir, { recursive: true });
|
|
268
|
+
for (const [moduleName, controllerCode] of Object.entries(controllers)) {
|
|
269
|
+
const fileName = `${moduleName}Controller.ts`;
|
|
270
|
+
const filePath = path.join(controllersDir, fileName);
|
|
271
|
+
// eslint-disable-next-line no-await-in-loop
|
|
272
|
+
await (0, generationRegistry_1.writeGeneratedFile)(filePath, controllerCode, { force: !!(opts === null || opts === void 0 ? void 0 : opts.force), skipOnConflict: !!(opts === null || opts === void 0 ? void 0 : opts.skipOnConflict) });
|
|
273
|
+
generatedControllerPaths.push(filePath);
|
|
274
|
+
}
|
|
275
|
+
// eslint-disable-next-line no-console
|
|
276
|
+
console.log('\n' + colors_1.colors.green('Controller files generated successfully!') + '\n');
|
|
277
|
+
return generatedControllerPaths;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
exports.ControllerGenerator = ControllerGenerator;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
interface FieldConfig {
|
|
2
|
+
name: string;
|
|
3
|
+
type: string;
|
|
4
|
+
required?: boolean;
|
|
5
|
+
unique?: boolean;
|
|
6
|
+
auto?: boolean;
|
|
7
|
+
}
|
|
8
|
+
interface ModelConfig {
|
|
9
|
+
name: string;
|
|
10
|
+
fields: FieldConfig[];
|
|
11
|
+
}
|
|
12
|
+
type ModuleConfig = {
|
|
13
|
+
models: ModelConfig[];
|
|
14
|
+
};
|
|
15
|
+
type AppConfig = {
|
|
16
|
+
modules: Record<string, ModuleConfig>;
|
|
17
|
+
} | ModuleConfig;
|
|
18
|
+
export declare class DomainModelGenerator {
|
|
19
|
+
private typeMapping;
|
|
20
|
+
private getDefaultValue;
|
|
21
|
+
private mapType;
|
|
22
|
+
private generateConstructorParameter;
|
|
23
|
+
private generateSetterMethods;
|
|
24
|
+
generateModel(modelConfig: ModelConfig): string;
|
|
25
|
+
generateModels(models: ModelConfig[]): string;
|
|
26
|
+
generateFromYamlFile(yamlFilePath: string): Record<string, string>;
|
|
27
|
+
generateFromConfig(config: AppConfig): Record<string, string>;
|
|
28
|
+
generateAndSaveFiles(yamlFilePath: string, outputDir: string, opts?: {
|
|
29
|
+
force?: boolean;
|
|
30
|
+
skipOnConflict?: boolean;
|
|
31
|
+
}): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.DomainModelGenerator = void 0;
|
|
37
|
+
const yaml_1 = require("yaml");
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const generationRegistry_1 = require("../utils/generationRegistry");
|
|
41
|
+
const colors_1 = require("../utils/colors");
|
|
42
|
+
class DomainModelGenerator {
|
|
43
|
+
constructor() {
|
|
44
|
+
this.typeMapping = {
|
|
45
|
+
string: 'string',
|
|
46
|
+
number: 'number',
|
|
47
|
+
boolean: 'boolean',
|
|
48
|
+
datetime: 'Date',
|
|
49
|
+
json: 'any',
|
|
50
|
+
array: 'any[]',
|
|
51
|
+
object: 'object'
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
getDefaultValue(type) {
|
|
55
|
+
switch (type) {
|
|
56
|
+
case 'datetime':
|
|
57
|
+
return 'new Date()';
|
|
58
|
+
case 'string':
|
|
59
|
+
return "''";
|
|
60
|
+
case 'number':
|
|
61
|
+
return '0';
|
|
62
|
+
case 'boolean':
|
|
63
|
+
return 'false';
|
|
64
|
+
case 'array':
|
|
65
|
+
return '[]';
|
|
66
|
+
case 'object':
|
|
67
|
+
case 'json':
|
|
68
|
+
return '{}';
|
|
69
|
+
default:
|
|
70
|
+
return 'undefined';
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
mapType(yamlType) {
|
|
74
|
+
return this.typeMapping[yamlType] || 'any';
|
|
75
|
+
}
|
|
76
|
+
generateConstructorParameter(field) {
|
|
77
|
+
const tsType = this.mapType(field.type);
|
|
78
|
+
const isOptional = !field.required && !field.auto;
|
|
79
|
+
const hasDefault = field.auto;
|
|
80
|
+
let param = `public ${field.name}`;
|
|
81
|
+
if (isOptional && !hasDefault) {
|
|
82
|
+
param += '?';
|
|
83
|
+
}
|
|
84
|
+
param += `: ${tsType}`;
|
|
85
|
+
if (hasDefault) {
|
|
86
|
+
param += ` = ${this.getDefaultValue(field.type)}`;
|
|
87
|
+
}
|
|
88
|
+
return param;
|
|
89
|
+
}
|
|
90
|
+
generateSetterMethods(modelConfig) {
|
|
91
|
+
const setterMethods = [];
|
|
92
|
+
modelConfig.fields.forEach(field => {
|
|
93
|
+
if (!field.auto && field.name !== 'id') {
|
|
94
|
+
const tsType = this.mapType(field.type);
|
|
95
|
+
const methodName = `set${field.name.charAt(0).toUpperCase() + field.name.slice(1)}`;
|
|
96
|
+
const setter = `
|
|
97
|
+
${methodName}(${field.name}: ${tsType}): void {
|
|
98
|
+
this.${field.name} = ${field.name};
|
|
99
|
+
}`;
|
|
100
|
+
setterMethods.push(setter);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
return setterMethods.join('\n');
|
|
104
|
+
}
|
|
105
|
+
generateModel(modelConfig) {
|
|
106
|
+
const className = modelConfig.name;
|
|
107
|
+
// Always add id field first
|
|
108
|
+
const constructorParams = ['public id: number'];
|
|
109
|
+
// Process other fields
|
|
110
|
+
modelConfig.fields.forEach(field => {
|
|
111
|
+
constructorParams.push(this.generateConstructorParameter(field));
|
|
112
|
+
});
|
|
113
|
+
const constructorParamsStr = constructorParams.join(',\n ');
|
|
114
|
+
const setterMethods = this.generateSetterMethods(modelConfig);
|
|
115
|
+
return `export class ${className} {
|
|
116
|
+
public constructor(
|
|
117
|
+
${constructorParamsStr}
|
|
118
|
+
) { }
|
|
119
|
+
${setterMethods}
|
|
120
|
+
}`;
|
|
121
|
+
}
|
|
122
|
+
generateModels(models) {
|
|
123
|
+
return models.map(model => this.generateModel(model)).join('\n\n');
|
|
124
|
+
}
|
|
125
|
+
generateFromYamlFile(yamlFilePath) {
|
|
126
|
+
const yamlContent = fs.readFileSync(yamlFilePath, 'utf8');
|
|
127
|
+
const config = (0, yaml_1.parse)(yamlContent);
|
|
128
|
+
const result = {};
|
|
129
|
+
if (config.modules) {
|
|
130
|
+
const app = config;
|
|
131
|
+
Object.values(app.modules).forEach(moduleConfig => {
|
|
132
|
+
if (moduleConfig.models && moduleConfig.models.length > 0) {
|
|
133
|
+
moduleConfig.models.forEach(m => {
|
|
134
|
+
result[m.name] = this.generateModel(m);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
else if (config.models) {
|
|
140
|
+
const module = config;
|
|
141
|
+
module.models.forEach(m => {
|
|
142
|
+
result[m.name] = this.generateModel(m);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
generateFromConfig(config) {
|
|
148
|
+
const result = {};
|
|
149
|
+
if (config.modules) {
|
|
150
|
+
Object.values(config.modules).forEach(moduleConfig => {
|
|
151
|
+
if (moduleConfig.models && moduleConfig.models.length > 0) {
|
|
152
|
+
moduleConfig.models.forEach(m => {
|
|
153
|
+
result[m.name] = this.generateModel(m);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
else if (config.models) {
|
|
159
|
+
config.models.forEach(m => {
|
|
160
|
+
result[m.name] = this.generateModel(m);
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
return result;
|
|
164
|
+
}
|
|
165
|
+
async generateAndSaveFiles(yamlFilePath, outputDir, opts) {
|
|
166
|
+
const codeByEntity = this.generateFromYamlFile(yamlFilePath);
|
|
167
|
+
await Promise.all(Object.entries(codeByEntity).map(([entity, code]) => {
|
|
168
|
+
const filePath = path.join(outputDir, `${entity}.ts`);
|
|
169
|
+
return (0, generationRegistry_1.writeGeneratedFile)(filePath, code, { force: !!(opts === null || opts === void 0 ? void 0 : opts.force), skipOnConflict: !!(opts === null || opts === void 0 ? void 0 : opts.skipOnConflict) });
|
|
170
|
+
}));
|
|
171
|
+
// eslint-disable-next-line no-console
|
|
172
|
+
console.log('\n' + colors_1.colors.green('Domain model files generated successfully!') + '\n');
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
exports.DomainModelGenerator = DomainModelGenerator;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
interface ActionConfig {
|
|
2
|
+
handlers: string[];
|
|
3
|
+
}
|
|
4
|
+
interface PermissionConfig {
|
|
5
|
+
role: string;
|
|
6
|
+
actions: string[];
|
|
7
|
+
}
|
|
8
|
+
interface ModelConfig {
|
|
9
|
+
name: string;
|
|
10
|
+
fields: any[];
|
|
11
|
+
}
|
|
12
|
+
type ModuleConfig = {
|
|
13
|
+
models?: ModelConfig[];
|
|
14
|
+
actions?: Record<string, ActionConfig>;
|
|
15
|
+
permissions?: PermissionConfig[];
|
|
16
|
+
};
|
|
17
|
+
export declare class ServiceGenerator {
|
|
18
|
+
private hasPermissions;
|
|
19
|
+
private getActionPermissions;
|
|
20
|
+
private generatePermissionCheck;
|
|
21
|
+
private getResourceIdForAction;
|
|
22
|
+
private generateMethodParams;
|
|
23
|
+
private generateReturnType;
|
|
24
|
+
private generateMethodImplementation;
|
|
25
|
+
private extractFunctionName;
|
|
26
|
+
private getMethodCallParams;
|
|
27
|
+
private generateConstructorArgs;
|
|
28
|
+
private generateUpdateSetterCalls;
|
|
29
|
+
private replaceTemplateVars;
|
|
30
|
+
private generateServiceMethod;
|
|
31
|
+
generateService(moduleName: string, moduleConfig: ModuleConfig, hasGlobalPermissions: boolean): string;
|
|
32
|
+
private generateCustomImports;
|
|
33
|
+
generateFromYamlFile(yamlFilePath: string): Record<string, string>;
|
|
34
|
+
generateAndSaveFiles(yamlFilePath?: string, outputDir?: string, opts?: {
|
|
35
|
+
force?: boolean;
|
|
36
|
+
skipOnConflict?: boolean;
|
|
37
|
+
}): Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
export {};
|