@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.
Files changed (55) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE +56 -0
  3. package/README.md +686 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.js +143 -0
  6. package/dist/commands/commit.d.ts +1 -0
  7. package/dist/commands/commit.js +153 -0
  8. package/dist/commands/createApp.d.ts +1 -0
  9. package/dist/commands/createApp.js +64 -0
  10. package/dist/commands/createModule.d.ts +1 -0
  11. package/dist/commands/createModule.js +121 -0
  12. package/dist/commands/diff.d.ts +1 -0
  13. package/dist/commands/diff.js +164 -0
  14. package/dist/commands/generateAll.d.ts +4 -0
  15. package/dist/commands/generateAll.js +305 -0
  16. package/dist/commands/infer.d.ts +1 -0
  17. package/dist/commands/infer.js +179 -0
  18. package/dist/generators/controllerGenerator.d.ts +20 -0
  19. package/dist/generators/controllerGenerator.js +280 -0
  20. package/dist/generators/domainModelGenerator.d.ts +33 -0
  21. package/dist/generators/domainModelGenerator.js +175 -0
  22. package/dist/generators/serviceGenerator.d.ts +39 -0
  23. package/dist/generators/serviceGenerator.js +379 -0
  24. package/dist/generators/storeGenerator.d.ts +31 -0
  25. package/dist/generators/storeGenerator.js +191 -0
  26. package/dist/generators/templateGenerator.d.ts +11 -0
  27. package/dist/generators/templateGenerator.js +143 -0
  28. package/dist/generators/templates/appTemplates.d.ts +27 -0
  29. package/dist/generators/templates/appTemplates.js +1621 -0
  30. package/dist/generators/templates/controllerTemplates.d.ts +43 -0
  31. package/dist/generators/templates/controllerTemplates.js +82 -0
  32. package/dist/generators/templates/index.d.ts +5 -0
  33. package/dist/generators/templates/index.js +21 -0
  34. package/dist/generators/templates/serviceTemplates.d.ts +15 -0
  35. package/dist/generators/templates/serviceTemplates.js +54 -0
  36. package/dist/generators/templates/storeTemplates.d.ts +9 -0
  37. package/dist/generators/templates/storeTemplates.js +260 -0
  38. package/dist/generators/templates/validationTemplates.d.ts +25 -0
  39. package/dist/generators/templates/validationTemplates.js +66 -0
  40. package/dist/generators/templates/viewTemplates.d.ts +16 -0
  41. package/dist/generators/templates/viewTemplates.js +359 -0
  42. package/dist/generators/validationGenerator.d.ts +24 -0
  43. package/dist/generators/validationGenerator.js +199 -0
  44. package/dist/utils/cliUtils.d.ts +6 -0
  45. package/dist/utils/cliUtils.js +71 -0
  46. package/dist/utils/colors.d.ts +26 -0
  47. package/dist/utils/colors.js +80 -0
  48. package/dist/utils/commitUtils.d.ts +46 -0
  49. package/dist/utils/commitUtils.js +377 -0
  50. package/dist/utils/constants.d.ts +52 -0
  51. package/dist/utils/constants.js +64 -0
  52. package/dist/utils/generationRegistry.d.ts +25 -0
  53. package/dist/utils/generationRegistry.js +192 -0
  54. package/howto.md +556 -0
  55. package/package.json +44 -0
@@ -0,0 +1,305 @@
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.handleGenerateAll = handleGenerateAll;
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 domainModelGenerator_1 = require("../generators/domainModelGenerator");
42
+ const validationGenerator_1 = require("../generators/validationGenerator");
43
+ const serviceGenerator_1 = require("../generators/serviceGenerator");
44
+ const controllerGenerator_1 = require("../generators/controllerGenerator");
45
+ const storeGenerator_1 = require("../generators/storeGenerator");
46
+ const templateGenerator_1 = require("../generators/templateGenerator");
47
+ const generationRegistry_1 = require("../utils/generationRegistry");
48
+ const colors_1 = require("../utils/colors");
49
+ const constants_1 = require("../utils/constants");
50
+ async function handleGenerateAll(yamlPathArg, _outArg, moduleName, opts) {
51
+ var _a, _b;
52
+ const appYamlPath = (0, cliUtils_1.resolveYamlPath)(yamlPathArg);
53
+ (0, generationRegistry_1.initGenerationRegistry)(process.cwd());
54
+ const raw = fs.readFileSync(appYamlPath, 'utf8');
55
+ const appConfig = (0, yaml_1.parse)(raw);
56
+ 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));
57
+ const providersConfig = appConfig === null || appConfig === void 0 ? void 0 : appConfig.providers;
58
+ const databaseProviderName = appConfig === null || appConfig === void 0 ? void 0 : appConfig.database;
59
+ const shouldIncludeModule = (moduleYamlRel) => {
60
+ if (!moduleName || moduleName === '*')
61
+ return true;
62
+ const moduleNameLc = moduleName.toLowerCase();
63
+ const relNormalized = moduleYamlRel.replace(/\\/g, '/').toLowerCase();
64
+ if (relNormalized.endsWith(`/${moduleNameLc}.yaml`))
65
+ return true;
66
+ const moduleYamlPath = path.isAbsolute(moduleYamlRel)
67
+ ? moduleYamlRel
68
+ : path.resolve(process.cwd(), moduleYamlRel);
69
+ const dirName = path.basename(path.dirname(moduleYamlPath)).toLowerCase();
70
+ if (dirName === moduleNameLc)
71
+ return true;
72
+ // Allow passing a path fragment
73
+ if (relNormalized.includes(`/${moduleNameLc}/`) || relNormalized.endsWith(`/${moduleNameLc}`))
74
+ return true;
75
+ return false;
76
+ };
77
+ const filteredModules = modulesList.filter(shouldIncludeModule);
78
+ if (filteredModules.length === 0) {
79
+ // eslint-disable-next-line no-console
80
+ console.warn(colors_1.colors.yellow(`No modules matched: ${moduleName}`));
81
+ return;
82
+ }
83
+ const domainGen = new domainModelGenerator_1.DomainModelGenerator();
84
+ const valGen = new validationGenerator_1.ValidationGenerator();
85
+ const svcGen = new serviceGenerator_1.ServiceGenerator();
86
+ const ctrlGen = new controllerGenerator_1.ControllerGenerator();
87
+ const storeGen = new storeGenerator_1.StoreGenerator();
88
+ const tplGen = new templateGenerator_1.TemplateGenerator();
89
+ const initsBySrcDir = new Map();
90
+ // Run modules sequentially to avoid overlapping interactive prompts
91
+ for (const moduleYamlRel of filteredModules) {
92
+ const moduleYamlPath = path.isAbsolute(moduleYamlRel)
93
+ ? moduleYamlRel
94
+ : path.resolve(process.cwd(), moduleYamlRel);
95
+ if (!fs.existsSync(moduleYamlPath)) {
96
+ // eslint-disable-next-line no-console
97
+ console.warn(colors_1.colors.yellow(`Module YAML not found: ${moduleYamlPath}`));
98
+ continue;
99
+ }
100
+ const moduleDir = path.dirname(moduleYamlPath);
101
+ // Output folders inside module structure
102
+ const domainOut = path.join(moduleDir, 'domain', 'entities');
103
+ const appOut = path.join(moduleDir, 'application');
104
+ const infraOut = path.join(moduleDir, 'infrastructure');
105
+ fs.mkdirSync(domainOut, { recursive: true });
106
+ fs.mkdirSync(appOut, { recursive: true });
107
+ fs.mkdirSync(infraOut, { recursive: true });
108
+ // Domain entities
109
+ // eslint-disable-next-line no-await-in-loop
110
+ await domainGen.generateAndSaveFiles(moduleYamlPath, domainOut, { force: !!(opts === null || opts === void 0 ? void 0 : opts.force), skipOnConflict: !!(opts === null || opts === void 0 ? void 0 : opts.skip) });
111
+ // Generate and save via per-generator write logic
112
+ // eslint-disable-next-line no-await-in-loop
113
+ await valGen.generateAndSaveFiles(moduleYamlPath, appOut, { force: !!(opts === null || opts === void 0 ? void 0 : opts.force), skipOnConflict: !!(opts === null || opts === void 0 ? void 0 : opts.skip) });
114
+ await svcGen.generateAndSaveFiles(moduleYamlPath, appOut, { force: !!(opts === null || opts === void 0 ? void 0 : opts.force), skipOnConflict: !!(opts === null || opts === void 0 ? void 0 : opts.skip) });
115
+ const generatedControllers = await ctrlGen.generateAndSaveFiles(moduleYamlPath, infraOut, { force: !!(opts === null || opts === void 0 ? void 0 : opts.force), skipOnConflict: !!(opts === null || opts === void 0 ? void 0 : opts.skip) });
116
+ await tplGen.generateAndSaveFiles(moduleYamlPath, undefined, { force: !!(opts === null || opts === void 0 ? void 0 : opts.force), skipOnConflict: !!(opts === null || opts === void 0 ? void 0 : opts.skip) });
117
+ // Find nearest ancestor containing src/app.ts and collect controller inits for a single write later
118
+ let probeDir = moduleDir;
119
+ let srcDir = null;
120
+ for (let i = 0; i < 6; i += 1) {
121
+ const candidate = path.join(probeDir, 'src', constants_1.COMMON_FILES.APP_TS);
122
+ if (fs.existsSync(candidate)) {
123
+ srcDir = path.join(probeDir, 'src');
124
+ break;
125
+ }
126
+ const parent = path.dirname(probeDir);
127
+ if (parent === probeDir)
128
+ break;
129
+ probeDir = parent;
130
+ }
131
+ if (!srcDir)
132
+ continue;
133
+ const list = (_b = initsBySrcDir.get(srcDir)) !== null && _b !== void 0 ? _b : [];
134
+ for (const filePath of generatedControllers) {
135
+ const rel = path
136
+ .relative(srcDir, filePath)
137
+ .replace(/\\/g, '/')
138
+ .replace(/\.ts$/, '');
139
+ const ctrlName = path.basename(rel);
140
+ const importPath = rel.startsWith('.') ? rel : `./${rel}`;
141
+ const baseEntityName = ctrlName.endsWith('ApiController')
142
+ ? ctrlName.slice(0, -'ApiController'.length)
143
+ : ctrlName.endsWith('WebController')
144
+ ? ctrlName.slice(0, -'WebController'.length)
145
+ : ctrlName.replace('Controller', '');
146
+ const entityName = baseEntityName;
147
+ const entityVar = entityName.charAt(0).toLowerCase() + entityName.slice(1);
148
+ const m = rel.match(/modules\/([^/]+)\/infrastructure\/controllers\//);
149
+ const moduleFolder = m ? m[1] : undefined;
150
+ if (!moduleFolder)
151
+ continue;
152
+ const storeImportPath = `${constants_1.PATH_PATTERNS.MODULES_RELATIVE}${moduleFolder}/${constants_1.PATH_PATTERNS.INFRASTRUCTURE}/${constants_1.PATH_PATTERNS.STORES}/${entityName}${constants_1.GENERATOR_SUFFIXES.STORE}`;
153
+ const serviceImportPath = `${constants_1.PATH_PATTERNS.MODULES_RELATIVE}${moduleFolder}/${constants_1.PATH_PATTERNS.APPLICATION}/${constants_1.PATH_PATTERNS.SERVICES}/${entityName}${constants_1.GENERATOR_SUFFIXES.SERVICE}`;
154
+ //const authImportPath = `./modules/${moduleFolder}/application/auth/AuthService`;
155
+ // const hasAuth = true;//fs.existsSync(path.join(srcDir, authImportPath + '.ts'));
156
+ const init = {
157
+ ctrlName,
158
+ entityName,
159
+ entityVar,
160
+ importController: `import { ${ctrlName} } from '${importPath}';`,
161
+ importStore: `import { ${entityName}Store } from '${storeImportPath}';`,
162
+ importService: `import { ${entityName}Service } from '${serviceImportPath}';`,
163
+ importAuth: undefined, //hasAuth ? `import { AuthService } from '${authImportPath}';` : undefined,
164
+ wiring: [
165
+ `const ${entityVar}Store = new ${entityName}Store(db);`,
166
+ `const ${entityVar}Service = new ${entityName}Service(${entityVar}Store);`
167
+ ],
168
+ registration: `new ${ctrlName}(${entityVar}Service)`
169
+ };
170
+ // Avoid duplicates by controller (keep both Api/Web), dedupe wiring later by entityName
171
+ if (!list.find((x) => x.ctrlName === init.ctrlName))
172
+ list.push(init);
173
+ }
174
+ initsBySrcDir.set(srcDir, list);
175
+ await storeGen.generateAndSaveFiles(moduleYamlPath, infraOut, { force: !!(opts === null || opts === void 0 ? void 0 : opts.force), skipOnConflict: !!(opts === null || opts === void 0 ? void 0 : opts.skip) });
176
+ }
177
+ // Single write per app: inject imports and rewrite block between markers
178
+ let isIProviderImported = false;
179
+ for (const [srcDir, controllerInits] of initsBySrcDir.entries()) {
180
+ try {
181
+ const appTsPath = path.join(srcDir, constants_1.COMMON_FILES.APP_TS);
182
+ if (!fs.existsSync(appTsPath))
183
+ continue;
184
+ let appTs = fs.readFileSync(appTsPath, 'utf8');
185
+ // Build providers import and initialization from app.yaml providers section
186
+ const importLines = [];
187
+ const providerInitLines = [];
188
+ const providersArrayEntries = [];
189
+ if (providersConfig && Object.keys(providersConfig).length > 0) {
190
+ for (const [provName, mod] of Object.entries(providersConfig)) {
191
+ if (!mod)
192
+ continue;
193
+ // Assume default import name from module spec after last '/'
194
+ const baseName = mod.split('/').pop() || 'provider';
195
+ const className = baseName
196
+ .replace(/^[^a-zA-Z_]*/g, '')
197
+ .split(/[-_]/)
198
+ .map(s => s.charAt(0).toUpperCase() + s.slice(1))
199
+ .join('');
200
+ importLines.push(`import { ${className}${!isIProviderImported ? ', IProvider, ISqlProvider' : ''} } from '${mod}';`);
201
+ if (!isIProviderImported)
202
+ isIProviderImported = true;
203
+ // Read provider configuration from env by name, parse JSON if possible, pass as is
204
+ providerInitLines.push(` ${provName}: new ${className}((() => {
205
+ const raw = process.env.${provName.toUpperCase()} || '';
206
+ try { return raw ? JSON.parse(raw) : undefined; } catch { return raw; }
207
+ })())`);
208
+ providersArrayEntries.push(provName);
209
+ }
210
+ }
211
+ else {
212
+ // Fallback to MySQL provider if no providers configured
213
+ importLines.push(`import { ProviderMysql, ISqlProvider } from '@currentjs/provider-mysql';`);
214
+ providerInitLines.push(` mysql: new ProviderMysql((() => {
215
+ const raw = process.env.MYSQL || '';
216
+ try { return raw ? JSON.parse(raw) : undefined; } catch { return raw; }
217
+ })())`);
218
+ providersArrayEntries.push('mysql');
219
+ }
220
+ const ensureDbLine = `const providers: Record<string, IProvider> = {\n${providerInitLines.join(',\n')}\n};\nconst db = providers['${databaseProviderName || providersArrayEntries[0]}'] as ISqlProvider;`;
221
+ // Ensure router import for server (app template already imports templating)
222
+ if (!appTs.includes("from '@currentjs/router'")) {
223
+ importLines.push(`import { createWebServer, createStaticServer } from '@currentjs/router';`);
224
+ }
225
+ for (const il of importLines) {
226
+ if (!appTs.includes(il)) {
227
+ appTs = il + '\n' + appTs;
228
+ }
229
+ }
230
+ // Ensure MySQL provider import exists
231
+ if (!appTs.includes("from '@currentjs/provider-mysql'")) {
232
+ importLines.push(`import { ProviderMysql } from '@currentjs/provider-mysql';`);
233
+ }
234
+ for (const init of controllerInits) {
235
+ const maybe = [init.importController, init.importStore, init.importService];
236
+ if (init.importAuth)
237
+ maybe.push(init.importAuth);
238
+ for (const line of maybe) {
239
+ if (!appTs.includes(line) && !importLines.includes(line))
240
+ importLines.push(line);
241
+ }
242
+ }
243
+ if (importLines.length) {
244
+ const existingImports = new Set();
245
+ const importRegex = /^import[^;]+;$/gm;
246
+ const currentImports = appTs.match(importRegex) || [];
247
+ currentImports.forEach(line => existingImports.add(line.trim()));
248
+ const toAdd = importLines.filter(line => !existingImports.has(line.trim()));
249
+ if (toAdd.length)
250
+ appTs = toAdd.join('\n') + '\n' + appTs;
251
+ }
252
+ // Compose fresh block content
253
+ const wiringLines = [];
254
+ // DB placeholder once
255
+ wiringLines.push(ensureDbLine);
256
+ const wiredEntities = new Set();
257
+ for (const init of controllerInits) {
258
+ if (!wiredEntities.has(init.entityName)) {
259
+ wiringLines.push(...init.wiring);
260
+ wiredEntities.add(init.entityName);
261
+ }
262
+ }
263
+ const registrations = controllerInits.map((i) => i.registration);
264
+ wiringLines.push('const controllers = [');
265
+ wiringLines.push(` ${registrations.join(',\n ')}`);
266
+ wiringLines.push('];');
267
+ const startMarker = constants_1.GENERATOR_MARKERS.CONTROLLERS_START;
268
+ const endMarker = constants_1.GENERATOR_MARKERS.CONTROLLERS_END;
269
+ const startIdx = appTs.indexOf(startMarker);
270
+ const endIdx = appTs.indexOf(endMarker);
271
+ if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {
272
+ const before = appTs.slice(0, startIdx + startMarker.length);
273
+ const after = appTs.slice(endIdx);
274
+ const block = '\n' + wiringLines.join('\n') + '\n';
275
+ appTs = before + block + after;
276
+ }
277
+ // Ensure the createWebServer call includes renderer in options
278
+ // Case 1: createWebServer(controllers, { ... })
279
+ const withOptionsRegex = /createWebServer\(\s*controllers\s*,\s*\{([\s\S]*?)\}\s*\)/m;
280
+ if (withOptionsRegex.test(appTs)) {
281
+ appTs = appTs.replace(withOptionsRegex, (full, inner) => {
282
+ if (/\brenderer\b\s*:/.test(inner))
283
+ return full; // already present
284
+ const trimmed = inner.trim();
285
+ const prefix = trimmed.length ? inner.replace(trimmed, '') : '';
286
+ const suffix = inner.endsWith(trimmed) ? '' : inner.slice(inner.indexOf(trimmed) + trimmed.length);
287
+ const sep = trimmed.length ? ', ' : '';
288
+ return full.replace(inner, `${prefix}${trimmed}${sep}renderer` + `: renderer${suffix}`);
289
+ });
290
+ }
291
+ else {
292
+ // Case 2: createWebServer(controllers)
293
+ const noOptionsRegex = /createWebServer\(\s*controllers\s*\)/m;
294
+ if (noOptionsRegex.test(appTs)) {
295
+ appTs = appTs.replace(noOptionsRegex, 'createWebServer(controllers, { renderer })');
296
+ }
297
+ }
298
+ fs.writeFileSync(appTsPath, appTs, 'utf8');
299
+ }
300
+ catch (e) {
301
+ // eslint-disable-next-line no-console
302
+ console.warn(colors_1.colors.yellow(`Could not update app.ts with controllers: ${e instanceof Error ? e.message : String(e)}`));
303
+ }
304
+ }
305
+ }
@@ -0,0 +1 @@
1
+ export declare function handleInfer(entityFileArg?: string, write?: boolean): void;
@@ -0,0 +1,179 @@
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.handleInfer = handleInfer;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const yaml_1 = require("yaml");
40
+ const cliUtils_1 = require("../utils/cliUtils");
41
+ function reverseType(tsType) {
42
+ const t = tsType.trim();
43
+ if (t === 'string')
44
+ return 'string';
45
+ if (t === 'number')
46
+ return 'number';
47
+ if (t === 'boolean')
48
+ return 'boolean';
49
+ if (t === 'Date')
50
+ return 'datetime';
51
+ if (t === 'any[]')
52
+ return 'array';
53
+ if (t === 'object')
54
+ return 'object';
55
+ if (t === 'any')
56
+ return 'json';
57
+ return 'json';
58
+ }
59
+ function inferFromConstructorParams(paramsSrc) {
60
+ // Remove newlines to simplify parsing
61
+ const src = paramsSrc.replace(/\n/g, ' ');
62
+ const fields = [];
63
+ const regex = /public\s+(\w+)(\?)?\s*:\s*([^=,]+)(\s*=\s*([^,]+))?/g;
64
+ let match;
65
+ let index = 0;
66
+ while ((match = regex.exec(src))) {
67
+ const name = match[1];
68
+ const optionalMark = !!match[2];
69
+ const tsType = match[3].trim();
70
+ const hasDefault = !!match[4];
71
+ if (index === 0 && name === 'id') {
72
+ // Skip id
73
+ index += 1;
74
+ continue;
75
+ }
76
+ const yamlType = reverseType(tsType);
77
+ const field = { name, type: yamlType };
78
+ if (hasDefault)
79
+ field.auto = true;
80
+ // required: if optional mark present then not required; if auto true, mark not required as well
81
+ if (optionalMark || hasDefault)
82
+ field.required = false;
83
+ else
84
+ field.required = true;
85
+ fields.push(field);
86
+ index += 1;
87
+ }
88
+ return fields;
89
+ }
90
+ function parseEntity(filePath) {
91
+ const content = fs.readFileSync(filePath, 'utf8');
92
+ const classMatch = content.match(/export\s+class\s+(\w+)\s*\{/);
93
+ if (!classMatch) {
94
+ throw new Error(`Cannot find exported class in ${filePath}`);
95
+ }
96
+ const entityName = classMatch[1];
97
+ // Extract constructor params
98
+ const ctorMatch = content.match(/constructor\s*\(([^)]*)\)/s);
99
+ if (!ctorMatch) {
100
+ throw new Error(`Cannot find constructor in ${filePath}`);
101
+ }
102
+ const paramsSrc = ctorMatch[1];
103
+ const fields = inferFromConstructorParams(paramsSrc);
104
+ return { entityName, fields };
105
+ }
106
+ function findModuleYamlForEntity(entityFile) {
107
+ const abs = (0, cliUtils_1.toAbsolute)(entityFile);
108
+ // Expect .../src/modules/<ModuleName>/domain/entities/<Entity>.ts
109
+ const parts = abs.split(path.sep);
110
+ const idx = parts.lastIndexOf('modules');
111
+ if (idx === -1 || idx + 1 >= parts.length)
112
+ return null;
113
+ const moduleName = parts[idx + 1];
114
+ // Build absolute module dir (handle leading path segment on POSIX correctly)
115
+ const moduleDir = path.isAbsolute(abs)
116
+ ? path.join(path.sep, ...parts.slice(1, idx + 2))
117
+ : path.join(...parts.slice(0, idx + 2));
118
+ // Try to find any yaml in module dir (prefer one matching module name)
119
+ try {
120
+ const entries = fs.readdirSync(moduleDir);
121
+ const yamls = entries.filter(e => e.toLowerCase().endsWith('.yaml'));
122
+ if (yamls.length > 0) {
123
+ const preferred = yamls.find(y => y.toLowerCase() === `${moduleName.toLowerCase()}.yaml`);
124
+ const chosen = preferred !== null && preferred !== void 0 ? preferred : yamls[0];
125
+ return path.join(moduleDir, chosen);
126
+ }
127
+ }
128
+ catch {
129
+ // ignore
130
+ }
131
+ // Fallback to conventional name
132
+ const moduleYaml = path.join(moduleDir, `${moduleName.toLowerCase()}.yaml`);
133
+ return moduleYaml;
134
+ }
135
+ function handleInfer(entityFileArg, write) {
136
+ if (!entityFileArg) {
137
+ throw new Error('Usage: currentjs infer --file <path/to/Entity.ts> [--write]');
138
+ }
139
+ const entityFile = (0, cliUtils_1.toAbsolute)(entityFileArg);
140
+ if (!fs.existsSync(entityFile)) {
141
+ throw new Error(`Entity file not found: ${entityFile}`);
142
+ }
143
+ const { entityName, fields } = parseEntity(entityFile);
144
+ const modelDesc = {
145
+ name: entityName,
146
+ fields
147
+ };
148
+ if (!write) {
149
+ // Print a YAML snippet for the model only
150
+ // eslint-disable-next-line no-console
151
+ console.log((0, yaml_1.stringify)({ models: [modelDesc] }));
152
+ return;
153
+ }
154
+ const moduleYamlPath = findModuleYamlForEntity(entityFile);
155
+ if (!moduleYamlPath) {
156
+ throw new Error('Could not determine module YAML path from entity file location. Use --write only within a module structure.');
157
+ }
158
+ let config = {};
159
+ if (fs.existsSync(moduleYamlPath)) {
160
+ try {
161
+ config = (0, yaml_1.parse)(fs.readFileSync(moduleYamlPath, 'utf8')) || {};
162
+ }
163
+ catch {
164
+ config = {};
165
+ }
166
+ }
167
+ if (!config.models)
168
+ config.models = [];
169
+ const idx = config.models.findIndex((m) => m && m.name === entityName);
170
+ if (idx === -1)
171
+ config.models.push(modelDesc);
172
+ else
173
+ config.models[idx] = modelDesc;
174
+ fs.mkdirSync(path.dirname(moduleYamlPath), { recursive: true });
175
+ const yamlOut = (0, yaml_1.stringify)(config);
176
+ fs.writeFileSync(moduleYamlPath, yamlOut, 'utf8');
177
+ // eslint-disable-next-line no-console
178
+ console.log(`Updated ${path.relative(process.cwd(), path.resolve(moduleYamlPath))} with model ${entityName}`);
179
+ }
@@ -0,0 +1,20 @@
1
+ export declare class ControllerGenerator {
2
+ private hasPermissions;
3
+ private getActionPermissions;
4
+ private shouldGenerateMethod;
5
+ private needsUserParam;
6
+ private getHttpMethodName;
7
+ private getHttpDecorator;
8
+ private generateMethodImplementation;
9
+ private replaceTemplateVars;
10
+ private generateControllerMethod;
11
+ private getWebMethodName;
12
+ private getPathSuffix;
13
+ private getReturnType;
14
+ private generateController;
15
+ generateFromYamlFile(yamlFilePath: string): Record<string, string>;
16
+ generateAndSaveFiles(yamlFilePath?: string, outputDir?: string, opts?: {
17
+ force?: boolean;
18
+ skipOnConflict?: boolean;
19
+ }): Promise<string[]>;
20
+ }