@currentjs/gen 0.5.0 → 0.5.2

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.
Files changed (70) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +374 -996
  3. package/dist/cli.js +28 -10
  4. package/dist/commands/createModel.d.ts +1 -0
  5. package/dist/commands/createModel.js +764 -0
  6. package/dist/commands/createModule.js +13 -0
  7. package/dist/commands/generateAll.d.ts +1 -0
  8. package/dist/commands/generateAll.js +1 -1
  9. package/dist/commands/init.d.ts +1 -0
  10. package/dist/commands/{createApp.js → init.js} +2 -2
  11. package/dist/commands/migrateCommit.js +33 -68
  12. package/dist/generators/controllerGenerator.d.ts +7 -0
  13. package/dist/generators/controllerGenerator.js +56 -17
  14. package/dist/generators/domainLayerGenerator.js +51 -8
  15. package/dist/generators/dtoGenerator.js +13 -8
  16. package/dist/generators/serviceGenerator.d.ts +6 -0
  17. package/dist/generators/serviceGenerator.js +219 -23
  18. package/dist/generators/storeGenerator.d.ts +4 -0
  19. package/dist/generators/storeGenerator.js +116 -9
  20. package/dist/generators/templateGenerator.d.ts +1 -0
  21. package/dist/generators/templateGenerator.js +8 -2
  22. package/dist/generators/templates/appTemplates.js +1 -1
  23. package/dist/generators/templates/data/cursorRulesTemplate +11 -755
  24. package/dist/generators/templates/data/frontendScriptTemplate +11 -4
  25. package/dist/generators/templates/data/mainViewTemplate +1 -0
  26. package/dist/generators/templates/storeTemplates.d.ts +1 -1
  27. package/dist/generators/templates/storeTemplates.js +3 -26
  28. package/dist/generators/useCaseGenerator.js +6 -3
  29. package/dist/types/configTypes.d.ts +6 -0
  30. package/dist/utils/migrationUtils.d.ts +9 -19
  31. package/dist/utils/migrationUtils.js +80 -110
  32. package/dist/utils/promptUtils.d.ts +37 -0
  33. package/dist/utils/promptUtils.js +149 -0
  34. package/dist/utils/typeUtils.d.ts +4 -0
  35. package/dist/utils/typeUtils.js +7 -0
  36. package/package.json +1 -1
  37. package/dist/commands/createApp.d.ts +0 -1
  38. package/dist/commands/migratePush.d.ts +0 -1
  39. package/dist/commands/migratePush.js +0 -135
  40. package/dist/commands/migrateUpdate.d.ts +0 -1
  41. package/dist/commands/migrateUpdate.js +0 -147
  42. package/dist/commands/newGenerateAll.d.ts +0 -4
  43. package/dist/commands/newGenerateAll.js +0 -336
  44. package/dist/generators/domainModelGenerator.d.ts +0 -41
  45. package/dist/generators/domainModelGenerator.js +0 -242
  46. package/dist/generators/newControllerGenerator.d.ts +0 -55
  47. package/dist/generators/newControllerGenerator.js +0 -644
  48. package/dist/generators/newServiceGenerator.d.ts +0 -19
  49. package/dist/generators/newServiceGenerator.js +0 -266
  50. package/dist/generators/newStoreGenerator.d.ts +0 -39
  51. package/dist/generators/newStoreGenerator.js +0 -408
  52. package/dist/generators/newTemplateGenerator.d.ts +0 -29
  53. package/dist/generators/newTemplateGenerator.js +0 -510
  54. package/dist/generators/storeGeneratorV2.d.ts +0 -31
  55. package/dist/generators/storeGeneratorV2.js +0 -190
  56. package/dist/generators/templates/controllerTemplates.d.ts +0 -43
  57. package/dist/generators/templates/controllerTemplates.js +0 -82
  58. package/dist/generators/templates/newStoreTemplates.d.ts +0 -5
  59. package/dist/generators/templates/newStoreTemplates.js +0 -141
  60. package/dist/generators/templates/serviceTemplates.d.ts +0 -16
  61. package/dist/generators/templates/serviceTemplates.js +0 -59
  62. package/dist/generators/templates/validationTemplates.d.ts +0 -25
  63. package/dist/generators/templates/validationTemplates.js +0 -66
  64. package/dist/generators/templates/viewTemplates.d.ts +0 -25
  65. package/dist/generators/templates/viewTemplates.js +0 -491
  66. package/dist/generators/validationGenerator.d.ts +0 -29
  67. package/dist/generators/validationGenerator.js +0 -250
  68. package/dist/utils/new_parts_of_migrationUtils.d.ts +0 -0
  69. package/dist/utils/new_parts_of_migrationUtils.js +0 -164
  70. package/howto.md +0 -667
@@ -1,336 +0,0 @@
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.handleNewGenerateAll = handleNewGenerateAll;
37
- const fs = __importStar(require("fs"));
38
- const path = __importStar(require("path"));
39
- const cliUtils_1 = require("../utils/cliUtils");
40
- const yaml_1 = require("yaml");
41
- const domainLayerGenerator_1 = require("../generators/domainLayerGenerator");
42
- const dtoGenerator_1 = require("../generators/dtoGenerator");
43
- const useCaseGenerator_1 = require("../generators/useCaseGenerator");
44
- const newServiceGenerator_1 = require("../generators/newServiceGenerator");
45
- const newControllerGenerator_1 = require("../generators/newControllerGenerator");
46
- const newTemplateGenerator_1 = require("../generators/newTemplateGenerator");
47
- const newStoreGenerator_1 = require("../generators/newStoreGenerator");
48
- const generationRegistry_1 = require("../utils/generationRegistry");
49
- const colors_1 = require("../utils/colors");
50
- const constants_1 = require("../utils/constants");
51
- const configTypes_1 = require("../types/configTypes");
52
- const childEntityUtils_1 = require("../utils/childEntityUtils");
53
- async function handleNewGenerateAll(yamlPathArg, _outArg, moduleName, opts) {
54
- var _a, _b;
55
- const appYamlPath = (0, cliUtils_1.resolveYamlPath)(yamlPathArg);
56
- (0, generationRegistry_1.initGenerationRegistry)(process.cwd());
57
- const raw = fs.readFileSync(appYamlPath, 'utf8');
58
- const appConfig = (0, yaml_1.parse)(raw);
59
- const modulesList = ((_a = appConfig === null || appConfig === void 0 ? void 0 : appConfig.modules) !== null && _a !== void 0 ? _a : []).map(m => (typeof m === 'string' ? m : m.module));
60
- const providersConfig = appConfig === null || appConfig === void 0 ? void 0 : appConfig.providers;
61
- const databaseProviderName = appConfig === null || appConfig === void 0 ? void 0 : appConfig.database;
62
- const shouldIncludeModule = (moduleYamlRel) => {
63
- if (!moduleName || moduleName === '*')
64
- return true;
65
- const moduleNameLc = moduleName.toLowerCase();
66
- const relNormalized = moduleYamlRel.replace(/\\/g, '/').toLowerCase();
67
- if (relNormalized.endsWith(`/${moduleNameLc}.yaml`))
68
- return true;
69
- const moduleYamlPath = path.isAbsolute(moduleYamlRel)
70
- ? moduleYamlRel
71
- : path.resolve(process.cwd(), moduleYamlRel);
72
- const dirName = path.basename(path.dirname(moduleYamlPath)).toLowerCase();
73
- if (dirName === moduleNameLc)
74
- return true;
75
- if (relNormalized.includes(`/${moduleNameLc}/`) || relNormalized.endsWith(`/${moduleNameLc}`))
76
- return true;
77
- return false;
78
- };
79
- const filteredModules = modulesList.filter(shouldIncludeModule);
80
- if (filteredModules.length === 0) {
81
- // eslint-disable-next-line no-console
82
- console.warn(colors_1.colors.yellow(`No modules matched: ${moduleName}`));
83
- return;
84
- }
85
- // Initialize generators
86
- const domainGen = new domainLayerGenerator_1.DomainLayerGenerator();
87
- const dtoGen = new dtoGenerator_1.DtoGenerator();
88
- const useCaseGen = new useCaseGenerator_1.UseCaseGenerator();
89
- const serviceGen = new newServiceGenerator_1.NewServiceGenerator();
90
- const controllerGen = new newControllerGenerator_1.NewControllerGenerator();
91
- const templateGen = new newTemplateGenerator_1.NewTemplateGenerator();
92
- const storeGen = new newStoreGenerator_1.NewStoreGenerator();
93
- const initsBySrcDir = new Map();
94
- // Process each module
95
- for (const moduleYamlRel of filteredModules) {
96
- const moduleYamlPath = path.isAbsolute(moduleYamlRel)
97
- ? moduleYamlRel
98
- : path.resolve(process.cwd(), moduleYamlRel);
99
- if (!fs.existsSync(moduleYamlPath)) {
100
- // eslint-disable-next-line no-console
101
- console.warn(colors_1.colors.yellow(`Module YAML not found: ${moduleYamlPath}`));
102
- continue;
103
- }
104
- // Check if this is a new format config
105
- const moduleYamlContent = fs.readFileSync(moduleYamlPath, 'utf8');
106
- const moduleConfig = (0, yaml_1.parse)(moduleYamlContent);
107
- if (!(0, configTypes_1.isNewModuleConfig)(moduleConfig)) {
108
- // eslint-disable-next-line no-console
109
- console.warn(colors_1.colors.yellow(`Skipping ${moduleYamlPath}: not in new format (missing domain/useCases)`));
110
- continue;
111
- }
112
- const moduleDir = path.dirname(moduleYamlPath);
113
- // eslint-disable-next-line no-console
114
- console.log(colors_1.colors.blue(`\nGenerating module: ${path.basename(moduleDir)}`));
115
- // 1. Generate domain layer (entities + value objects)
116
- // eslint-disable-next-line no-await-in-loop
117
- await domainGen.generateAndSaveFiles(moduleYamlPath, moduleDir, opts);
118
- // 2. Generate DTOs
119
- // eslint-disable-next-line no-await-in-loop
120
- await dtoGen.generateAndSaveFiles(moduleYamlPath, moduleDir, opts);
121
- // 3. Generate Use Cases
122
- // eslint-disable-next-line no-await-in-loop
123
- await useCaseGen.generateAndSaveFiles(moduleYamlPath, moduleDir, opts);
124
- // 4. Generate Services
125
- // eslint-disable-next-line no-await-in-loop
126
- await serviceGen.generateAndSaveFiles(moduleYamlPath, moduleDir, opts);
127
- // 5. Generate Stores
128
- // eslint-disable-next-line no-await-in-loop
129
- await storeGen.generateAndSaveFiles(moduleYamlPath, moduleDir, opts);
130
- // 6. Generate Controllers
131
- // eslint-disable-next-line no-await-in-loop
132
- const controllerPaths = await controllerGen.generateAndSaveFiles(moduleYamlPath, moduleDir, opts);
133
- // 7. Generate Templates
134
- // eslint-disable-next-line no-await-in-loop
135
- await templateGen.generateAndSaveFiles(moduleYamlPath, moduleDir, opts);
136
- // Collect wiring information for app.ts
137
- let probeDir = moduleDir;
138
- let srcDir = null;
139
- for (let i = 0; i < 6; i += 1) {
140
- const candidate = path.join(probeDir, 'src', constants_1.COMMON_FILES.APP_TS);
141
- if (fs.existsSync(candidate)) {
142
- srcDir = path.join(probeDir, 'src');
143
- break;
144
- }
145
- const parent = path.dirname(probeDir);
146
- if (parent === probeDir)
147
- break;
148
- probeDir = parent;
149
- }
150
- if (!srcDir)
151
- continue;
152
- // Build wiring for each model in the module
153
- const list = (_b = initsBySrcDir.get(srcDir)) !== null && _b !== void 0 ? _b : [];
154
- Object.keys(moduleConfig.useCases).forEach(modelName => {
155
- const entityVar = modelName.charAt(0).toLowerCase() + modelName.slice(1);
156
- const moduleFolderName = path.basename(moduleDir);
157
- const init = {
158
- entityName: modelName,
159
- entityVar,
160
- importStore: `import { ${modelName}Store } from './modules/${moduleFolderName}/infrastructure/stores/${modelName}Store';`,
161
- importService: `import { ${modelName}Service } from './modules/${moduleFolderName}/application/services/${modelName}Service';`,
162
- importUseCase: `import { ${modelName}UseCase } from './modules/${moduleFolderName}/application/useCases/${modelName}UseCase';`,
163
- importController: '',
164
- wiring: [],
165
- registration: ''
166
- };
167
- // Check if this root entity's web controller needs child services (withChild: true)
168
- const childEntityMap = (0, childEntityUtils_1.buildChildEntityMap)(moduleConfig);
169
- const isRootEntity = !childEntityMap.has(modelName);
170
- const withChildChildren = isRootEntity ? (0, childEntityUtils_1.getChildrenOfParent)(moduleConfig, modelName) : [];
171
- const webUseCases = moduleConfig.useCases[modelName];
172
- const needsChildServices = withChildChildren.length > 0 && webUseCases && Object.entries(webUseCases).some(([action, uc]) => action === 'get' && uc.withChild === true);
173
- // Add controller imports if they exist
174
- controllerPaths.forEach(ctrlPath => {
175
- const ctrlName = path.basename(ctrlPath, '.ts');
176
- const ctrlModelName = ctrlName.replace(/(Api|Web)Controller$/, '');
177
- if (ctrlModelName === modelName) {
178
- const rel = path.relative(srcDir, ctrlPath).replace(/\\/g, '/').replace(/\.ts$/, '');
179
- const importPath = rel.startsWith('.') ? rel : `./${rel}`;
180
- init.importController += `import { ${ctrlName} } from '${importPath}';\n`;
181
- // Web controllers may need child services when withChild is true
182
- const isWebCtrl = ctrlName.endsWith('WebController');
183
- if (isWebCtrl && needsChildServices) {
184
- const childServiceArgs = withChildChildren
185
- .map(c => c.childEntityName.charAt(0).toLowerCase() + c.childEntityName.slice(1) + 'Service')
186
- .join(', ');
187
- init.registration += `new ${ctrlName}(${entityVar}UseCase, ${childServiceArgs}),\n `;
188
- }
189
- else {
190
- init.registration += `new ${ctrlName}(${entityVar}UseCase),\n `;
191
- }
192
- }
193
- });
194
- list.push(init);
195
- });
196
- initsBySrcDir.set(srcDir, list);
197
- }
198
- // Update app.ts files with wiring
199
- for (const [srcDir, controllerInits] of initsBySrcDir.entries()) {
200
- try {
201
- const appTsPath = path.join(srcDir, constants_1.COMMON_FILES.APP_TS);
202
- if (!fs.existsSync(appTsPath))
203
- continue;
204
- let appTs = fs.readFileSync(appTsPath, 'utf8');
205
- // Build providers import and initialization from app.yaml providers section
206
- const importLines = [];
207
- const providerInitLines = [];
208
- const providersArrayEntries = [];
209
- let isIProviderImported = false;
210
- if (providersConfig && Object.keys(providersConfig).length > 0) {
211
- for (const [provName, mod] of Object.entries(providersConfig)) {
212
- if (!mod)
213
- continue;
214
- // Assume default import name from module spec after last '/'
215
- const baseName = mod.split('/').pop() || 'provider';
216
- const className = baseName
217
- .replace(/^[^a-zA-Z_]*/g, '')
218
- .split(/[-_]/)
219
- .map(s => s.charAt(0).toUpperCase() + s.slice(1))
220
- .join('');
221
- // Only add import if the module path isn't already imported
222
- if (!appTs.includes(`from '${mod}'`)) {
223
- importLines.push(`import { ${className}${!isIProviderImported ? ', IProvider, ISqlProvider' : ''} } from '${mod}';`);
224
- }
225
- if (!isIProviderImported)
226
- isIProviderImported = true;
227
- // Read provider configuration from env by name, parse JSON if possible, pass as is
228
- providerInitLines.push(` ${provName}: new ${className}((() => {
229
- const raw = process.env.${provName.toUpperCase()} || '';
230
- try { return raw ? JSON.parse(raw) : undefined; } catch { return raw; }
231
- })())`);
232
- providersArrayEntries.push(provName);
233
- }
234
- }
235
- else {
236
- // Fallback to MySQL provider if no providers configured
237
- if (!appTs.includes("from '@currentjs/provider-mysql'")) {
238
- importLines.push(`import { ProviderMysql, IProvider, ISqlProvider } from '@currentjs/provider-mysql';`);
239
- }
240
- providerInitLines.push(` mysql: new ProviderMysql((() => {
241
- const raw = process.env.MYSQL || '';
242
- try { return raw ? JSON.parse(raw) : undefined; } catch { return raw; }
243
- })())`);
244
- providersArrayEntries.push('mysql');
245
- }
246
- const dbProviderKey = databaseProviderName || providersArrayEntries[0];
247
- const ensureDbLine = `const providers: Record<string, IProvider> = {\n${providerInitLines.join(',\n')}\n};\nconst db = providers['${dbProviderKey}'] as ISqlProvider;`;
248
- // Ensure router imports
249
- if (!appTs.includes("from '@currentjs/router'")) {
250
- importLines.push(`import { createWebServer } from '@currentjs/router';`);
251
- }
252
- // Add entity imports
253
- for (const init of controllerInits) {
254
- const lines = [
255
- init.importStore,
256
- init.importService,
257
- init.importUseCase,
258
- init.importController
259
- ].filter(line => line && line.trim() !== '');
260
- for (const line of lines) {
261
- if (!appTs.includes(line) && !importLines.includes(line)) {
262
- importLines.push(line);
263
- }
264
- }
265
- }
266
- if (importLines.length) {
267
- // Filter out duplicates before prepending
268
- const existingImports = new Set();
269
- const importRegex = /^import[^;]+;$/gm;
270
- const currentImports = appTs.match(importRegex) || [];
271
- currentImports.forEach(line => existingImports.add(line.trim()));
272
- const toAdd = importLines.filter(line => !existingImports.has(line.trim()));
273
- if (toAdd.length)
274
- appTs = toAdd.join('\n') + '\n' + appTs;
275
- }
276
- // Build wiring block
277
- const wiringLines = [];
278
- // Providers + DB initialization
279
- wiringLines.push(ensureDbLine);
280
- // Store -> Service -> UseCase wiring
281
- for (const init of controllerInits) {
282
- const { entityName, entityVar } = init;
283
- wiringLines.push(`const ${entityVar}Store = new ${entityName}Store(db);`);
284
- wiringLines.push(`const ${entityVar}Service = new ${entityName}Service(${entityVar}Store);`);
285
- wiringLines.push(`const ${entityVar}UseCase = new ${entityName}UseCase(${entityVar}Service);`);
286
- }
287
- // Controller registrations
288
- const registrations = controllerInits
289
- .map(i => i.registration)
290
- .filter(r => r && r.trim() !== '')
291
- .join('');
292
- wiringLines.push('const controllers = [');
293
- if (registrations) {
294
- wiringLines.push(` ${registrations.trim()}`);
295
- }
296
- wiringLines.push('];');
297
- // Replace content between markers
298
- const startMarker = constants_1.GENERATOR_MARKERS.CONTROLLERS_START;
299
- const endMarker = constants_1.GENERATOR_MARKERS.CONTROLLERS_END;
300
- const startIdx = appTs.indexOf(startMarker);
301
- const endIdx = appTs.indexOf(endMarker);
302
- if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {
303
- const before = appTs.slice(0, startIdx + startMarker.length);
304
- const after = appTs.slice(endIdx);
305
- const block = '\n' + wiringLines.join('\n') + '\n';
306
- appTs = before + block + after;
307
- }
308
- // Deduplicate import lines across the entire file
309
- const lines = appTs.split('\n');
310
- const seenImports = new Set();
311
- const deduped = lines.filter(line => {
312
- const trimmed = line.trim();
313
- if (/^import\s+/.test(trimmed) && trimmed.endsWith(';')) {
314
- if (seenImports.has(trimmed))
315
- return false;
316
- seenImports.add(trimmed);
317
- }
318
- return true;
319
- });
320
- appTs = deduped.join('\n');
321
- fs.writeFileSync(appTsPath, appTs, 'utf8');
322
- // eslint-disable-next-line no-console
323
- console.log(colors_1.colors.green(`Updated ${appTsPath}`));
324
- }
325
- catch (e) {
326
- // eslint-disable-next-line no-console
327
- console.warn(colors_1.colors.yellow(`Could not update app.ts: ${e instanceof Error ? e.message : String(e)}`));
328
- }
329
- }
330
- // Run build
331
- (0, cliUtils_1.runCommand)('npm run build', {
332
- infoMessage: '\nBuilding...',
333
- successMessage: '[v] Build completed successfully',
334
- errorMessage: '[x] Build failed:'
335
- });
336
- }
@@ -1,41 +0,0 @@
1
- interface FieldConfig {
2
- name: string;
3
- type: string;
4
- required?: boolean;
5
- unique?: boolean;
6
- auto?: boolean;
7
- displayFields?: string[];
8
- }
9
- interface ModelConfig {
10
- name: string;
11
- fields: FieldConfig[];
12
- }
13
- type ModuleConfig = {
14
- models: ModelConfig[];
15
- };
16
- type AppConfig = {
17
- modules: Record<string, ModuleConfig>;
18
- } | ModuleConfig;
19
- export declare class DomainModelGenerator {
20
- private typeMapping;
21
- private availableModels;
22
- private getDefaultValue;
23
- private mapType;
24
- private setAvailableModels;
25
- private getRelatedModelImports;
26
- private generateConstructorParameter;
27
- private isRelationshipField;
28
- private getForeignKeyFieldName;
29
- private generateForeignKeyParameter;
30
- private generateSetterMethods;
31
- private sortFieldsByRequired;
32
- generateModel(modelConfig: ModelConfig): string;
33
- generateModels(models: ModelConfig[]): string;
34
- generateFromYamlFile(yamlFilePath: string): Record<string, string>;
35
- generateFromConfig(config: AppConfig): Record<string, string>;
36
- generateAndSaveFiles(yamlFilePath: string, outputDir: string, opts?: {
37
- force?: boolean;
38
- skipOnConflict?: boolean;
39
- }): Promise<void>;
40
- }
41
- export {};
@@ -1,242 +0,0 @@
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
- this.availableModels = new Set();
54
- }
55
- getDefaultValue(type) {
56
- switch (type) {
57
- case 'datetime':
58
- return 'new Date()';
59
- case 'string':
60
- return "''";
61
- case 'number':
62
- return '0';
63
- case 'boolean':
64
- return 'false';
65
- case 'array':
66
- return '[]';
67
- case 'object':
68
- case 'json':
69
- return '{}';
70
- default:
71
- return 'undefined';
72
- }
73
- }
74
- mapType(yamlType) {
75
- // Check if this is a known model (relationship)
76
- if (this.availableModels.has(yamlType)) {
77
- return yamlType;
78
- }
79
- return this.typeMapping[yamlType] || 'any';
80
- }
81
- setAvailableModels(models) {
82
- this.availableModels.clear();
83
- models.forEach(model => {
84
- this.availableModels.add(model.name);
85
- });
86
- }
87
- getRelatedModelImports(modelConfig) {
88
- const imports = [];
89
- modelConfig.fields.forEach(field => {
90
- if (this.availableModels.has(field.type) && field.type !== modelConfig.name) {
91
- imports.push(`import { ${field.type} } from './${field.type}';`);
92
- }
93
- });
94
- return imports;
95
- }
96
- generateConstructorParameter(field) {
97
- const tsType = this.mapType(field.type);
98
- const isOptional = !field.required && !field.auto;
99
- const hasDefault = field.auto;
100
- let param = `public ${field.name}`;
101
- if (isOptional && !hasDefault) {
102
- param += '?';
103
- }
104
- param += `: ${tsType}`;
105
- if (hasDefault) {
106
- param += ` = ${this.getDefaultValue(field.type)}`;
107
- }
108
- return param;
109
- }
110
- isRelationshipField(field) {
111
- return this.availableModels.has(field.type);
112
- }
113
- getForeignKeyFieldName(field) {
114
- // Convention: fieldName + 'Id' (e.g., owner -> ownerId)
115
- return field.name + 'Id';
116
- }
117
- generateForeignKeyParameter(field) {
118
- const foreignKeyName = this.getForeignKeyFieldName(field);
119
- const isOptional = !field.required && !field.auto;
120
- let param = `public ${foreignKeyName}`;
121
- if (isOptional) {
122
- param += '?';
123
- }
124
- param += ': number';
125
- return param;
126
- }
127
- generateSetterMethods(modelConfig) {
128
- const setterMethods = [];
129
- modelConfig.fields.forEach(field => {
130
- if (!field.auto && field.name !== 'id') {
131
- const tsType = this.mapType(field.type);
132
- const methodName = `set${field.name.charAt(0).toUpperCase() + field.name.slice(1)}`;
133
- // For all fields (including relationships), generate simple setter
134
- // Domain model doesn't care about FKs - that's infrastructure concern
135
- const isOptional = !field.required && !field.auto;
136
- const setter = `
137
- ${methodName}(${field.name}: ${tsType}${isOptional ? ' | undefined' : ''}): void {
138
- this.${field.name} = ${field.name};
139
- }`;
140
- setterMethods.push(setter);
141
- }
142
- });
143
- return setterMethods.join('\n');
144
- }
145
- sortFieldsByRequired(fields) {
146
- // Sort fields: required fields first, then optional fields
147
- return [...fields].sort((a, b) => {
148
- const aRequired = a.required !== false && !a.auto;
149
- const bRequired = b.required !== false && !b.auto;
150
- if (aRequired === bRequired) {
151
- return 0; // Keep original order if both have same required status
152
- }
153
- return aRequired ? -1 : 1; // Required fields come first
154
- });
155
- }
156
- generateModel(modelConfig) {
157
- const className = modelConfig.name;
158
- // Always add id field first
159
- const constructorParams = ['public id: number'];
160
- // Sort fields to put required fields before optional ones
161
- const sortedFields = this.sortFieldsByRequired(modelConfig.fields);
162
- // Process other fields
163
- sortedFields.forEach(field => {
164
- // For relationship fields, only add the relationship object (not FK)
165
- // Domain model works with objects only - FK is infrastructure concern
166
- constructorParams.push(this.generateConstructorParameter(field));
167
- });
168
- const constructorParamsStr = constructorParams.join(',\n ');
169
- const setterMethods = this.generateSetterMethods(modelConfig);
170
- // Generate imports for related models
171
- const imports = this.getRelatedModelImports(modelConfig);
172
- const importsStr = imports.length > 0 ? imports.join('\n') + '\n\n' : '';
173
- return `${importsStr}export class ${className} {
174
- public constructor(
175
- ${constructorParamsStr}
176
- ) { }
177
- ${setterMethods}
178
- }`;
179
- }
180
- generateModels(models) {
181
- return models.map(model => this.generateModel(model)).join('\n\n');
182
- }
183
- generateFromYamlFile(yamlFilePath) {
184
- const yamlContent = fs.readFileSync(yamlFilePath, 'utf8');
185
- const config = (0, yaml_1.parse)(yamlContent);
186
- const result = {};
187
- if (config.modules) {
188
- const app = config;
189
- Object.values(app.modules).forEach(moduleConfig => {
190
- if (moduleConfig.models && moduleConfig.models.length > 0) {
191
- // Set available models for relationship detection
192
- this.setAvailableModels(moduleConfig.models);
193
- moduleConfig.models.forEach(m => {
194
- result[m.name] = this.generateModel(m);
195
- });
196
- }
197
- });
198
- }
199
- else if (config.models) {
200
- const module = config;
201
- // Set available models for relationship detection
202
- this.setAvailableModels(module.models);
203
- module.models.forEach(m => {
204
- result[m.name] = this.generateModel(m);
205
- });
206
- }
207
- return result;
208
- }
209
- generateFromConfig(config) {
210
- const result = {};
211
- if (config.modules) {
212
- Object.values(config.modules).forEach(moduleConfig => {
213
- if (moduleConfig.models && moduleConfig.models.length > 0) {
214
- // Set available models for relationship detection
215
- this.setAvailableModels(moduleConfig.models);
216
- moduleConfig.models.forEach(m => {
217
- result[m.name] = this.generateModel(m);
218
- });
219
- }
220
- });
221
- }
222
- else if (config.models) {
223
- const module = config;
224
- // Set available models for relationship detection
225
- this.setAvailableModels(module.models);
226
- module.models.forEach(m => {
227
- result[m.name] = this.generateModel(m);
228
- });
229
- }
230
- return result;
231
- }
232
- async generateAndSaveFiles(yamlFilePath, outputDir, opts) {
233
- const codeByEntity = this.generateFromYamlFile(yamlFilePath);
234
- await Promise.all(Object.entries(codeByEntity).map(([entity, code]) => {
235
- const filePath = path.join(outputDir, `${entity}.ts`);
236
- 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) });
237
- }));
238
- // eslint-disable-next-line no-console
239
- console.log('\n' + colors_1.colors.green('Domain model files generated successfully!') + '\n');
240
- }
241
- }
242
- exports.DomainModelGenerator = DomainModelGenerator;
@@ -1,55 +0,0 @@
1
- import { NewModuleConfig } from '../types/configTypes';
2
- export declare class NewControllerGenerator {
3
- private capitalize;
4
- private getHttpDecorator;
5
- private parseUseCase;
6
- /**
7
- * Normalize auth config to an array of roles
8
- */
9
- private normalizeAuth;
10
- /**
11
- * Check if auth config includes owner permission
12
- */
13
- private hasOwnerAuth;
14
- /**
15
- * Generate pre-fetch authentication/authorization check code.
16
- * This runs before fetching the entity and validates authentication and role-based access.
17
- * @param auth - The auth requirement: 'all', 'authenticated', 'owner', role names, or array of roles
18
- * @returns Code string for the auth check, or empty string if no check needed
19
- */
20
- private generateAuthCheck;
21
- /**
22
- * Generate post-fetch authorization check for owner validation.
23
- * This runs after fetching the entity and validates ownership.
24
- * Used for READ operations (get, list) where we check after fetch.
25
- * For child entities, uses getResourceOwner() since result has no ownerId.
26
- */
27
- private generatePostFetchOwnerCheck;
28
- /**
29
- * Generate pre-mutation authorization check for owner validation.
30
- * This runs BEFORE the mutation to prevent unauthorized changes.
31
- * Used for WRITE operations (update, delete).
32
- * @param auth - The auth requirement
33
- * @param useCaseVar - The use case variable name
34
- * @returns Code string for the pre-mutation owner check, or empty string if not needed
35
- */
36
- private generatePreMutationOwnerCheck;
37
- private generateApiEndpointMethod;
38
- private generateWebPageMethod;
39
- private generateOnSuccessHandler;
40
- private generateOnErrorHandler;
41
- /**
42
- * Sort routes so static paths are registered before parameterized ones.
43
- * This prevents parameterized routes (e.g. /:id) from catching requests
44
- * meant for static routes (e.g. /create).
45
- */
46
- private sortRoutesBySpecificity;
47
- private generateApiController;
48
- private generateWebController;
49
- generateFromConfig(config: NewModuleConfig): Record<string, string>;
50
- generateFromYamlFile(yamlFilePath: string): Record<string, string>;
51
- generateAndSaveFiles(yamlFilePath: string, moduleDir: string, opts?: {
52
- force?: boolean;
53
- skipOnConflict?: boolean;
54
- }): Promise<string[]>;
55
- }