@currentjs/gen 0.5.3 → 0.5.4
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 +4 -0
- package/dist/generators/domainLayerGenerator.js +7 -8
- package/dist/generators/dtoGenerator.js +5 -6
- package/dist/generators/storeGenerator.d.ts +14 -0
- package/dist/generators/storeGenerator.js +131 -16
- package/dist/generators/templateGenerator.d.ts +15 -0
- package/dist/generators/templateGenerator.js +215 -10
- package/dist/utils/migrationUtils.d.ts +1 -1
- package/dist/utils/migrationUtils.js +12 -1
- package/dist/utils/typeUtils.d.ts +29 -1
- package/dist/utils/typeUtils.js +100 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -137,14 +137,13 @@ class DomainLayerGenerator {
|
|
|
137
137
|
.filter(entityName => entityName !== name && allAggregates[entityName])
|
|
138
138
|
.map(entityName => `import { ${entityName} } from './${entityName}';`)
|
|
139
139
|
.join('\n');
|
|
140
|
-
// Generate imports for value objects used in fields
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
.
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
.filter((imp, idx, arr) => arr.indexOf(imp) === idx) // dedupe
|
|
140
|
+
// Generate imports for value objects used in fields (including compound types like Foo[] and Foo | Bar)
|
|
141
|
+
const referencedVoNames = new Set();
|
|
142
|
+
fields.forEach(([, fieldConfig]) => {
|
|
143
|
+
(0, typeUtils_1.getReferencedValueObjects)(fieldConfig.type, this.availableValueObjects).forEach(name => referencedVoNames.add(name));
|
|
144
|
+
});
|
|
145
|
+
const valueObjectImports = [...referencedVoNames]
|
|
146
|
+
.map(voName => `import { ${voName} } from '../valueObjects/${voName}';`)
|
|
148
147
|
.join('\n');
|
|
149
148
|
// Generate imports for aggregate references in fields (e.g. idea: { type: Idea })
|
|
150
149
|
const aggregateRefImports = fields
|
|
@@ -51,8 +51,7 @@ class DtoGenerator {
|
|
|
51
51
|
return (0, typeUtils_1.mapType)(yamlType, this.availableAggregates, this.availableValueObjects);
|
|
52
52
|
}
|
|
53
53
|
isValueObjectType(yamlType) {
|
|
54
|
-
|
|
55
|
-
return this.availableValueObjects.has(capitalizedType);
|
|
54
|
+
return (0, typeUtils_1.isValueObjectFieldType)(yamlType, this.availableValueObjects);
|
|
56
55
|
}
|
|
57
56
|
getValidationCode(fieldName, fieldType, isRequired) {
|
|
58
57
|
const checks = [];
|
|
@@ -431,11 +430,11 @@ ${mappingsStr}
|
|
|
431
430
|
if (outputConfig.pick && outputConfig.pick.length > 0) {
|
|
432
431
|
fieldsToCheck = fieldsToCheck.filter(([fieldName]) => outputConfig.pick.includes(fieldName));
|
|
433
432
|
}
|
|
434
|
-
// Check each field for value object types
|
|
433
|
+
// Check each field for value object types (including compound types like Foo[] and Foo | Bar)
|
|
435
434
|
fieldsToCheck.forEach(([, fieldConfig]) => {
|
|
436
|
-
|
|
437
|
-
valueObjects.add(
|
|
438
|
-
}
|
|
435
|
+
(0, typeUtils_1.getReferencedValueObjects)(fieldConfig.type, this.availableValueObjects).forEach(voName => {
|
|
436
|
+
valueObjects.add(voName);
|
|
437
|
+
});
|
|
439
438
|
});
|
|
440
439
|
}
|
|
441
440
|
// Check include for child entities
|
|
@@ -4,6 +4,8 @@ export declare class StoreGenerator {
|
|
|
4
4
|
private availableAggregates;
|
|
5
5
|
private isAggregateField;
|
|
6
6
|
private isValueObjectType;
|
|
7
|
+
private isArrayVoType;
|
|
8
|
+
private isUnionVoType;
|
|
7
9
|
private getValueObjectName;
|
|
8
10
|
private getValueObjectConfig;
|
|
9
11
|
/**
|
|
@@ -21,8 +23,20 @@ export declare class StoreGenerator {
|
|
|
21
23
|
private mapTypeToRowType;
|
|
22
24
|
/** Single line for serializing a value object field to DB (insert/update). */
|
|
23
25
|
private generateValueObjectSerialization;
|
|
26
|
+
/** Serialization for an array-of-VOs field. */
|
|
27
|
+
private generateArrayVoSerialization;
|
|
28
|
+
/** Serialization for a union-of-VOs field. Uses _type discriminator. */
|
|
29
|
+
private generateUnionVoSerialization;
|
|
24
30
|
/** Single line for deserializing a value object from row (rowToModel). */
|
|
25
31
|
private generateValueObjectDeserialization;
|
|
32
|
+
/** Deserialization for an array-of-VOs field. */
|
|
33
|
+
private generateArrayVoDeserialization;
|
|
34
|
+
/** Deserialization for a union-of-VOs field. Uses _type discriminator. */
|
|
35
|
+
private generateUnionVoDeserialization;
|
|
36
|
+
/** Serialization for an array-of-union-VOs field. Each element tagged with _type discriminator. */
|
|
37
|
+
private generateArrayUnionVoSerialization;
|
|
38
|
+
/** Deserialization for an array-of-union-VOs field. Each element reconstructed via _type. */
|
|
39
|
+
private generateArrayUnionVoDeserialization;
|
|
26
40
|
/** Single line for datetime conversion: toDate (row->model) or toMySQL (entity->row). */
|
|
27
41
|
private generateDatetimeConversion;
|
|
28
42
|
private replaceTemplateVars;
|
|
@@ -52,8 +52,16 @@ class StoreGenerator {
|
|
|
52
52
|
return (0, typeUtils_1.isAggregateReference)(fieldConfig.type, this.availableAggregates);
|
|
53
53
|
}
|
|
54
54
|
isValueObjectType(fieldType) {
|
|
55
|
-
const
|
|
56
|
-
return this.availableValueObjects.has(
|
|
55
|
+
const { baseTypes } = (0, typeUtils_1.parseFieldType)(fieldType);
|
|
56
|
+
return baseTypes.some(bt => this.availableValueObjects.has((0, typeUtils_1.capitalize)(bt)));
|
|
57
|
+
}
|
|
58
|
+
isArrayVoType(fieldType) {
|
|
59
|
+
const parsed = (0, typeUtils_1.parseFieldType)(fieldType);
|
|
60
|
+
return parsed.isArray && parsed.baseTypes.some(bt => this.availableValueObjects.has((0, typeUtils_1.capitalize)(bt)));
|
|
61
|
+
}
|
|
62
|
+
isUnionVoType(fieldType) {
|
|
63
|
+
const parsed = (0, typeUtils_1.parseFieldType)(fieldType);
|
|
64
|
+
return parsed.isUnion && parsed.baseTypes.some(bt => this.availableValueObjects.has((0, typeUtils_1.capitalize)(bt)));
|
|
57
65
|
}
|
|
58
66
|
getValueObjectName(fieldType) {
|
|
59
67
|
return (0, typeUtils_1.capitalize)(fieldType);
|
|
@@ -105,6 +113,18 @@ class StoreGenerator {
|
|
|
105
113
|
}
|
|
106
114
|
return ` ${fieldName}: entity.${fieldName} ? JSON.stringify(entity.${fieldName}) : undefined`;
|
|
107
115
|
}
|
|
116
|
+
/** Serialization for an array-of-VOs field. */
|
|
117
|
+
generateArrayVoSerialization(fieldName) {
|
|
118
|
+
return ` ${fieldName}: entity.${fieldName} ? JSON.stringify(entity.${fieldName}) : undefined`;
|
|
119
|
+
}
|
|
120
|
+
/** Serialization for a union-of-VOs field. Uses _type discriminator. */
|
|
121
|
+
generateUnionVoSerialization(fieldName, unionVoNames) {
|
|
122
|
+
const checks = unionVoNames
|
|
123
|
+
.map(voName => `entity.${fieldName} instanceof ${voName} ? '${voName}'`)
|
|
124
|
+
.join(' : ');
|
|
125
|
+
const discriminator = `${checks} : 'unknown'`;
|
|
126
|
+
return ` ${fieldName}: entity.${fieldName} ? JSON.stringify({ _type: ${discriminator}, ...entity.${fieldName} }) : undefined`;
|
|
127
|
+
}
|
|
108
128
|
/** Single line for deserializing a value object from row (rowToModel). */
|
|
109
129
|
generateValueObjectDeserialization(fieldName, voName, voConfig) {
|
|
110
130
|
const voFields = Object.keys(voConfig.fields);
|
|
@@ -123,6 +143,46 @@ class StoreGenerator {
|
|
|
123
143
|
}
|
|
124
144
|
return ` row.${fieldName} ? new ${voName}(...Object.values(JSON.parse(row.${fieldName}))) : undefined`;
|
|
125
145
|
}
|
|
146
|
+
/** Deserialization for an array-of-VOs field. */
|
|
147
|
+
generateArrayVoDeserialization(fieldName, voName, voConfig) {
|
|
148
|
+
const voFields = Object.keys(voConfig.fields);
|
|
149
|
+
const itemArgs = voFields.length > 0
|
|
150
|
+
? voFields.map(f => `item.${f}`).join(', ')
|
|
151
|
+
: '...Object.values(item)';
|
|
152
|
+
return ` row.${fieldName} ? (JSON.parse(row.${fieldName}) as any[]).map((item: any) => new ${voName}(${itemArgs})) : []`;
|
|
153
|
+
}
|
|
154
|
+
/** Deserialization for a union-of-VOs field. Uses _type discriminator. */
|
|
155
|
+
generateUnionVoDeserialization(fieldName, unionVoNames, unionVoConfigs) {
|
|
156
|
+
const cases = unionVoNames.map(voName => {
|
|
157
|
+
const cfg = unionVoConfigs[voName];
|
|
158
|
+
const voFields = cfg ? Object.keys(cfg.fields) : [];
|
|
159
|
+
const args = voFields.length > 0
|
|
160
|
+
? voFields.map(f => `parsed.${f}`).join(', ')
|
|
161
|
+
: '...Object.values(parsed)';
|
|
162
|
+
return `if (parsed._type === '${voName}') return new ${voName}(${args});`;
|
|
163
|
+
}).join(' ');
|
|
164
|
+
return ` row.${fieldName} ? (() => { const parsed = JSON.parse(row.${fieldName}); ${cases} return undefined; })() : undefined`;
|
|
165
|
+
}
|
|
166
|
+
/** Serialization for an array-of-union-VOs field. Each element tagged with _type discriminator. */
|
|
167
|
+
generateArrayUnionVoSerialization(fieldName, unionVoNames) {
|
|
168
|
+
const checks = unionVoNames
|
|
169
|
+
.map(voName => `item instanceof ${voName} ? '${voName}'`)
|
|
170
|
+
.join(' : ');
|
|
171
|
+
const discriminator = `${checks} : 'unknown'`;
|
|
172
|
+
return ` ${fieldName}: entity.${fieldName} ? JSON.stringify(entity.${fieldName}.map((item: any) => ({ _type: ${discriminator}, ...item }))) : undefined`;
|
|
173
|
+
}
|
|
174
|
+
/** Deserialization for an array-of-union-VOs field. Each element reconstructed via _type. */
|
|
175
|
+
generateArrayUnionVoDeserialization(fieldName, unionVoNames, unionVoConfigs) {
|
|
176
|
+
const cases = unionVoNames.map(voName => {
|
|
177
|
+
const cfg = unionVoConfigs[voName];
|
|
178
|
+
const voFields = cfg ? Object.keys(cfg.fields) : [];
|
|
179
|
+
const args = voFields.length > 0
|
|
180
|
+
? voFields.map(f => `item.${f}`).join(', ')
|
|
181
|
+
: '...Object.values(item)';
|
|
182
|
+
return `if (item._type === '${voName}') return new ${voName}(${args});`;
|
|
183
|
+
}).join(' ');
|
|
184
|
+
return ` row.${fieldName} ? (JSON.parse(row.${fieldName}) as any[]).map((item: any) => { ${cases} return undefined; }) : []`;
|
|
185
|
+
}
|
|
126
186
|
/** Single line for datetime conversion: toDate (row->model) or toMySQL (entity->row). */
|
|
127
187
|
generateDatetimeConversion(fieldName, direction) {
|
|
128
188
|
if (direction === 'toDate') {
|
|
@@ -186,8 +246,37 @@ class StoreGenerator {
|
|
|
186
246
|
result.push(` Boolean(row.${fieldName})`);
|
|
187
247
|
return;
|
|
188
248
|
}
|
|
189
|
-
// Handle value object conversion - deserialize from JSON
|
|
249
|
+
// Handle value object conversion - deserialize from JSON (simple, array, union, or array-of-union)
|
|
190
250
|
if (this.isValueObjectType(fieldType)) {
|
|
251
|
+
const parsed = (0, typeUtils_1.parseFieldType)(fieldType);
|
|
252
|
+
if (parsed.isArray && parsed.isUnion) {
|
|
253
|
+
const unionVoNames = parsed.baseTypes.map(bt => (0, typeUtils_1.capitalize)(bt)).filter(name => this.availableValueObjects.has(name));
|
|
254
|
+
const unionVoConfigs = {};
|
|
255
|
+
unionVoNames.forEach(name => {
|
|
256
|
+
const cfg = this.availableValueObjects.get(name);
|
|
257
|
+
if (cfg)
|
|
258
|
+
unionVoConfigs[name] = cfg;
|
|
259
|
+
});
|
|
260
|
+
result.push(this.generateArrayUnionVoDeserialization(fieldName, unionVoNames, unionVoConfigs));
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
if (parsed.isArray) {
|
|
264
|
+
const voName = (0, typeUtils_1.capitalize)(parsed.baseTypes[0]);
|
|
265
|
+
const voConfig = this.availableValueObjects.get(voName);
|
|
266
|
+
result.push(this.generateArrayVoDeserialization(fieldName, voName, voConfig || { fields: {} }));
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
if (parsed.isUnion) {
|
|
270
|
+
const unionVoNames = parsed.baseTypes.map(bt => (0, typeUtils_1.capitalize)(bt)).filter(name => this.availableValueObjects.has(name));
|
|
271
|
+
const unionVoConfigs = {};
|
|
272
|
+
unionVoNames.forEach(name => {
|
|
273
|
+
const cfg = this.availableValueObjects.get(name);
|
|
274
|
+
if (cfg)
|
|
275
|
+
unionVoConfigs[name] = cfg;
|
|
276
|
+
});
|
|
277
|
+
result.push(this.generateUnionVoDeserialization(fieldName, unionVoNames, unionVoConfigs));
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
191
280
|
const voName = this.getValueObjectName(fieldType);
|
|
192
281
|
const voConfig = this.getValueObjectConfig(fieldType);
|
|
193
282
|
if (voConfig) {
|
|
@@ -218,8 +307,23 @@ class StoreGenerator {
|
|
|
218
307
|
result.push(this.generateDatetimeConversion(fieldName, 'toMySQL'));
|
|
219
308
|
return;
|
|
220
309
|
}
|
|
221
|
-
// Handle value object - serialize to JSON
|
|
310
|
+
// Handle value object - serialize to JSON (simple, array, union, or array-of-union)
|
|
222
311
|
if (this.isValueObjectType(fieldType)) {
|
|
312
|
+
const parsed = (0, typeUtils_1.parseFieldType)(fieldType);
|
|
313
|
+
if (parsed.isArray && parsed.isUnion) {
|
|
314
|
+
const unionVoNames = parsed.baseTypes.map(bt => (0, typeUtils_1.capitalize)(bt)).filter(name => this.availableValueObjects.has(name));
|
|
315
|
+
result.push(this.generateArrayUnionVoSerialization(fieldName, unionVoNames));
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
if (parsed.isArray) {
|
|
319
|
+
result.push(this.generateArrayVoSerialization(fieldName));
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
if (parsed.isUnion) {
|
|
323
|
+
const unionVoNames = parsed.baseTypes.map(bt => (0, typeUtils_1.capitalize)(bt)).filter(name => this.availableValueObjects.has(name));
|
|
324
|
+
result.push(this.generateUnionVoSerialization(fieldName, unionVoNames));
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
223
327
|
const voConfig = this.getValueObjectConfig(fieldType);
|
|
224
328
|
if (voConfig) {
|
|
225
329
|
result.push(this.generateValueObjectSerialization(fieldName, this.getValueObjectName(fieldType), voConfig));
|
|
@@ -244,6 +348,18 @@ class StoreGenerator {
|
|
|
244
348
|
return this.generateDatetimeConversion(fieldName, 'toMySQL');
|
|
245
349
|
}
|
|
246
350
|
if (this.isValueObjectType(fieldType)) {
|
|
351
|
+
const parsed = (0, typeUtils_1.parseFieldType)(fieldType);
|
|
352
|
+
if (parsed.isArray && parsed.isUnion) {
|
|
353
|
+
const unionVoNames = parsed.baseTypes.map(bt => (0, typeUtils_1.capitalize)(bt)).filter(name => this.availableValueObjects.has(name));
|
|
354
|
+
return this.generateArrayUnionVoSerialization(fieldName, unionVoNames);
|
|
355
|
+
}
|
|
356
|
+
if (parsed.isArray) {
|
|
357
|
+
return this.generateArrayVoSerialization(fieldName);
|
|
358
|
+
}
|
|
359
|
+
if (parsed.isUnion) {
|
|
360
|
+
const unionVoNames = parsed.baseTypes.map(bt => (0, typeUtils_1.capitalize)(bt)).filter(name => this.availableValueObjects.has(name));
|
|
361
|
+
return this.generateUnionVoSerialization(fieldName, unionVoNames);
|
|
362
|
+
}
|
|
247
363
|
const voConfig = this.getValueObjectConfig(fieldType);
|
|
248
364
|
if (voConfig) {
|
|
249
365
|
return this.generateValueObjectSerialization(fieldName, this.getValueObjectName(fieldType), voConfig);
|
|
@@ -260,26 +376,25 @@ class StoreGenerator {
|
|
|
260
376
|
generateValueObjectImports(fields) {
|
|
261
377
|
const imports = [];
|
|
262
378
|
fields.forEach(([, fieldConfig]) => {
|
|
263
|
-
if (this.isValueObjectType(fieldConfig.type))
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
379
|
+
if (!this.isValueObjectType(fieldConfig.type))
|
|
380
|
+
return;
|
|
381
|
+
// Collect all VO names referenced in this field type (handles Foo[], Foo | Bar)
|
|
382
|
+
const referencedVoNames = (0, typeUtils_1.getReferencedValueObjects)(fieldConfig.type, this.availableValueObjects);
|
|
383
|
+
referencedVoNames.forEach(voName => {
|
|
384
|
+
const voConfig = this.availableValueObjects.get(voName);
|
|
267
385
|
const importItems = [voName];
|
|
268
|
-
// Also import
|
|
269
|
-
if (voConfig) {
|
|
386
|
+
// Also import enum type alias if present (only for simple single-VO fields)
|
|
387
|
+
if (voConfig && !(0, typeUtils_1.parseFieldType)(fieldConfig.type).isArray && !(0, typeUtils_1.parseFieldType)(fieldConfig.type).isUnion) {
|
|
270
388
|
const enumTypeName = this.getValueObjectFieldTypeName(voName, voConfig);
|
|
271
|
-
if (enumTypeName)
|
|
389
|
+
if (enumTypeName)
|
|
272
390
|
importItems.push(enumTypeName);
|
|
273
|
-
}
|
|
274
391
|
}
|
|
275
392
|
imports.push(`import { ${importItems.join(', ')} } from '../../domain/valueObjects/${voName}';`);
|
|
276
|
-
}
|
|
393
|
+
});
|
|
277
394
|
});
|
|
278
|
-
// Dedupe imports
|
|
279
395
|
const uniqueImports = [...new Set(imports)];
|
|
280
|
-
if (uniqueImports.length === 0)
|
|
396
|
+
if (uniqueImports.length === 0)
|
|
281
397
|
return '';
|
|
282
|
-
}
|
|
283
398
|
return '\n' + uniqueImports.join('\n');
|
|
284
399
|
}
|
|
285
400
|
generateAggregateRefImports(modelName, fields) {
|
|
@@ -19,6 +19,21 @@ export declare class TemplateGenerator {
|
|
|
19
19
|
private renderEditTemplate;
|
|
20
20
|
private getInputType;
|
|
21
21
|
private renderValueObjectField;
|
|
22
|
+
/**
|
|
23
|
+
* Render an array-of-VOs field as checkboxes.
|
|
24
|
+
* If the VO has a single enum field: one checkbox per enum value.
|
|
25
|
+
* If the VO has multiple / non-enum fields: one labeled checkbox group per VO subfield.
|
|
26
|
+
*/
|
|
27
|
+
private renderArrayVoField;
|
|
28
|
+
/**
|
|
29
|
+
* Render a union-of-VOs field as a type selector with sub-fields for each VO type.
|
|
30
|
+
*/
|
|
31
|
+
private renderUnionVoField;
|
|
32
|
+
/**
|
|
33
|
+
* Render an array-of-union-VOs field as a repeatable group where each item
|
|
34
|
+
* has a type selector and conditionally-shown sub-fields per VO type.
|
|
35
|
+
*/
|
|
36
|
+
private renderArrayUnionVoField;
|
|
22
37
|
private renderFormField;
|
|
23
38
|
private getEnumValuesMap;
|
|
24
39
|
generateFromConfig(config: ModuleConfig): Record<string, string>;
|
|
@@ -69,7 +69,12 @@ class TemplateGenerator {
|
|
|
69
69
|
.filter(([name]) => name !== 'id')
|
|
70
70
|
.slice(0, 5)
|
|
71
71
|
.map(([name, config]) => {
|
|
72
|
-
const
|
|
72
|
+
const typeStr = (config.type || 'string');
|
|
73
|
+
const parsed = (0, typeUtils_1.parseFieldType)(typeStr);
|
|
74
|
+
if (parsed.isArray || parsed.isUnion) {
|
|
75
|
+
return ` <td>{{ item.${name} }}</td>`;
|
|
76
|
+
}
|
|
77
|
+
const voConfig = this.valueObjects[(0, typeUtils_1.capitalize)(typeStr)];
|
|
73
78
|
if (voConfig) {
|
|
74
79
|
const parts = Object.keys(voConfig.fields)
|
|
75
80
|
.map(sub => `{{ item.${name}.${sub} }}`)
|
|
@@ -136,12 +141,16 @@ ${fieldCells}
|
|
|
136
141
|
const fieldEntries = Object.entries(child.childFields).filter(([name]) => name !== 'id').slice(0, 5);
|
|
137
142
|
const headers = fieldEntries.map(([name]) => ` <th>${(0, typeUtils_1.capitalize)(name)}</th>`).join('\n');
|
|
138
143
|
const cells = fieldEntries.map(([name, config]) => {
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
144
|
+
const typeStr = ((config === null || config === void 0 ? void 0 : config.type) || 'string');
|
|
145
|
+
const parsedType = (0, typeUtils_1.parseFieldType)(typeStr);
|
|
146
|
+
if (!parsedType.isArray && !parsedType.isUnion) {
|
|
147
|
+
const voConfig = this.valueObjects[(0, typeUtils_1.capitalize)(typeStr)];
|
|
148
|
+
if (voConfig) {
|
|
149
|
+
const parts = Object.keys(voConfig.fields)
|
|
150
|
+
.map(sub => `{{ childItem.${name}.${sub} }}`)
|
|
151
|
+
.join(' ');
|
|
152
|
+
return ` <td>${parts}</td>`;
|
|
153
|
+
}
|
|
145
154
|
}
|
|
146
155
|
return ` <td>{{ childItem.${name} }}</td>`;
|
|
147
156
|
}).join('\n');
|
|
@@ -177,7 +186,15 @@ ${actionLinks}
|
|
|
177
186
|
renderDetailTemplate(modelName, viewName, fields, basePath, withChildChildren) {
|
|
178
187
|
const fieldRows = fields
|
|
179
188
|
.map(([name, config]) => {
|
|
180
|
-
const
|
|
189
|
+
const typeStr = (config.type || 'string');
|
|
190
|
+
const parsed = (0, typeUtils_1.parseFieldType)(typeStr);
|
|
191
|
+
if (parsed.isArray || parsed.isUnion) {
|
|
192
|
+
return ` <div class="row mb-2">
|
|
193
|
+
<div class="col-4"><strong>${(0, typeUtils_1.capitalize)(name)}:</strong></div>
|
|
194
|
+
<div class="col-8">{{ ${name} }}</div>
|
|
195
|
+
</div>`;
|
|
196
|
+
}
|
|
197
|
+
const voConfig = this.valueObjects[(0, typeUtils_1.capitalize)(typeStr)];
|
|
181
198
|
if (voConfig) {
|
|
182
199
|
const parts = Object.keys(voConfig.fields)
|
|
183
200
|
.map(sub => `{{ ${name}.${sub} }}`)
|
|
@@ -215,6 +232,15 @@ ${fieldRows}
|
|
|
215
232
|
buildFieldTypesJson(safeFields) {
|
|
216
233
|
return JSON.stringify(safeFields.reduce((acc, [name, config]) => {
|
|
217
234
|
const typeStr = typeof (config === null || config === void 0 ? void 0 : config.type) === 'string' ? config.type : 'string';
|
|
235
|
+
const parsed = (0, typeUtils_1.parseFieldType)(typeStr);
|
|
236
|
+
// Array or union of VOs → stored as JSON, emit single "json" entry
|
|
237
|
+
if (parsed.isArray || parsed.isUnion) {
|
|
238
|
+
const anyVoReferenced = parsed.baseTypes.some(bt => this.valueObjects[(0, typeUtils_1.capitalize)(bt)]);
|
|
239
|
+
if (anyVoReferenced) {
|
|
240
|
+
acc[name] = 'json';
|
|
241
|
+
return acc;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
218
244
|
const capitalizedType = (0, typeUtils_1.capitalize)(typeStr);
|
|
219
245
|
const voConfig = this.valueObjects[capitalizedType];
|
|
220
246
|
if (voConfig) {
|
|
@@ -319,13 +345,192 @@ ${options}
|
|
|
319
345
|
<div class="row g-2">
|
|
320
346
|
${columns}
|
|
321
347
|
</div>
|
|
348
|
+
</div>`;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Render an array-of-VOs field as checkboxes.
|
|
352
|
+
* If the VO has a single enum field: one checkbox per enum value.
|
|
353
|
+
* If the VO has multiple / non-enum fields: one labeled checkbox group per VO subfield.
|
|
354
|
+
*/
|
|
355
|
+
renderArrayVoField(name, label, voName, voConfig, isEdit) {
|
|
356
|
+
const subFields = Object.entries(voConfig.fields);
|
|
357
|
+
// Single enum field: render one checkbox per enum value
|
|
358
|
+
if (subFields.length === 1) {
|
|
359
|
+
const [subName, subConfig] = subFields[0];
|
|
360
|
+
if (typeof subConfig === 'object' && 'values' in subConfig) {
|
|
361
|
+
const uniqueValues = [...new Set(subConfig.values)];
|
|
362
|
+
const checkboxes = uniqueValues.map(v => {
|
|
363
|
+
const checkedExpr = isEdit ? ` {{ (${name} || []).some(function(item){ return item.${subName} === '${v}'; }) ? 'checked' : '' }}` : '';
|
|
364
|
+
return ` <div class="form-check form-check-inline">
|
|
365
|
+
<input type="checkbox" class="form-check-input" name="${name}[]" value="${v}"${checkedExpr}>
|
|
366
|
+
<label class="form-check-label">${v}</label>
|
|
367
|
+
</div>`;
|
|
368
|
+
}).join('\n');
|
|
369
|
+
return ` <div class="mb-3">
|
|
370
|
+
<label class="form-label">${label}</label>
|
|
371
|
+
<div>
|
|
372
|
+
${checkboxes}
|
|
373
|
+
</div>
|
|
374
|
+
</div>`;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
// Multi-field VO: render a repeatable entry group with one checkbox-style row per sub-field
|
|
378
|
+
const subInputs = subFields.map(([subName, subConfig]) => {
|
|
379
|
+
const subLabel = (0, typeUtils_1.capitalize)(subName);
|
|
380
|
+
if (typeof subConfig === 'object' && 'values' in subConfig) {
|
|
381
|
+
const uniqueValues = [...new Set(subConfig.values)];
|
|
382
|
+
const options = uniqueValues.map(v => `<option value="${v}">${v}</option>`).join('');
|
|
383
|
+
return ` <div class="col-auto">
|
|
384
|
+
<label class="form-label">${subLabel}</label>
|
|
385
|
+
<select class="form-select form-select-sm" name="${name}[0].${subName}"><option value="">--</option>${options}</select>
|
|
386
|
+
</div>`;
|
|
387
|
+
}
|
|
388
|
+
const inputType = this.getInputType(subConfig.type);
|
|
389
|
+
return ` <div class="col">
|
|
390
|
+
<label class="form-label">${subLabel}</label>
|
|
391
|
+
<input type="${inputType}" class="form-control form-control-sm" name="${name}[0].${subName}" placeholder="${subLabel}">
|
|
392
|
+
</div>`;
|
|
393
|
+
}).join('\n');
|
|
394
|
+
return ` <div class="mb-3">
|
|
395
|
+
<label class="form-label">${label}</label>
|
|
396
|
+
<div class="border rounded p-2">
|
|
397
|
+
<div class="row g-2 align-items-end">
|
|
398
|
+
${subInputs}
|
|
399
|
+
</div>
|
|
400
|
+
<small class="text-muted">Add multiple ${voName} entries as needed.</small>
|
|
401
|
+
</div>
|
|
402
|
+
</div>`;
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Render a union-of-VOs field as a type selector with sub-fields for each VO type.
|
|
406
|
+
*/
|
|
407
|
+
renderUnionVoField(name, label, unionVoNames, isEdit) {
|
|
408
|
+
const typeOptions = unionVoNames.map(voName => {
|
|
409
|
+
const sel = isEdit ? ` {{ ${name}._type === '${voName}' ? 'selected' : '' }}` : '';
|
|
410
|
+
return ` <option value="${voName}"${sel}>${voName}</option>`;
|
|
411
|
+
}).join('\n');
|
|
412
|
+
const subFieldGroups = unionVoNames.map(voName => {
|
|
413
|
+
const voConfig = this.valueObjects[voName];
|
|
414
|
+
if (!voConfig)
|
|
415
|
+
return '';
|
|
416
|
+
const subInputs = Object.entries(voConfig.fields).map(([subName, subConfig]) => {
|
|
417
|
+
const subLabel = (0, typeUtils_1.capitalize)(subName);
|
|
418
|
+
const fullName = `${name}.${subName}`;
|
|
419
|
+
if (typeof subConfig === 'object' && 'values' in subConfig) {
|
|
420
|
+
const uniqueValues = [...new Set(subConfig.values)];
|
|
421
|
+
const options = uniqueValues.map(v => {
|
|
422
|
+
const sel = isEdit ? ` {{ ${name}.${subName} === '${v}' ? 'selected' : '' }}` : '';
|
|
423
|
+
return ` <option value="${v}"${sel}>${v}</option>`;
|
|
424
|
+
}).join('\n');
|
|
425
|
+
return ` <div class="col-auto">
|
|
426
|
+
<label class="form-label">${subLabel}</label>
|
|
427
|
+
<select class="form-select" id="${fullName}" name="${fullName}">
|
|
428
|
+
<option value="">-- ${subLabel} --</option>
|
|
429
|
+
${options}
|
|
430
|
+
</select>
|
|
431
|
+
</div>`;
|
|
432
|
+
}
|
|
433
|
+
const inputType = this.getInputType(subConfig.type);
|
|
434
|
+
const value = isEdit ? ` value="{{ ${name}.${subName} || '' }}"` : '';
|
|
435
|
+
return ` <div class="col">
|
|
436
|
+
<label class="form-label">${subLabel}</label>
|
|
437
|
+
<input type="${inputType}" class="form-control" id="${fullName}" name="${fullName}" placeholder="${subLabel}"${value}>
|
|
438
|
+
</div>`;
|
|
439
|
+
}).join('\n');
|
|
440
|
+
return ` <div class="${name}-fields-${voName}">
|
|
441
|
+
<div class="row g-2">
|
|
442
|
+
${subInputs}
|
|
443
|
+
</div>
|
|
444
|
+
</div>`;
|
|
445
|
+
}).join('\n');
|
|
446
|
+
return ` <div class="mb-3">
|
|
447
|
+
<label for="${name}_type" class="form-label">${label} Type</label>
|
|
448
|
+
<select class="form-select mb-2" id="${name}_type" name="${name}._type">
|
|
449
|
+
<option value="">-- Select type --</option>
|
|
450
|
+
${typeOptions}
|
|
451
|
+
</select>
|
|
452
|
+
${subFieldGroups}
|
|
453
|
+
</div>`;
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Render an array-of-union-VOs field as a repeatable group where each item
|
|
457
|
+
* has a type selector and conditionally-shown sub-fields per VO type.
|
|
458
|
+
*/
|
|
459
|
+
renderArrayUnionVoField(name, label, unionVoNames, isEdit) {
|
|
460
|
+
const typeOptions = unionVoNames.map(voName => {
|
|
461
|
+
return ` <option value="${voName}">${voName}</option>`;
|
|
462
|
+
}).join('\n');
|
|
463
|
+
const subFieldGroups = unionVoNames.map(voName => {
|
|
464
|
+
const voConfig = this.valueObjects[voName];
|
|
465
|
+
if (!voConfig)
|
|
466
|
+
return '';
|
|
467
|
+
const subInputs = Object.entries(voConfig.fields).map(([subName, subConfig]) => {
|
|
468
|
+
const subLabel = (0, typeUtils_1.capitalize)(subName);
|
|
469
|
+
const fullName = `${name}[0].${subName}`;
|
|
470
|
+
if (typeof subConfig === 'object' && 'values' in subConfig) {
|
|
471
|
+
const uniqueValues = [...new Set(subConfig.values)];
|
|
472
|
+
const options = uniqueValues.map(v => `<option value="${v}">${v}</option>`).join('');
|
|
473
|
+
return ` <div class="col-auto">
|
|
474
|
+
<label class="form-label">${subLabel}</label>
|
|
475
|
+
<select class="form-select form-select-sm" name="${fullName}"><option value="">--</option>${options}</select>
|
|
476
|
+
</div>`;
|
|
477
|
+
}
|
|
478
|
+
const inputType = this.getInputType(subConfig.type);
|
|
479
|
+
return ` <div class="col">
|
|
480
|
+
<label class="form-label">${subLabel}</label>
|
|
481
|
+
<input type="${inputType}" class="form-control form-control-sm" name="${fullName}" placeholder="${subLabel}">
|
|
482
|
+
</div>`;
|
|
483
|
+
}).join('\n');
|
|
484
|
+
return ` <div class="${name}-fields-${voName}">
|
|
485
|
+
<div class="row g-2">
|
|
486
|
+
${subInputs}
|
|
487
|
+
</div>
|
|
488
|
+
</div>`;
|
|
489
|
+
}).join('\n');
|
|
490
|
+
const editHint = isEdit ? ` <!-- existing items rendered server-side -->` : '';
|
|
491
|
+
return ` <div class="mb-3">
|
|
492
|
+
<label class="form-label">${label}</label>
|
|
493
|
+
<div class="border rounded p-2" id="${name}-container">${editHint}
|
|
494
|
+
<div class="${name}-entry mb-2">
|
|
495
|
+
<select class="form-select form-select-sm mb-1" name="${name}[0]._type">
|
|
496
|
+
<option value="">-- Select type --</option>
|
|
497
|
+
${typeOptions}
|
|
498
|
+
</select>
|
|
499
|
+
${subFieldGroups}
|
|
500
|
+
</div>
|
|
501
|
+
</div>
|
|
502
|
+
<small class="text-muted">Add multiple ${label} entries as needed.</small>
|
|
322
503
|
</div>`;
|
|
323
504
|
}
|
|
324
505
|
renderFormField(name, config, enumValues = [], isEdit = false) {
|
|
325
506
|
const required = config.required ? 'required' : '';
|
|
326
507
|
const label = (0, typeUtils_1.capitalize)(name);
|
|
327
|
-
const fieldType = (config.type || 'string')
|
|
328
|
-
const
|
|
508
|
+
const fieldType = (config.type || 'string');
|
|
509
|
+
const parsed = (0, typeUtils_1.parseFieldType)(fieldType);
|
|
510
|
+
// Array of union of value objects
|
|
511
|
+
if (parsed.isArray && parsed.isUnion) {
|
|
512
|
+
const unionVoNames = parsed.baseTypes.map(bt => (0, typeUtils_1.capitalize)(bt)).filter(n => this.valueObjects[n]);
|
|
513
|
+
if (unionVoNames.length > 0) {
|
|
514
|
+
return this.renderArrayUnionVoField(name, label, unionVoNames, isEdit);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
// Array of value objects
|
|
518
|
+
if (parsed.isArray) {
|
|
519
|
+
const voName = (0, typeUtils_1.capitalize)(parsed.baseTypes[0]);
|
|
520
|
+
const voConfig = this.valueObjects[voName];
|
|
521
|
+
if (voConfig) {
|
|
522
|
+
return this.renderArrayVoField(name, label, voName, voConfig, isEdit);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
// Union of value objects
|
|
526
|
+
if (parsed.isUnion) {
|
|
527
|
+
const unionVoNames = parsed.baseTypes.map(bt => (0, typeUtils_1.capitalize)(bt)).filter(n => this.valueObjects[n]);
|
|
528
|
+
if (unionVoNames.length > 0) {
|
|
529
|
+
return this.renderUnionVoField(name, label, unionVoNames, isEdit);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
// Simple value object
|
|
533
|
+
const capitalizedType = (0, typeUtils_1.capitalize)(fieldType.toLowerCase());
|
|
329
534
|
const voConfig = this.valueObjects[capitalizedType];
|
|
330
535
|
if (voConfig) {
|
|
331
536
|
return this.renderValueObjectField(name, label, voConfig, required, isEdit);
|
|
@@ -21,7 +21,7 @@ export interface ForeignKeyInfo {
|
|
|
21
21
|
REFERENCED_TABLE_NAME: string;
|
|
22
22
|
REFERENCED_COLUMN_NAME: string;
|
|
23
23
|
}
|
|
24
|
-
export declare function mapYamlTypeToSql(yamlType: string, availableAggregates: Set<string>): string;
|
|
24
|
+
export declare function mapYamlTypeToSql(yamlType: string, availableAggregates: Set<string>, availableValueObjects?: Set<string>): string;
|
|
25
25
|
export declare function getTableName(aggregateName: string): string;
|
|
26
26
|
export declare function getForeignKeyFieldName(fieldName: string): string;
|
|
27
27
|
export declare function isRelationshipField(fieldType: string, availableAggregates: Set<string>): boolean;
|
|
@@ -52,6 +52,7 @@ exports.getMigrationFileName = getMigrationFileName;
|
|
|
52
52
|
const fs = __importStar(require("fs"));
|
|
53
53
|
const path = __importStar(require("path"));
|
|
54
54
|
const yaml_1 = require("yaml");
|
|
55
|
+
const typeUtils_1 = require("./typeUtils");
|
|
55
56
|
const TYPE_MAPPING = {
|
|
56
57
|
string: 'VARCHAR(255)',
|
|
57
58
|
number: 'INT',
|
|
@@ -61,10 +62,20 @@ const TYPE_MAPPING = {
|
|
|
61
62
|
array: 'JSON',
|
|
62
63
|
object: 'JSON'
|
|
63
64
|
};
|
|
64
|
-
function mapYamlTypeToSql(yamlType, availableAggregates) {
|
|
65
|
+
function mapYamlTypeToSql(yamlType, availableAggregates, availableValueObjects) {
|
|
66
|
+
// Simple aggregate reference → foreign key INT
|
|
65
67
|
if (availableAggregates.has(yamlType)) {
|
|
66
68
|
return 'INT';
|
|
67
69
|
}
|
|
70
|
+
// Compound types: array ("Foo[]") or union ("Foo | Bar") → JSON column
|
|
71
|
+
const parsed = (0, typeUtils_1.parseFieldType)(yamlType);
|
|
72
|
+
if (parsed.isArray || parsed.isUnion) {
|
|
73
|
+
return 'JSON';
|
|
74
|
+
}
|
|
75
|
+
// Named value object → stored as JSON
|
|
76
|
+
if (availableValueObjects && availableValueObjects.has(yamlType)) {
|
|
77
|
+
return 'JSON';
|
|
78
|
+
}
|
|
68
79
|
return TYPE_MAPPING[yamlType] || 'VARCHAR(255)';
|
|
69
80
|
}
|
|
70
81
|
function getTableName(aggregateName) {
|
|
@@ -9,8 +9,35 @@ export declare const TYPE_MAPPING: Record<string, string>;
|
|
|
9
9
|
/** Store-specific: YAML type to DB row TypeScript type (e.g. datetime -> string). */
|
|
10
10
|
export declare const ROW_TYPE_MAPPING: Record<string, string>;
|
|
11
11
|
export declare function capitalize(str: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Parsed representation of a compound YAML field type.
|
|
14
|
+
* Supports array syntax ("Foo[]") and union syntax ("Foo | Bar").
|
|
15
|
+
*/
|
|
16
|
+
export interface ParsedFieldType {
|
|
17
|
+
/** Individual base type names without modifiers. */
|
|
18
|
+
baseTypes: string[];
|
|
19
|
+
/** True when the type ends with "[]" (array of values). */
|
|
20
|
+
isArray: boolean;
|
|
21
|
+
/** True when the type contains "|" (union of types). */
|
|
22
|
+
isUnion: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Parse a YAML field type string into its structural components.
|
|
26
|
+
* Handles simple types ("Money"), array types ("Money[]"), union types ("Foo | Bar"),
|
|
27
|
+
* and array-of-union types ("(Foo | Bar)[]").
|
|
28
|
+
*/
|
|
29
|
+
export declare function parseFieldType(typeStr: string): ParsedFieldType;
|
|
30
|
+
/**
|
|
31
|
+
* Returns true when any base type in the (possibly compound) type expression is a known value object.
|
|
32
|
+
*/
|
|
33
|
+
export declare function isValueObjectFieldType(typeStr: string, valueObjects: Set<string> | Map<string, unknown>): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Returns the set of value object names referenced in a (possibly compound) type expression.
|
|
36
|
+
*/
|
|
37
|
+
export declare function getReferencedValueObjects(typeStr: string, valueObjects: Set<string> | Map<string, unknown>): Set<string>;
|
|
12
38
|
/**
|
|
13
39
|
* Map a YAML field type to TypeScript type, resolving aggregates and value objects by name.
|
|
40
|
+
* Supports compound types: "Foo[]" -> "Foo[]", "Foo | Bar" -> "Foo | Bar".
|
|
14
41
|
*/
|
|
15
42
|
export declare function mapType(yamlType: string, aggregates?: Set<string> | Map<string, unknown>, valueObjects?: Set<string> | Map<string, unknown>): string;
|
|
16
43
|
/**
|
|
@@ -18,6 +45,7 @@ export declare function mapType(yamlType: string, aggregates?: Set<string> | Map
|
|
|
18
45
|
*/
|
|
19
46
|
export declare function isAggregateReference(yamlType: string, aggregates?: Set<string> | Map<string, unknown>): boolean;
|
|
20
47
|
/**
|
|
21
|
-
* Map a YAML type to the store row TypeScript type
|
|
48
|
+
* Map a YAML type to the store row TypeScript type.
|
|
49
|
+
* Value objects (including compound types) become "string" (stored as JSON).
|
|
22
50
|
*/
|
|
23
51
|
export declare function mapRowType(yamlType: string, valueObjects?: Set<string> | Map<string, unknown>): string;
|
package/dist/utils/typeUtils.js
CHANGED
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.ROW_TYPE_MAPPING = exports.TYPE_MAPPING = void 0;
|
|
7
7
|
exports.capitalize = capitalize;
|
|
8
|
+
exports.parseFieldType = parseFieldType;
|
|
9
|
+
exports.isValueObjectFieldType = isValueObjectFieldType;
|
|
10
|
+
exports.getReferencedValueObjects = getReferencedValueObjects;
|
|
8
11
|
exports.mapType = mapType;
|
|
9
12
|
exports.isAggregateReference = isAggregateReference;
|
|
10
13
|
exports.mapRowType = mapRowType;
|
|
@@ -41,20 +44,111 @@ exports.ROW_TYPE_MAPPING = {
|
|
|
41
44
|
function capitalize(str) {
|
|
42
45
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
43
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Parse a YAML field type string into its structural components.
|
|
49
|
+
* Handles simple types ("Money"), array types ("Money[]"), union types ("Foo | Bar"),
|
|
50
|
+
* and array-of-union types ("(Foo | Bar)[]").
|
|
51
|
+
*/
|
|
52
|
+
function parseFieldType(typeStr) {
|
|
53
|
+
const trimmed = typeStr.trim();
|
|
54
|
+
// Array of union: "(Foo | Bar)[]"
|
|
55
|
+
if (trimmed.startsWith('(') && trimmed.endsWith(')[]')) {
|
|
56
|
+
const inner = trimmed.slice(1, -3).trim();
|
|
57
|
+
const parts = inner.split('|').map(p => p.trim()).filter(Boolean);
|
|
58
|
+
return { baseTypes: parts, isArray: true, isUnion: true };
|
|
59
|
+
}
|
|
60
|
+
if (trimmed.endsWith('[]')) {
|
|
61
|
+
const base = trimmed.slice(0, -2).trim();
|
|
62
|
+
return { baseTypes: [base], isArray: true, isUnion: false };
|
|
63
|
+
}
|
|
64
|
+
if (trimmed.includes('|')) {
|
|
65
|
+
const parts = trimmed.split('|').map(p => p.trim()).filter(Boolean);
|
|
66
|
+
return { baseTypes: parts, isArray: false, isUnion: true };
|
|
67
|
+
}
|
|
68
|
+
return { baseTypes: [trimmed], isArray: false, isUnion: false };
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Returns true when any base type in the (possibly compound) type expression is a known value object.
|
|
72
|
+
*/
|
|
73
|
+
function isValueObjectFieldType(typeStr, valueObjects) {
|
|
74
|
+
const { baseTypes } = parseFieldType(typeStr);
|
|
75
|
+
return baseTypes.some(bt => {
|
|
76
|
+
const cap = capitalize(bt);
|
|
77
|
+
return valueObjects instanceof Set ? valueObjects.has(cap) : valueObjects.has(cap);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Returns the set of value object names referenced in a (possibly compound) type expression.
|
|
82
|
+
*/
|
|
83
|
+
function getReferencedValueObjects(typeStr, valueObjects) {
|
|
84
|
+
const { baseTypes } = parseFieldType(typeStr);
|
|
85
|
+
const result = new Set();
|
|
86
|
+
for (const bt of baseTypes) {
|
|
87
|
+
const cap = capitalize(bt);
|
|
88
|
+
const has = valueObjects instanceof Set ? valueObjects.has(cap) : valueObjects.has(cap);
|
|
89
|
+
if (has)
|
|
90
|
+
result.add(cap);
|
|
91
|
+
}
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
44
94
|
/**
|
|
45
95
|
* Map a YAML field type to TypeScript type, resolving aggregates and value objects by name.
|
|
96
|
+
* Supports compound types: "Foo[]" -> "Foo[]", "Foo | Bar" -> "Foo | Bar".
|
|
46
97
|
*/
|
|
47
98
|
function mapType(yamlType, aggregates, valueObjects) {
|
|
48
|
-
var _a;
|
|
99
|
+
var _a, _b;
|
|
100
|
+
// Simple aggregate reference (no compound syntax)
|
|
49
101
|
if (aggregates === null || aggregates === void 0 ? void 0 : aggregates.has(yamlType))
|
|
50
102
|
return yamlType;
|
|
103
|
+
const parsed = parseFieldType(yamlType);
|
|
104
|
+
// Array of union of value objects: "(Foo | Bar)[]"
|
|
105
|
+
if (parsed.isArray && parsed.isUnion) {
|
|
106
|
+
const resolvedParts = parsed.baseTypes.map(bt => {
|
|
107
|
+
var _a;
|
|
108
|
+
const cap = capitalize(bt);
|
|
109
|
+
if (valueObjects) {
|
|
110
|
+
const has = valueObjects instanceof Set ? valueObjects.has(cap) : valueObjects.has(cap);
|
|
111
|
+
if (has)
|
|
112
|
+
return cap;
|
|
113
|
+
}
|
|
114
|
+
return (_a = exports.TYPE_MAPPING[bt]) !== null && _a !== void 0 ? _a : 'any';
|
|
115
|
+
});
|
|
116
|
+
return `(${resolvedParts.join(' | ')})[]`;
|
|
117
|
+
}
|
|
118
|
+
// Array of value objects: "Foo[]"
|
|
119
|
+
if (parsed.isArray) {
|
|
120
|
+
const [base] = parsed.baseTypes;
|
|
121
|
+
const capitalizedBase = capitalize(base);
|
|
122
|
+
if (valueObjects) {
|
|
123
|
+
const has = valueObjects instanceof Set ? valueObjects.has(capitalizedBase) : valueObjects.has(capitalizedBase);
|
|
124
|
+
if (has)
|
|
125
|
+
return `${capitalizedBase}[]`;
|
|
126
|
+
}
|
|
127
|
+
// Fall back: treat as plain mapped type array
|
|
128
|
+
return `${(_a = exports.TYPE_MAPPING[base]) !== null && _a !== void 0 ? _a : 'any'}[]`;
|
|
129
|
+
}
|
|
130
|
+
// Union of value objects: "Foo | Bar"
|
|
131
|
+
if (parsed.isUnion) {
|
|
132
|
+
const resolvedParts = parsed.baseTypes.map(bt => {
|
|
133
|
+
var _a;
|
|
134
|
+
const cap = capitalize(bt);
|
|
135
|
+
if (valueObjects) {
|
|
136
|
+
const has = valueObjects instanceof Set ? valueObjects.has(cap) : valueObjects.has(cap);
|
|
137
|
+
if (has)
|
|
138
|
+
return cap;
|
|
139
|
+
}
|
|
140
|
+
return (_a = exports.TYPE_MAPPING[bt]) !== null && _a !== void 0 ? _a : 'any';
|
|
141
|
+
});
|
|
142
|
+
return resolvedParts.join(' | ');
|
|
143
|
+
}
|
|
144
|
+
// Simple type
|
|
51
145
|
const capitalizedType = capitalize(yamlType);
|
|
52
146
|
if (valueObjects) {
|
|
53
147
|
const has = valueObjects instanceof Set ? valueObjects.has(capitalizedType) : valueObjects.has(capitalizedType);
|
|
54
148
|
if (has)
|
|
55
149
|
return capitalizedType;
|
|
56
150
|
}
|
|
57
|
-
return (
|
|
151
|
+
return (_b = exports.TYPE_MAPPING[yamlType]) !== null && _b !== void 0 ? _b : 'any';
|
|
58
152
|
}
|
|
59
153
|
/**
|
|
60
154
|
* Check if a YAML field type references another aggregate entity.
|
|
@@ -63,14 +157,14 @@ function isAggregateReference(yamlType, aggregates) {
|
|
|
63
157
|
return !!(aggregates === null || aggregates === void 0 ? void 0 : aggregates.has(yamlType));
|
|
64
158
|
}
|
|
65
159
|
/**
|
|
66
|
-
* Map a YAML type to the store row TypeScript type
|
|
160
|
+
* Map a YAML type to the store row TypeScript type.
|
|
161
|
+
* Value objects (including compound types) become "string" (stored as JSON).
|
|
67
162
|
*/
|
|
68
163
|
function mapRowType(yamlType, valueObjects) {
|
|
69
164
|
var _a;
|
|
70
165
|
if (valueObjects) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if (has)
|
|
166
|
+
// Any compound type containing a VO name is stored as JSON string
|
|
167
|
+
if (isValueObjectFieldType(yamlType, valueObjects))
|
|
74
168
|
return 'string';
|
|
75
169
|
}
|
|
76
170
|
return (_a = exports.ROW_TYPE_MAPPING[yamlType]) !== null && _a !== void 0 ? _a : 'string';
|