@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.
- package/CHANGELOG.md +8 -289
- package/README.md +623 -427
- package/dist/cli.js +2 -1
- package/dist/commands/commit.js +25 -42
- package/dist/commands/createApp.js +1 -0
- package/dist/commands/createModule.js +151 -45
- package/dist/commands/diff.js +27 -40
- package/dist/commands/generateAll.js +141 -291
- package/dist/commands/migrateCommit.js +6 -18
- package/dist/commands/migratePush.d.ts +1 -0
- package/dist/commands/migratePush.js +135 -0
- package/dist/commands/migrateUpdate.d.ts +1 -0
- package/dist/commands/migrateUpdate.js +147 -0
- package/dist/commands/newGenerateAll.d.ts +4 -0
- package/dist/commands/newGenerateAll.js +336 -0
- package/dist/generators/controllerGenerator.d.ts +43 -19
- package/dist/generators/controllerGenerator.js +547 -329
- package/dist/generators/domainLayerGenerator.d.ts +21 -0
- package/dist/generators/domainLayerGenerator.js +276 -0
- package/dist/generators/dtoGenerator.d.ts +21 -0
- package/dist/generators/dtoGenerator.js +518 -0
- package/dist/generators/newControllerGenerator.d.ts +55 -0
- package/dist/generators/newControllerGenerator.js +644 -0
- package/dist/generators/newServiceGenerator.d.ts +19 -0
- package/dist/generators/newServiceGenerator.js +266 -0
- package/dist/generators/newStoreGenerator.d.ts +39 -0
- package/dist/generators/newStoreGenerator.js +408 -0
- package/dist/generators/newTemplateGenerator.d.ts +29 -0
- package/dist/generators/newTemplateGenerator.js +510 -0
- package/dist/generators/serviceGenerator.d.ts +16 -51
- package/dist/generators/serviceGenerator.js +167 -586
- package/dist/generators/storeGenerator.d.ts +35 -32
- package/dist/generators/storeGenerator.js +291 -238
- package/dist/generators/storeGeneratorV2.d.ts +31 -0
- package/dist/generators/storeGeneratorV2.js +190 -0
- package/dist/generators/templateGenerator.d.ts +21 -21
- package/dist/generators/templateGenerator.js +393 -268
- package/dist/generators/templates/appTemplates.d.ts +3 -1
- package/dist/generators/templates/appTemplates.js +15 -10
- package/dist/generators/templates/data/appYamlTemplate +5 -2
- package/dist/generators/templates/data/cursorRulesTemplate +315 -221
- package/dist/generators/templates/data/frontendScriptTemplate +76 -47
- package/dist/generators/templates/data/mainViewTemplate +1 -1
- package/dist/generators/templates/data/systemTsTemplate +5 -0
- package/dist/generators/templates/index.d.ts +0 -3
- package/dist/generators/templates/index.js +0 -3
- package/dist/generators/templates/newStoreTemplates.d.ts +5 -0
- package/dist/generators/templates/newStoreTemplates.js +141 -0
- package/dist/generators/templates/storeTemplates.d.ts +1 -5
- package/dist/generators/templates/storeTemplates.js +102 -219
- package/dist/generators/templates/viewTemplates.js +1 -1
- package/dist/generators/useCaseGenerator.d.ts +13 -0
- package/dist/generators/useCaseGenerator.js +188 -0
- package/dist/types/configTypes.d.ts +148 -0
- package/dist/types/configTypes.js +10 -0
- package/dist/utils/childEntityUtils.d.ts +18 -0
- package/dist/utils/childEntityUtils.js +78 -0
- package/dist/utils/commandUtils.d.ts +43 -0
- package/dist/utils/commandUtils.js +124 -0
- package/dist/utils/commitUtils.d.ts +4 -1
- package/dist/utils/constants.d.ts +10 -0
- package/dist/utils/constants.js +13 -1
- package/dist/utils/diResolver.d.ts +32 -0
- package/dist/utils/diResolver.js +204 -0
- package/dist/utils/new_parts_of_migrationUtils.d.ts +0 -0
- package/dist/utils/new_parts_of_migrationUtils.js +164 -0
- package/dist/utils/typeUtils.d.ts +19 -0
- package/dist/utils/typeUtils.js +70 -0
- package/package.json +7 -3
|
@@ -0,0 +1,408 @@
|
|
|
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.NewStoreGenerator = 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
|
+
const configTypes_1 = require("../types/configTypes");
|
|
43
|
+
const childEntityUtils_1 = require("../utils/childEntityUtils");
|
|
44
|
+
const newStoreTemplates_1 = require("./templates/newStoreTemplates");
|
|
45
|
+
class NewStoreGenerator {
|
|
46
|
+
constructor() {
|
|
47
|
+
// Maps YAML types to TypeScript types for Row interface (database representation)
|
|
48
|
+
this.rowTypeMapping = {
|
|
49
|
+
string: 'string',
|
|
50
|
+
number: 'number',
|
|
51
|
+
integer: 'number',
|
|
52
|
+
decimal: 'number',
|
|
53
|
+
boolean: 'boolean',
|
|
54
|
+
datetime: 'string', // MySQL returns datetime as string
|
|
55
|
+
date: 'string', // MySQL returns date as string
|
|
56
|
+
id: 'number', // Foreign key references are numbers
|
|
57
|
+
json: 'string', // JSON stored as string in MySQL
|
|
58
|
+
array: 'string', // Arrays serialized as string
|
|
59
|
+
object: 'string', // Objects serialized as string
|
|
60
|
+
enum: 'string' // Enum values stored as strings
|
|
61
|
+
};
|
|
62
|
+
this.availableValueObjects = new Map();
|
|
63
|
+
}
|
|
64
|
+
capitalize(str) {
|
|
65
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
66
|
+
}
|
|
67
|
+
isValueObjectType(fieldType) {
|
|
68
|
+
// Check if the type matches a known value object (case-insensitive)
|
|
69
|
+
const capitalizedType = this.capitalize(fieldType);
|
|
70
|
+
return this.availableValueObjects.has(capitalizedType);
|
|
71
|
+
}
|
|
72
|
+
getValueObjectName(fieldType) {
|
|
73
|
+
return this.capitalize(fieldType);
|
|
74
|
+
}
|
|
75
|
+
getValueObjectConfig(fieldType) {
|
|
76
|
+
return this.availableValueObjects.get(this.getValueObjectName(fieldType));
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Sort fields the same way as the domain layer generator:
|
|
80
|
+
* Required fields first, then optional fields.
|
|
81
|
+
* This ensures rowToModel parameter order matches entity constructor.
|
|
82
|
+
*/
|
|
83
|
+
sortFieldsForConstructor(fields) {
|
|
84
|
+
return [...fields].sort((a, b) => {
|
|
85
|
+
const aRequired = a[1].required !== false && !a[1].auto;
|
|
86
|
+
const bRequired = b[1].required !== false && !b[1].auto;
|
|
87
|
+
if (aRequired === bRequired)
|
|
88
|
+
return 0;
|
|
89
|
+
return aRequired ? -1 : 1;
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Gets the type name for a value object field (for casting).
|
|
94
|
+
* For enum fields, returns the generated type name (e.g., BreedName).
|
|
95
|
+
* For other fields, returns the basic TypeScript type.
|
|
96
|
+
*/
|
|
97
|
+
getValueObjectFieldTypeName(voName, voConfig) {
|
|
98
|
+
const fields = Object.entries(voConfig.fields);
|
|
99
|
+
// Look for enum fields - they get generated type names
|
|
100
|
+
for (const [fieldName, fieldConfig] of fields) {
|
|
101
|
+
if (typeof fieldConfig === 'object' && 'values' in fieldConfig) {
|
|
102
|
+
// This is an enum field, return the generated type name
|
|
103
|
+
return `${voName}${this.capitalize(fieldName)}`;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
mapTypeToRowType(yamlType) {
|
|
109
|
+
// Value objects are stored as strings in the database
|
|
110
|
+
if (this.isValueObjectType(yamlType)) {
|
|
111
|
+
return 'string';
|
|
112
|
+
}
|
|
113
|
+
return this.rowTypeMapping[yamlType] || 'string';
|
|
114
|
+
}
|
|
115
|
+
replaceTemplateVars(template, variables) {
|
|
116
|
+
let result = template;
|
|
117
|
+
Object.entries(variables).forEach(([key, value]) => {
|
|
118
|
+
const regex = new RegExp(`{{${key}}}`, 'g');
|
|
119
|
+
result = result.replace(regex, value);
|
|
120
|
+
});
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
generateRowFields(fields, childInfo) {
|
|
124
|
+
const result = [];
|
|
125
|
+
const ownerOrParentField = childInfo ? childInfo.parentIdField : 'ownerId';
|
|
126
|
+
result.push(` ${ownerOrParentField}: number;`);
|
|
127
|
+
fields.forEach(([fieldName, fieldConfig]) => {
|
|
128
|
+
const tsType = this.mapTypeToRowType(fieldConfig.type);
|
|
129
|
+
const isOptional = !fieldConfig.required;
|
|
130
|
+
result.push(` ${fieldName}${isOptional ? '?' : ''}: ${tsType};`);
|
|
131
|
+
});
|
|
132
|
+
return result.join('\n');
|
|
133
|
+
}
|
|
134
|
+
generateFieldNamesStr(fields, childInfo) {
|
|
135
|
+
const fieldNames = ['id'];
|
|
136
|
+
fieldNames.push(childInfo ? childInfo.parentIdField : 'ownerId');
|
|
137
|
+
fieldNames.push(...fields.map(([name]) => name));
|
|
138
|
+
return fieldNames.map(f => `\\\`${f}\\\``).join(', ');
|
|
139
|
+
}
|
|
140
|
+
generateRowToModelMapping(fields, childInfo) {
|
|
141
|
+
const result = [];
|
|
142
|
+
const ownerOrParentField = childInfo ? childInfo.parentIdField : 'ownerId';
|
|
143
|
+
result.push(` row.${ownerOrParentField}`);
|
|
144
|
+
fields.forEach(([fieldName, fieldConfig]) => {
|
|
145
|
+
const fieldType = fieldConfig.type;
|
|
146
|
+
// Handle datetime/date conversion
|
|
147
|
+
if (fieldType === 'datetime' || fieldType === 'date') {
|
|
148
|
+
result.push(` row.${fieldName} ? new Date(row.${fieldName}) : undefined`);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
// Handle boolean conversion
|
|
152
|
+
if (fieldType === 'boolean') {
|
|
153
|
+
result.push(` Boolean(row.${fieldName})`);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
// Handle value object conversion - deserialize from JSON
|
|
157
|
+
if (this.isValueObjectType(fieldType)) {
|
|
158
|
+
const voName = this.getValueObjectName(fieldType);
|
|
159
|
+
const voConfig = this.getValueObjectConfig(fieldType);
|
|
160
|
+
if (voConfig) {
|
|
161
|
+
const voFields = Object.keys(voConfig.fields);
|
|
162
|
+
if (voFields.length > 1) {
|
|
163
|
+
// Multi-field value object - deserialize from JSON
|
|
164
|
+
const voArgs = voFields.map(f => `parsed.${f}`).join(', ');
|
|
165
|
+
result.push(` row.${fieldName} ? (() => { const parsed = JSON.parse(row.${fieldName}); return new ${voName}(${voArgs}); })() : undefined`);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
else if (voFields.length === 1) {
|
|
169
|
+
// Single-field value object
|
|
170
|
+
const singleFieldType = voConfig.fields[voFields[0]];
|
|
171
|
+
const hasEnumValues = typeof singleFieldType === 'object' && 'values' in singleFieldType;
|
|
172
|
+
if (hasEnumValues) {
|
|
173
|
+
const enumTypeName = this.getValueObjectFieldTypeName(voName, voConfig);
|
|
174
|
+
result.push(` row.${fieldName} ? new ${voName}(row.${fieldName} as ${enumTypeName}) : undefined`);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
result.push(` row.${fieldName} ? new ${voName}(row.${fieldName}) : undefined`);
|
|
178
|
+
}
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// Fallback - try to deserialize from JSON
|
|
183
|
+
result.push(` row.${fieldName} ? new ${voName}(...Object.values(JSON.parse(row.${fieldName}))) : undefined`);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
result.push(` row.${fieldName}`);
|
|
187
|
+
});
|
|
188
|
+
return result.join(',\n');
|
|
189
|
+
}
|
|
190
|
+
generateInsertDataMapping(fields, childInfo) {
|
|
191
|
+
const result = [];
|
|
192
|
+
const ownerOrParentField = childInfo ? childInfo.parentIdField : 'ownerId';
|
|
193
|
+
result.push(` ${ownerOrParentField}: entity.${ownerOrParentField}`);
|
|
194
|
+
fields.forEach(([fieldName, fieldConfig]) => {
|
|
195
|
+
const fieldType = fieldConfig.type;
|
|
196
|
+
// Handle datetime/date - convert Date to MySQL DATETIME format
|
|
197
|
+
if (fieldType === 'datetime' || fieldType === 'date') {
|
|
198
|
+
result.push(` ${fieldName}: entity.${fieldName} ? this.toMySQLDatetime(entity.${fieldName}) : undefined`);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
// Handle value object - serialize to JSON
|
|
202
|
+
if (this.isValueObjectType(fieldType)) {
|
|
203
|
+
const voConfig = this.getValueObjectConfig(fieldType);
|
|
204
|
+
if (voConfig) {
|
|
205
|
+
const voFields = Object.keys(voConfig.fields);
|
|
206
|
+
if (voFields.length > 1) {
|
|
207
|
+
// Multi-field value object - serialize to JSON
|
|
208
|
+
result.push(` ${fieldName}: entity.${fieldName} ? JSON.stringify(entity.${fieldName}) : undefined`);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
else if (voFields.length === 1) {
|
|
212
|
+
// Single-field value object - extract the single field
|
|
213
|
+
result.push(` ${fieldName}: entity.${fieldName}?.${voFields[0]}`);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// Fallback - serialize to JSON
|
|
218
|
+
result.push(` ${fieldName}: entity.${fieldName} ? JSON.stringify(entity.${fieldName}) : undefined`);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
result.push(` ${fieldName}: entity.${fieldName}`);
|
|
222
|
+
});
|
|
223
|
+
return result.join(',\n');
|
|
224
|
+
}
|
|
225
|
+
generateUpdateDataMapping(fields) {
|
|
226
|
+
return fields
|
|
227
|
+
.map(([fieldName, fieldConfig]) => {
|
|
228
|
+
const fieldType = fieldConfig.type;
|
|
229
|
+
// Handle datetime/date - convert Date to MySQL DATETIME format
|
|
230
|
+
if (fieldType === 'datetime' || fieldType === 'date') {
|
|
231
|
+
return ` ${fieldName}: entity.${fieldName} ? this.toMySQLDatetime(entity.${fieldName}) : undefined`;
|
|
232
|
+
}
|
|
233
|
+
// Handle value object - serialize to JSON
|
|
234
|
+
if (this.isValueObjectType(fieldType)) {
|
|
235
|
+
const voConfig = this.getValueObjectConfig(fieldType);
|
|
236
|
+
if (voConfig) {
|
|
237
|
+
const voFields = Object.keys(voConfig.fields);
|
|
238
|
+
if (voFields.length > 1) {
|
|
239
|
+
// Multi-field value object - serialize to JSON
|
|
240
|
+
return ` ${fieldName}: entity.${fieldName} ? JSON.stringify(entity.${fieldName}) : undefined`;
|
|
241
|
+
}
|
|
242
|
+
else if (voFields.length === 1) {
|
|
243
|
+
// Single-field value object - extract the single field
|
|
244
|
+
return ` ${fieldName}: entity.${fieldName}?.${voFields[0]}`;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
// Fallback - serialize to JSON
|
|
248
|
+
return ` ${fieldName}: entity.${fieldName} ? JSON.stringify(entity.${fieldName}) : undefined`;
|
|
249
|
+
}
|
|
250
|
+
return ` ${fieldName}: entity.${fieldName}`;
|
|
251
|
+
})
|
|
252
|
+
.join(',\n');
|
|
253
|
+
}
|
|
254
|
+
generateUpdateFieldsArray(fields) {
|
|
255
|
+
return JSON.stringify(fields.map(([name]) => name));
|
|
256
|
+
}
|
|
257
|
+
generateValueObjectImports(fields) {
|
|
258
|
+
const imports = [];
|
|
259
|
+
fields.forEach(([, fieldConfig]) => {
|
|
260
|
+
if (this.isValueObjectType(fieldConfig.type)) {
|
|
261
|
+
const voName = this.getValueObjectName(fieldConfig.type);
|
|
262
|
+
const voConfig = this.getValueObjectConfig(fieldConfig.type);
|
|
263
|
+
// Import the class
|
|
264
|
+
const importItems = [voName];
|
|
265
|
+
// Also import the type if it's an enum
|
|
266
|
+
if (voConfig) {
|
|
267
|
+
const enumTypeName = this.getValueObjectFieldTypeName(voName, voConfig);
|
|
268
|
+
if (enumTypeName) {
|
|
269
|
+
importItems.push(enumTypeName);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
imports.push(`import { ${importItems.join(', ')} } from '../../domain/valueObjects/${voName}';`);
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
// Dedupe imports
|
|
276
|
+
const uniqueImports = [...new Set(imports)];
|
|
277
|
+
if (uniqueImports.length === 0) {
|
|
278
|
+
return '';
|
|
279
|
+
}
|
|
280
|
+
return '\n' + uniqueImports.join('\n');
|
|
281
|
+
}
|
|
282
|
+
generateGetByParentIdMethod(modelName, fields, childInfo) {
|
|
283
|
+
if (!childInfo)
|
|
284
|
+
return '';
|
|
285
|
+
const fieldList = ['id', childInfo.parentIdField, ...fields.map(([name]) => name)].map(f => '\\`' + f + '\\`').join(', ');
|
|
286
|
+
const parentIdField = childInfo.parentIdField;
|
|
287
|
+
return `
|
|
288
|
+
|
|
289
|
+
async getByParentId(parentId: number): Promise<${modelName}[]> {
|
|
290
|
+
const result = await this.db.query(
|
|
291
|
+
\`SELECT ${fieldList} FROM \\\`\${this.tableName}\\\` WHERE \\\`${parentIdField}\\\` = :parentId AND deleted_at IS NULL\`,
|
|
292
|
+
{ parentId }
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
if (result.success && result.data) {
|
|
296
|
+
return result.data.map((row: ${modelName}Row) => this.rowToModel(row));
|
|
297
|
+
}
|
|
298
|
+
return [];
|
|
299
|
+
}`;
|
|
300
|
+
}
|
|
301
|
+
generateGetResourceOwnerMethod(childInfo) {
|
|
302
|
+
if (childInfo) {
|
|
303
|
+
const parentTable = childInfo.parentTableName;
|
|
304
|
+
const parentIdField = childInfo.parentIdField;
|
|
305
|
+
return `
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Get the owner ID of a resource by its ID (via parent entity).
|
|
309
|
+
* Used for pre-mutation authorization checks.
|
|
310
|
+
*/
|
|
311
|
+
async getResourceOwner(id: number): Promise<number | null> {
|
|
312
|
+
const result = await this.db.query(
|
|
313
|
+
\`SELECT p.ownerId FROM \\\`\${this.tableName}\\\` c INNER JOIN \\\`${parentTable}\\\` p ON p.id = c.\\\`${parentIdField}\\\` WHERE c.id = :id AND c.deleted_at IS NULL\`,
|
|
314
|
+
{ id }
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
if (result.success && result.data && result.data.length > 0) {
|
|
318
|
+
return result.data[0].ownerId as number;
|
|
319
|
+
}
|
|
320
|
+
return null;
|
|
321
|
+
}`;
|
|
322
|
+
}
|
|
323
|
+
return `
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Get the owner ID of a resource by its ID.
|
|
327
|
+
* Used for pre-mutation authorization checks.
|
|
328
|
+
*/
|
|
329
|
+
async getResourceOwner(id: number): Promise<number | null> {
|
|
330
|
+
const result = await this.db.query(
|
|
331
|
+
\`SELECT ownerId FROM \\\`\${this.tableName}\\\` WHERE id = :id AND deleted_at IS NULL\`,
|
|
332
|
+
{ id }
|
|
333
|
+
);
|
|
334
|
+
|
|
335
|
+
if (result.success && result.data && result.data.length > 0) {
|
|
336
|
+
return result.data[0].ownerId as number;
|
|
337
|
+
}
|
|
338
|
+
return null;
|
|
339
|
+
}`;
|
|
340
|
+
}
|
|
341
|
+
generateStore(modelName, aggregateConfig, childInfo) {
|
|
342
|
+
const tableName = modelName.toLowerCase();
|
|
343
|
+
const fields = Object.entries(aggregateConfig.fields);
|
|
344
|
+
// Sort fields for rowToModel to match entity constructor order (required first, optional second)
|
|
345
|
+
const sortedFields = this.sortFieldsForConstructor(fields);
|
|
346
|
+
const variables = {
|
|
347
|
+
ENTITY_NAME: modelName,
|
|
348
|
+
TABLE_NAME: tableName,
|
|
349
|
+
ROW_FIELDS: this.generateRowFields(fields, childInfo),
|
|
350
|
+
FIELD_NAMES: this.generateFieldNamesStr(fields, childInfo),
|
|
351
|
+
ROW_TO_MODEL_MAPPING: this.generateRowToModelMapping(sortedFields, childInfo),
|
|
352
|
+
INSERT_DATA_MAPPING: this.generateInsertDataMapping(fields, childInfo),
|
|
353
|
+
UPDATE_DATA_MAPPING: this.generateUpdateDataMapping(fields),
|
|
354
|
+
UPDATE_FIELDS_ARRAY: this.generateUpdateFieldsArray(fields),
|
|
355
|
+
VALUE_OBJECT_IMPORTS: this.generateValueObjectImports(fields),
|
|
356
|
+
GET_BY_PARENT_ID_METHOD: this.generateGetByParentIdMethod(modelName, fields, childInfo),
|
|
357
|
+
GET_RESOURCE_OWNER_METHOD: this.generateGetResourceOwnerMethod(childInfo)
|
|
358
|
+
};
|
|
359
|
+
const rowInterface = this.replaceTemplateVars(newStoreTemplates_1.newStoreTemplates.rowInterface, variables);
|
|
360
|
+
const storeClass = this.replaceTemplateVars(newStoreTemplates_1.newStoreTemplates.storeClass, variables);
|
|
361
|
+
return this.replaceTemplateVars(newStoreTemplates_1.newStoreFileTemplate, {
|
|
362
|
+
ENTITY_NAME: modelName,
|
|
363
|
+
ROW_INTERFACE: rowInterface,
|
|
364
|
+
STORE_CLASS: storeClass,
|
|
365
|
+
VALUE_OBJECT_IMPORTS: variables.VALUE_OBJECT_IMPORTS
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
generateFromConfig(config) {
|
|
369
|
+
const result = {};
|
|
370
|
+
// First, collect all value object names and configs
|
|
371
|
+
this.availableValueObjects.clear();
|
|
372
|
+
if (config.domain.valueObjects) {
|
|
373
|
+
Object.entries(config.domain.valueObjects).forEach(([name, voConfig]) => {
|
|
374
|
+
this.availableValueObjects.set(name, voConfig);
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
// Generate a store for each aggregate
|
|
378
|
+
const childEntityMap = (0, childEntityUtils_1.buildChildEntityMap)(config);
|
|
379
|
+
if (config.domain.aggregates) {
|
|
380
|
+
Object.entries(config.domain.aggregates).forEach(([modelName, aggregateConfig]) => {
|
|
381
|
+
const childInfo = childEntityMap.get(modelName);
|
|
382
|
+
result[modelName] = this.generateStore(modelName, aggregateConfig, childInfo);
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
return result;
|
|
386
|
+
}
|
|
387
|
+
generateFromYamlFile(yamlFilePath) {
|
|
388
|
+
const yamlContent = fs.readFileSync(yamlFilePath, 'utf8');
|
|
389
|
+
const config = (0, yaml_1.parse)(yamlContent);
|
|
390
|
+
if (!(0, configTypes_1.isNewModuleConfig)(config)) {
|
|
391
|
+
throw new Error('Configuration does not match new module format. Expected domain.aggregates structure.');
|
|
392
|
+
}
|
|
393
|
+
return this.generateFromConfig(config);
|
|
394
|
+
}
|
|
395
|
+
async generateAndSaveFiles(yamlFilePath, moduleDir, opts) {
|
|
396
|
+
const storesByModel = this.generateFromYamlFile(yamlFilePath);
|
|
397
|
+
const storesDir = path.join(moduleDir, 'infrastructure', 'stores');
|
|
398
|
+
fs.mkdirSync(storesDir, { recursive: true });
|
|
399
|
+
for (const [modelName, code] of Object.entries(storesByModel)) {
|
|
400
|
+
const filePath = path.join(storesDir, `${modelName}Store.ts`);
|
|
401
|
+
// eslint-disable-next-line no-await-in-loop
|
|
402
|
+
await (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) });
|
|
403
|
+
}
|
|
404
|
+
// eslint-disable-next-line no-console
|
|
405
|
+
console.log('\n' + colors_1.colors.green('Store files generated successfully!') + '\n');
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
exports.NewStoreGenerator = NewStoreGenerator;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { NewModuleConfig } from '../types/configTypes';
|
|
2
|
+
export declare class NewTemplateGenerator {
|
|
3
|
+
private valueObjects;
|
|
4
|
+
/**
|
|
5
|
+
* Convert a route prefix like "/invoice/:invoiceId/items" into a
|
|
6
|
+
* template-ready path like "/invoice/{{ invoiceId }}/items".
|
|
7
|
+
*/
|
|
8
|
+
private prefixToTemplatePath;
|
|
9
|
+
/**
|
|
10
|
+
* Replace a single path param in prefix with a template expression (e.g. for list: item.id, for detail: id).
|
|
11
|
+
*/
|
|
12
|
+
private prefixWithParam;
|
|
13
|
+
private renderListTemplate;
|
|
14
|
+
private renderChildTableSection;
|
|
15
|
+
private renderDetailTemplate;
|
|
16
|
+
private renderCreateTemplate;
|
|
17
|
+
private renderEditTemplate;
|
|
18
|
+
private getInputType;
|
|
19
|
+
private renderValueObjectField;
|
|
20
|
+
private renderFormField;
|
|
21
|
+
private getEnumValuesMap;
|
|
22
|
+
private capitalize;
|
|
23
|
+
generateFromConfig(config: NewModuleConfig): Record<string, string>;
|
|
24
|
+
generateFromYamlFile(yamlFilePath: string): Record<string, string>;
|
|
25
|
+
generateAndSaveFiles(yamlFilePath: string, moduleDir: string, opts?: {
|
|
26
|
+
force?: boolean;
|
|
27
|
+
skipOnConflict?: boolean;
|
|
28
|
+
}): Promise<void>;
|
|
29
|
+
}
|