@currentjs/gen 0.3.1 → 0.5.0

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 (69) hide show
  1. package/CHANGELOG.md +8 -289
  2. package/README.md +623 -427
  3. package/dist/cli.js +2 -1
  4. package/dist/commands/commit.js +25 -42
  5. package/dist/commands/createApp.js +1 -0
  6. package/dist/commands/createModule.js +151 -45
  7. package/dist/commands/diff.js +27 -40
  8. package/dist/commands/generateAll.js +141 -291
  9. package/dist/commands/migrateCommit.js +6 -18
  10. package/dist/commands/migratePush.d.ts +1 -0
  11. package/dist/commands/migratePush.js +135 -0
  12. package/dist/commands/migrateUpdate.d.ts +1 -0
  13. package/dist/commands/migrateUpdate.js +147 -0
  14. package/dist/commands/newGenerateAll.d.ts +4 -0
  15. package/dist/commands/newGenerateAll.js +336 -0
  16. package/dist/generators/controllerGenerator.d.ts +43 -19
  17. package/dist/generators/controllerGenerator.js +547 -329
  18. package/dist/generators/domainLayerGenerator.d.ts +21 -0
  19. package/dist/generators/domainLayerGenerator.js +276 -0
  20. package/dist/generators/dtoGenerator.d.ts +21 -0
  21. package/dist/generators/dtoGenerator.js +518 -0
  22. package/dist/generators/newControllerGenerator.d.ts +55 -0
  23. package/dist/generators/newControllerGenerator.js +644 -0
  24. package/dist/generators/newServiceGenerator.d.ts +19 -0
  25. package/dist/generators/newServiceGenerator.js +266 -0
  26. package/dist/generators/newStoreGenerator.d.ts +39 -0
  27. package/dist/generators/newStoreGenerator.js +408 -0
  28. package/dist/generators/newTemplateGenerator.d.ts +29 -0
  29. package/dist/generators/newTemplateGenerator.js +510 -0
  30. package/dist/generators/serviceGenerator.d.ts +16 -51
  31. package/dist/generators/serviceGenerator.js +167 -586
  32. package/dist/generators/storeGenerator.d.ts +35 -32
  33. package/dist/generators/storeGenerator.js +291 -238
  34. package/dist/generators/storeGeneratorV2.d.ts +31 -0
  35. package/dist/generators/storeGeneratorV2.js +190 -0
  36. package/dist/generators/templateGenerator.d.ts +21 -21
  37. package/dist/generators/templateGenerator.js +393 -268
  38. package/dist/generators/templates/appTemplates.d.ts +3 -1
  39. package/dist/generators/templates/appTemplates.js +15 -10
  40. package/dist/generators/templates/data/appYamlTemplate +5 -2
  41. package/dist/generators/templates/data/cursorRulesTemplate +315 -221
  42. package/dist/generators/templates/data/frontendScriptTemplate +76 -47
  43. package/dist/generators/templates/data/mainViewTemplate +1 -1
  44. package/dist/generators/templates/data/systemTsTemplate +5 -0
  45. package/dist/generators/templates/index.d.ts +0 -3
  46. package/dist/generators/templates/index.js +0 -3
  47. package/dist/generators/templates/newStoreTemplates.d.ts +5 -0
  48. package/dist/generators/templates/newStoreTemplates.js +141 -0
  49. package/dist/generators/templates/storeTemplates.d.ts +1 -5
  50. package/dist/generators/templates/storeTemplates.js +102 -219
  51. package/dist/generators/templates/viewTemplates.js +1 -1
  52. package/dist/generators/useCaseGenerator.d.ts +13 -0
  53. package/dist/generators/useCaseGenerator.js +188 -0
  54. package/dist/types/configTypes.d.ts +148 -0
  55. package/dist/types/configTypes.js +10 -0
  56. package/dist/utils/childEntityUtils.d.ts +18 -0
  57. package/dist/utils/childEntityUtils.js +78 -0
  58. package/dist/utils/commandUtils.d.ts +43 -0
  59. package/dist/utils/commandUtils.js +124 -0
  60. package/dist/utils/commitUtils.d.ts +4 -1
  61. package/dist/utils/constants.d.ts +10 -0
  62. package/dist/utils/constants.js +13 -1
  63. package/dist/utils/diResolver.d.ts +32 -0
  64. package/dist/utils/diResolver.js +204 -0
  65. package/dist/utils/new_parts_of_migrationUtils.d.ts +0 -0
  66. package/dist/utils/new_parts_of_migrationUtils.js +164 -0
  67. package/dist/utils/typeUtils.d.ts +19 -0
  68. package/dist/utils/typeUtils.js +70 -0
  69. package/package.json +7 -3
@@ -0,0 +1,510 @@
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.NewTemplateGenerator = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const yaml_1 = require("yaml");
40
+ const generationRegistry_1 = require("../utils/generationRegistry");
41
+ const colors_1 = require("../utils/colors");
42
+ const configTypes_1 = require("../types/configTypes");
43
+ const childEntityUtils_1 = require("../utils/childEntityUtils");
44
+ class NewTemplateGenerator {
45
+ constructor() {
46
+ this.valueObjects = {};
47
+ }
48
+ /**
49
+ * Convert a route prefix like "/invoice/:invoiceId/items" into a
50
+ * template-ready path like "/invoice/{{ invoiceId }}/items".
51
+ */
52
+ prefixToTemplatePath(prefix) {
53
+ return prefix.replace(/:([a-zA-Z_]\w*)/g, '{{ $1 }}');
54
+ }
55
+ /**
56
+ * Replace a single path param in prefix with a template expression (e.g. for list: item.id, for detail: id).
57
+ */
58
+ prefixWithParam(prefix, paramName, templateExpr) {
59
+ return prefix.replace(new RegExp(':' + paramName + '(?=/|$)'), templateExpr);
60
+ }
61
+ renderListTemplate(modelName, viewName, fields, basePath, withChildChildren) {
62
+ const fieldHeaders = fields
63
+ .filter(([name]) => name !== 'id')
64
+ .slice(0, 5)
65
+ .map(([name]) => ` <th>${this.capitalize(name)}</th>`)
66
+ .join('\n');
67
+ const fieldCells = fields
68
+ .filter(([name]) => name !== 'id')
69
+ .slice(0, 5)
70
+ .map(([name, config]) => {
71
+ const voConfig = this.valueObjects[this.capitalize((config.type || 'string'))];
72
+ if (voConfig) {
73
+ const parts = Object.keys(voConfig.fields)
74
+ .map(sub => `{{ item.${name}.${sub} }}`)
75
+ .join(' ');
76
+ return ` <td>${parts}</td>`;
77
+ }
78
+ return ` <td>{{ item.${name} }}</td>`;
79
+ })
80
+ .join('\n');
81
+ const childLinkHeaders = (withChildChildren || [])
82
+ .map(child => ` <th>${child.childEntityName}</th>`)
83
+ .join('\n');
84
+ const childLinkCells = (withChildChildren || [])
85
+ .map(child => {
86
+ const childPath = child.childWebPrefix
87
+ ? this.prefixWithParam(child.childWebPrefix, child.parentIdField, '{{ item.id }}')
88
+ : '#';
89
+ return ` <td><a href="${childPath}" class="btn btn-sm btn-outline-secondary">Items</a></td>`;
90
+ })
91
+ .join('\n');
92
+ const childHeaderBlock = childLinkHeaders ? '\n' + childLinkHeaders : '';
93
+ const childCellBlock = childLinkCells ? '\n' + childLinkCells : '';
94
+ return `<!-- @template name="${viewName}" -->
95
+ <div class="container mt-4">
96
+ <h1>${modelName} List</h1>
97
+
98
+ <div class="mb-3">
99
+ <a href="${basePath}/create" class="btn btn-primary">Create New ${modelName}</a>
100
+ </div>
101
+
102
+ <table class="table table-striped">
103
+ <thead>
104
+ <tr>
105
+ ${fieldHeaders}
106
+ <th>Actions</th>${childHeaderBlock}
107
+ </tr>
108
+ </thead>
109
+ <tbody x-for="items" x-row="item">
110
+ <tr>
111
+ ${fieldCells}
112
+ <td>
113
+ <a href="${basePath}/{{ item.id }}" class="btn btn-sm btn-info">View</a>
114
+ <a href="${basePath}/{{ item.id }}/edit" class="btn btn-sm btn-warning">Edit</a>
115
+ </td>${childCellBlock}
116
+ </tr>
117
+ </tbody>
118
+ </table>
119
+
120
+ <div x-if="total > limit">
121
+ <nav>
122
+ <ul class="pagination">
123
+ <!-- Pagination controls -->
124
+ </ul>
125
+ </nav>
126
+ </div>
127
+ </div>`;
128
+ }
129
+ renderChildTableSection(child, parentIdTemplateExpr) {
130
+ const childVar = child.childEntityName.charAt(0).toLowerCase() + child.childEntityName.slice(1);
131
+ const childItemsKey = `${childVar}Items`;
132
+ const childBasePath = child.childWebPrefix
133
+ ? this.prefixWithParam(child.childWebPrefix, child.parentIdField, parentIdTemplateExpr)
134
+ : '';
135
+ const fieldEntries = Object.entries(child.childFields).filter(([name]) => name !== 'id').slice(0, 5);
136
+ const headers = fieldEntries.map(([name]) => ` <th>${this.capitalize(name)}</th>`).join('\n');
137
+ const cells = fieldEntries.map(([name, config]) => {
138
+ const voConfig = this.valueObjects[this.capitalize(((config === null || config === void 0 ? void 0 : config.type) || 'string'))];
139
+ if (voConfig) {
140
+ const parts = Object.keys(voConfig.fields)
141
+ .map(sub => `{{ childItem.${name}.${sub} }}`)
142
+ .join(' ');
143
+ return ` <td>${parts}</td>`;
144
+ }
145
+ return ` <td>{{ childItem.${name} }}</td>`;
146
+ }).join('\n');
147
+ const addLink = childBasePath
148
+ ? ` <div class="mb-3">
149
+ <a href="${childBasePath}/create" class="btn btn-primary btn-sm">Add ${child.childEntityName}</a>
150
+ </div>`
151
+ : '';
152
+ const actionLinks = childBasePath
153
+ ? ` <td>
154
+ <a href="${childBasePath}/{{ childItem.id }}" class="btn btn-sm btn-info">View</a>
155
+ <a href="${childBasePath}/{{ childItem.id }}/edit" class="btn btn-sm btn-warning">Edit</a>
156
+ </td>`
157
+ : ' <td></td>';
158
+ return `
159
+ <h2 class="mt-4">${child.childEntityName} List</h2>
160
+ ${addLink}
161
+ <table class="table table-striped">
162
+ <thead>
163
+ <tr>
164
+ ${headers}
165
+ <th>Actions</th>
166
+ </tr>
167
+ </thead>
168
+ <tbody x-for="${childItemsKey}" x-row="childItem">
169
+ <tr>
170
+ ${cells}
171
+ ${actionLinks}
172
+ </tr>
173
+ </tbody>
174
+ </table>`;
175
+ }
176
+ renderDetailTemplate(modelName, viewName, fields, basePath, withChildChildren) {
177
+ const fieldRows = fields
178
+ .map(([name, config]) => {
179
+ const voConfig = this.valueObjects[this.capitalize((config.type || 'string'))];
180
+ if (voConfig) {
181
+ const parts = Object.keys(voConfig.fields)
182
+ .map(sub => `{{ ${name}.${sub} }}`)
183
+ .join(' ');
184
+ return ` <div class="row mb-2">
185
+ <div class="col-4"><strong>${this.capitalize(name)}:</strong></div>
186
+ <div class="col-8">${parts}</div>
187
+ </div>`;
188
+ }
189
+ return ` <div class="row mb-2">
190
+ <div class="col-4"><strong>${this.capitalize(name)}:</strong></div>
191
+ <div class="col-8">{{ ${name} }}</div>
192
+ </div>`;
193
+ })
194
+ .join('\n');
195
+ const childSections = (withChildChildren || [])
196
+ .map(child => this.renderChildTableSection(child, '{{ id }}'))
197
+ .join('');
198
+ return `<!-- @template name="${viewName}" -->
199
+ <div class="container mt-4">
200
+ <h1>${modelName} Details</h1>
201
+
202
+ <div class="card">
203
+ <div class="card-body">
204
+ ${fieldRows}
205
+ </div>
206
+ </div>
207
+
208
+ <div class="mt-3">
209
+ <a href="${basePath}/{{ id }}/edit" class="btn btn-warning">Edit</a>
210
+ <a href="${basePath}" class="btn btn-secondary">Back to List</a>
211
+ </div>${childSections}
212
+ </div>`;
213
+ }
214
+ renderCreateTemplate(modelName, viewName, fields, basePath, onSuccess, onError, enumValuesMap = {}) {
215
+ const safeFields = fields.filter(([name, config]) => name !== 'id' && !config.auto);
216
+ const formFields = safeFields
217
+ .map(([name, config]) => this.renderFormField(name, config, enumValuesMap[name] || []))
218
+ .join('\n');
219
+ const fieldTypesJson = JSON.stringify(safeFields.reduce((acc, [name, config]) => {
220
+ const capitalizedType = this.capitalize(config.type || 'string');
221
+ const voConfig = this.valueObjects[capitalizedType];
222
+ if (voConfig) {
223
+ for (const [subName, subConfig] of Object.entries(voConfig.fields)) {
224
+ if (typeof subConfig === 'object' && 'values' in subConfig) {
225
+ acc[`${name}.${subName}`] = 'enum';
226
+ }
227
+ else {
228
+ acc[`${name}.${subName}`] = subConfig.type || 'string';
229
+ }
230
+ }
231
+ }
232
+ else {
233
+ acc[name] = config.type || 'string';
234
+ }
235
+ return acc;
236
+ }, {}));
237
+ // Build strategy array from onSuccess/onError
238
+ const strategies = [];
239
+ if (onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess.toast)
240
+ strategies.push('toast');
241
+ if (onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess.back)
242
+ strategies.push('back');
243
+ if (onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess.redirect)
244
+ strategies.push('redirect');
245
+ const strategyAttr = strategies.length > 0
246
+ ? `data-strategy='${JSON.stringify(strategies)}'`
247
+ : '';
248
+ const redirectAttr = (onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess.redirect)
249
+ ? `data-redirect="${this.prefixToTemplatePath(onSuccess.redirect)}"`
250
+ : '';
251
+ return `<!-- @template name="${viewName}" -->
252
+ <div class="container mt-4">
253
+ <h1>Create ${modelName}</h1>
254
+
255
+ <form method="POST" action="${basePath}/create" ${strategyAttr} ${redirectAttr} data-entity-name="${modelName}" data-field-types='${fieldTypesJson}'>
256
+ ${formFields}
257
+
258
+ <div class="d-flex gap-2">
259
+ <button type="submit" class="btn btn-primary">Create</button>
260
+ <a href="${basePath}" class="btn btn-secondary">Cancel</a>
261
+ </div>
262
+ </form>
263
+ </div>`;
264
+ }
265
+ renderEditTemplate(modelName, viewName, fields, basePath, onSuccess, onError, enumValuesMap = {}) {
266
+ const safeFields = fields.filter(([name, config]) => name !== 'id' && !config.auto);
267
+ const formFields = safeFields
268
+ .map(([name, config]) => this.renderFormField(name, config, enumValuesMap[name] || [], true))
269
+ .join('\n');
270
+ const fieldTypesJson = JSON.stringify(safeFields.reduce((acc, [name, config]) => {
271
+ const capitalizedType = this.capitalize(config.type || 'string');
272
+ const voConfig = this.valueObjects[capitalizedType];
273
+ if (voConfig) {
274
+ for (const [subName, subConfig] of Object.entries(voConfig.fields)) {
275
+ if (typeof subConfig === 'object' && 'values' in subConfig) {
276
+ acc[`${name}.${subName}`] = 'enum';
277
+ }
278
+ else {
279
+ acc[`${name}.${subName}`] = subConfig.type || 'string';
280
+ }
281
+ }
282
+ }
283
+ else {
284
+ acc[name] = config.type || 'string';
285
+ }
286
+ return acc;
287
+ }, {}));
288
+ // Build strategy array from onSuccess/onError
289
+ const strategies = [];
290
+ if (onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess.toast)
291
+ strategies.push('toast');
292
+ if (onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess.back)
293
+ strategies.push('back');
294
+ const strategyAttr = strategies.length > 0
295
+ ? `data-strategy='${JSON.stringify(strategies)}'`
296
+ : '';
297
+ return `<!-- @template name="${viewName}" -->
298
+ <div class="container mt-4">
299
+ <h1>Edit ${modelName}</h1>
300
+
301
+ <form method="POST" action="${basePath}/{{ id }}/edit" ${strategyAttr} data-entity-name="${modelName}" data-field-types='${fieldTypesJson}'>
302
+ ${formFields}
303
+
304
+ <div class="d-flex gap-2">
305
+ <button type="submit" class="btn btn-primary">Update</button>
306
+ <a href="${basePath}/{{ id }}" class="btn btn-secondary">Cancel</a>
307
+ </div>
308
+ </form>
309
+ </div>`;
310
+ }
311
+ getInputType(fieldType) {
312
+ switch (fieldType) {
313
+ case 'string': return 'text';
314
+ case 'number':
315
+ case 'integer':
316
+ case 'float':
317
+ case 'decimal':
318
+ case 'money':
319
+ case 'id': return 'number';
320
+ case 'datetime':
321
+ case 'date': return 'datetime-local';
322
+ default: return 'text';
323
+ }
324
+ }
325
+ renderValueObjectField(name, label, voConfig, required, isEdit) {
326
+ const subFields = Object.entries(voConfig.fields);
327
+ const columns = subFields.map(([subName, subConfig]) => {
328
+ const fullName = `${name}.${subName}`;
329
+ const subLabel = this.capitalize(subName);
330
+ if (typeof subConfig === 'object' && 'values' in subConfig) {
331
+ const uniqueValues = [...new Set(subConfig.values)];
332
+ const options = uniqueValues.map(v => {
333
+ const sel = isEdit ? ` {{ ${name}.${subName} === '${v}' ? 'selected' : '' }}` : '';
334
+ return ` <option value="${v}"${sel}>${v}</option>`;
335
+ }).join('\n');
336
+ return ` <div class="col-auto">
337
+ <select class="form-select" id="${fullName}" name="${fullName}" ${required}>
338
+ <option value="">-- ${subLabel} --</option>
339
+ ${options}
340
+ </select>
341
+ </div>`;
342
+ }
343
+ else {
344
+ const type = this.getInputType(subConfig.type);
345
+ const value = isEdit ? ` value="{{ ${name}.${subName} || '' }}"` : '';
346
+ return ` <div class="col">
347
+ <input type="${type}" class="form-control" id="${fullName}" name="${fullName}" placeholder="${subLabel}"${value} ${required}>
348
+ </div>`;
349
+ }
350
+ }).join('\n');
351
+ return ` <div class="mb-3">
352
+ <label class="form-label">${label}</label>
353
+ <div class="row g-2">
354
+ ${columns}
355
+ </div>
356
+ </div>`;
357
+ }
358
+ renderFormField(name, config, enumValues = [], isEdit = false) {
359
+ const required = config.required ? 'required' : '';
360
+ const label = this.capitalize(name);
361
+ const fieldType = (config.type || 'string').toLowerCase();
362
+ const capitalizedType = this.capitalize(fieldType);
363
+ const voConfig = this.valueObjects[capitalizedType];
364
+ if (voConfig) {
365
+ return this.renderValueObjectField(name, label, voConfig, required, isEdit);
366
+ }
367
+ switch (fieldType) {
368
+ case 'boolean':
369
+ case 'bool': {
370
+ const checked = isEdit ? ` {{ ${name} ? 'checked' : '' }}` : '';
371
+ return ` <div class="mb-3">
372
+ <div class="form-check">
373
+ <input type="checkbox" class="form-check-input" id="${name}" name="${name}" value="true"${checked} ${required}>
374
+ <label for="${name}" class="form-check-label">${label}</label>
375
+ </div>
376
+ </div>`;
377
+ }
378
+ case 'enum': {
379
+ if (enumValues.length > 0) {
380
+ const options = enumValues.map(v => {
381
+ const sel = isEdit ? ` {{ ${name} === '${v}' ? 'selected' : '' }}` : '';
382
+ return ` <option value="${v}"${sel}>${this.capitalize(v)}</option>`;
383
+ }).join('\n');
384
+ return ` <div class="mb-3">
385
+ <label for="${name}" class="form-label">${label}</label>
386
+ <select class="form-select" id="${name}" name="${name}" ${required}>
387
+ <option value="">-- Select ${label} --</option>
388
+ ${options}
389
+ </select>
390
+ </div>`;
391
+ }
392
+ const value = isEdit ? ` value="{{ ${name} || '' }}"` : '';
393
+ return ` <div class="mb-3">
394
+ <label for="${name}" class="form-label">${label}</label>
395
+ <input type="text" class="form-control" id="${name}" name="${name}"${value} ${required}>
396
+ </div>`;
397
+ }
398
+ default: {
399
+ const type = this.getInputType(config.type);
400
+ const value = isEdit ? ` value="{{ ${name} || '' }}"` : '';
401
+ return ` <div class="mb-3">
402
+ <label for="${name}" class="form-label">${label}</label>
403
+ <input type="${type}" class="form-control" id="${name}" name="${name}"${value} ${required}>
404
+ </div>`;
405
+ }
406
+ }
407
+ }
408
+ getEnumValuesMap(config, resourceName) {
409
+ var _a;
410
+ const enumMap = {};
411
+ const aggregate = config.domain.aggregates[resourceName];
412
+ if (!aggregate)
413
+ return enumMap;
414
+ for (const [fieldName, fieldConfig] of Object.entries(aggregate.fields)) {
415
+ if (fieldConfig.type === 'enum' && fieldConfig.values) {
416
+ enumMap[fieldName] = fieldConfig.values;
417
+ }
418
+ }
419
+ const modelUseCases = config.useCases[resourceName];
420
+ if (modelUseCases) {
421
+ for (const useCase of Object.values(modelUseCases)) {
422
+ if ((_a = useCase.input) === null || _a === void 0 ? void 0 : _a.filters) {
423
+ for (const [filterName, filterConfig] of Object.entries(useCase.input.filters)) {
424
+ if (filterConfig.enum && !enumMap[filterName]) {
425
+ enumMap[filterName] = filterConfig.enum;
426
+ }
427
+ }
428
+ }
429
+ }
430
+ }
431
+ return enumMap;
432
+ }
433
+ capitalize(str) {
434
+ return str.charAt(0).toUpperCase() + str.slice(1);
435
+ }
436
+ generateFromConfig(config) {
437
+ const result = {};
438
+ this.valueObjects = config.domain.valueObjects || {};
439
+ if (!config.web) {
440
+ return result;
441
+ }
442
+ Object.entries(config.web).forEach(([resourceName, resourceConfig]) => {
443
+ const aggregate = config.domain.aggregates[resourceName];
444
+ if (!aggregate) {
445
+ console.warn(`Warning: No aggregate found for resource ${resourceName}`);
446
+ return;
447
+ }
448
+ const fields = Object.entries(aggregate.fields);
449
+ const enumValuesMap = this.getEnumValuesMap(config, resourceName);
450
+ const basePath = this.prefixToTemplatePath(resourceConfig.prefix);
451
+ const withChildChildren = (0, childEntityUtils_1.getChildrenOfParent)(config, resourceName);
452
+ resourceConfig.pages.forEach(page => {
453
+ var _a;
454
+ if (!page.view)
455
+ return;
456
+ // Determine template type from path and method
457
+ if (page.method === 'POST') {
458
+ // Skip POST endpoints - they don't need templates
459
+ return;
460
+ }
461
+ const useCaseWithChild = (() => {
462
+ var _a, _b;
463
+ if (!page.useCase)
464
+ return false;
465
+ const [model, action] = page.useCase.split(':');
466
+ return ((_b = (_a = config.useCases[model]) === null || _a === void 0 ? void 0 : _a[action]) === null || _b === void 0 ? void 0 : _b.withChild) === true;
467
+ })();
468
+ const childrenForTemplate = useCaseWithChild && withChildChildren.length > 0 ? withChildChildren : undefined;
469
+ if (page.path === '/' && ((_a = page.useCase) === null || _a === void 0 ? void 0 : _a.endsWith(':list'))) {
470
+ result[page.view] = this.renderListTemplate(resourceName, page.view, fields, basePath, childrenForTemplate);
471
+ }
472
+ else if (page.path.includes(':id') && !page.path.includes('edit')) {
473
+ result[page.view] = this.renderDetailTemplate(resourceName, page.view, fields, basePath, childrenForTemplate);
474
+ }
475
+ else if (page.path.includes('/create')) {
476
+ // Find corresponding POST endpoint for onSuccess/onError
477
+ const postEndpoint = resourceConfig.pages.find(p => p.path === page.path && p.method === 'POST');
478
+ result[page.view] = this.renderCreateTemplate(resourceName, page.view, fields, basePath, postEndpoint === null || postEndpoint === void 0 ? void 0 : postEndpoint.onSuccess, postEndpoint === null || postEndpoint === void 0 ? void 0 : postEndpoint.onError, enumValuesMap);
479
+ }
480
+ else if (page.path.includes('edit')) {
481
+ // Find corresponding POST endpoint for onSuccess/onError
482
+ const postEndpoint = resourceConfig.pages.find(p => p.path === page.path && p.method === 'POST');
483
+ result[page.view] = this.renderEditTemplate(resourceName, page.view, fields, basePath, postEndpoint === null || postEndpoint === void 0 ? void 0 : postEndpoint.onSuccess, postEndpoint === null || postEndpoint === void 0 ? void 0 : postEndpoint.onError, enumValuesMap);
484
+ }
485
+ });
486
+ });
487
+ return result;
488
+ }
489
+ generateFromYamlFile(yamlFilePath) {
490
+ const yamlContent = fs.readFileSync(yamlFilePath, 'utf8');
491
+ const config = (0, yaml_1.parse)(yamlContent);
492
+ if (!(0, configTypes_1.isNewModuleConfig)(config)) {
493
+ throw new Error('Configuration does not match new module format. Expected domain/useCases/web structure.');
494
+ }
495
+ return this.generateFromConfig(config);
496
+ }
497
+ async generateAndSaveFiles(yamlFilePath, moduleDir, opts) {
498
+ const templatesByName = this.generateFromYamlFile(yamlFilePath);
499
+ const viewsDir = path.join(moduleDir, 'views');
500
+ fs.mkdirSync(viewsDir, { recursive: true });
501
+ for (const [name, content] of Object.entries(templatesByName)) {
502
+ const filePath = path.join(viewsDir, `${name}.html`);
503
+ // eslint-disable-next-line no-await-in-loop
504
+ await (0, generationRegistry_1.writeGeneratedFile)(filePath, content, { force: !!(opts === null || opts === void 0 ? void 0 : opts.force), skipOnConflict: !!(opts === null || opts === void 0 ? void 0 : opts.skipOnConflict) });
505
+ }
506
+ // eslint-disable-next-line no-console
507
+ console.log('\n' + colors_1.colors.green('Template files generated successfully!') + '\n');
508
+ }
509
+ }
510
+ exports.NewTemplateGenerator = NewTemplateGenerator;
@@ -1,57 +1,22 @@
1
- interface FieldConfig {
2
- name: string;
3
- type: string;
4
- required?: boolean;
5
- unique?: boolean;
6
- auto?: boolean;
7
- displayFields?: string[];
8
- }
9
- interface ActionConfig {
10
- handlers: string[];
11
- }
12
- interface PermissionConfig {
13
- role: string;
14
- actions: string[];
15
- }
16
- interface ModelConfig {
17
- name: string;
18
- fields: FieldConfig[];
19
- }
20
- type ModuleConfig = {
21
- models?: ModelConfig[];
22
- actions?: Record<string, ActionConfig>;
23
- permissions?: PermissionConfig[];
24
- };
1
+ import { ModuleConfig } from '../types/configTypes';
25
2
  export declare class ServiceGenerator {
26
- private availableModels;
27
- private setAvailableModels;
28
- private isRelationshipField;
29
- private getForeignKeyFieldName;
30
- private hasPermissions;
31
- private getActionPermissions;
32
- private generatePermissionCheck;
33
- private getResourceIdForAction;
34
- private generateMethodParams;
35
- private generateReturnType;
36
- private generateMethodImplementation;
37
- private extractFunctionName;
38
- private getMethodCallParams;
39
- private sortFieldsByRequired;
40
- private generateConstructorArgs;
41
- private generateRelationshipLoading;
42
- private generateUpdateSetterCalls;
43
- private replaceTemplateVars;
44
- private getServiceMethodName;
45
- private generateHandlerMethod;
46
- generateServiceForModel(model: ModelConfig, moduleName: string, moduleConfig: ModuleConfig, hasGlobalPermissions: boolean): string;
47
- generateService(moduleName: string, moduleConfig: ModuleConfig, hasGlobalPermissions: boolean): string;
48
- private generateForeignStoreImports;
49
- private generateForeignStoreConstructorParams;
50
- private generateCustomImports;
3
+ private availableAggregates;
4
+ private mapType;
5
+ private generateListHandler;
6
+ private generateGetHandler;
7
+ private generateCreateHandler;
8
+ private generateUpdateHandler;
9
+ private generateDeleteHandler;
10
+ private generateDefaultHandlerMethod;
11
+ private generateCustomHandlerMethod;
12
+ private collectHandlers;
13
+ private generateListByParentMethod;
14
+ private generateGetResourceOwnerMethod;
15
+ private generateService;
16
+ generateFromConfig(config: ModuleConfig): Record<string, string>;
51
17
  generateFromYamlFile(yamlFilePath: string): Record<string, string>;
52
- generateAndSaveFiles(yamlFilePath?: string, outputDir?: string, opts?: {
18
+ generateAndSaveFiles(yamlFilePath: string, moduleDir: string, opts?: {
53
19
  force?: boolean;
54
20
  skipOnConflict?: boolean;
55
21
  }): Promise<void>;
56
22
  }
57
- export {};