@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.
- package/CHANGELOG.md +19 -0
- package/README.md +374 -996
- package/dist/cli.js +28 -10
- package/dist/commands/createModel.d.ts +1 -0
- package/dist/commands/createModel.js +764 -0
- package/dist/commands/createModule.js +13 -0
- package/dist/commands/generateAll.d.ts +1 -0
- package/dist/commands/generateAll.js +1 -1
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/{createApp.js → init.js} +2 -2
- package/dist/commands/migrateCommit.js +33 -68
- package/dist/generators/controllerGenerator.d.ts +7 -0
- package/dist/generators/controllerGenerator.js +56 -17
- package/dist/generators/domainLayerGenerator.js +51 -8
- package/dist/generators/dtoGenerator.js +13 -8
- package/dist/generators/serviceGenerator.d.ts +6 -0
- package/dist/generators/serviceGenerator.js +219 -23
- package/dist/generators/storeGenerator.d.ts +4 -0
- package/dist/generators/storeGenerator.js +116 -9
- package/dist/generators/templateGenerator.d.ts +1 -0
- package/dist/generators/templateGenerator.js +8 -2
- package/dist/generators/templates/appTemplates.js +1 -1
- package/dist/generators/templates/data/cursorRulesTemplate +11 -755
- package/dist/generators/templates/data/frontendScriptTemplate +11 -4
- package/dist/generators/templates/data/mainViewTemplate +1 -0
- package/dist/generators/templates/storeTemplates.d.ts +1 -1
- package/dist/generators/templates/storeTemplates.js +3 -26
- package/dist/generators/useCaseGenerator.js +6 -3
- package/dist/types/configTypes.d.ts +6 -0
- package/dist/utils/migrationUtils.d.ts +9 -19
- package/dist/utils/migrationUtils.js +80 -110
- package/dist/utils/promptUtils.d.ts +37 -0
- package/dist/utils/promptUtils.js +149 -0
- package/dist/utils/typeUtils.d.ts +4 -0
- package/dist/utils/typeUtils.js +7 -0
- package/package.json +1 -1
- package/dist/commands/createApp.d.ts +0 -1
- package/dist/commands/migratePush.d.ts +0 -1
- package/dist/commands/migratePush.js +0 -135
- package/dist/commands/migrateUpdate.d.ts +0 -1
- package/dist/commands/migrateUpdate.js +0 -147
- package/dist/commands/newGenerateAll.d.ts +0 -4
- package/dist/commands/newGenerateAll.js +0 -336
- package/dist/generators/domainModelGenerator.d.ts +0 -41
- package/dist/generators/domainModelGenerator.js +0 -242
- package/dist/generators/newControllerGenerator.d.ts +0 -55
- package/dist/generators/newControllerGenerator.js +0 -644
- package/dist/generators/newServiceGenerator.d.ts +0 -19
- package/dist/generators/newServiceGenerator.js +0 -266
- package/dist/generators/newStoreGenerator.d.ts +0 -39
- package/dist/generators/newStoreGenerator.js +0 -408
- package/dist/generators/newTemplateGenerator.d.ts +0 -29
- package/dist/generators/newTemplateGenerator.js +0 -510
- package/dist/generators/storeGeneratorV2.d.ts +0 -31
- package/dist/generators/storeGeneratorV2.js +0 -190
- package/dist/generators/templates/controllerTemplates.d.ts +0 -43
- package/dist/generators/templates/controllerTemplates.js +0 -82
- package/dist/generators/templates/newStoreTemplates.d.ts +0 -5
- package/dist/generators/templates/newStoreTemplates.js +0 -141
- package/dist/generators/templates/serviceTemplates.d.ts +0 -16
- package/dist/generators/templates/serviceTemplates.js +0 -59
- package/dist/generators/templates/validationTemplates.d.ts +0 -25
- package/dist/generators/templates/validationTemplates.js +0 -66
- package/dist/generators/templates/viewTemplates.d.ts +0 -25
- package/dist/generators/templates/viewTemplates.js +0 -491
- package/dist/generators/validationGenerator.d.ts +0 -29
- package/dist/generators/validationGenerator.js +0 -250
- package/dist/utils/new_parts_of_migrationUtils.d.ts +0 -0
- package/dist/utils/new_parts_of_migrationUtils.js +0 -164
- 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
|
-
}
|