@currentjs/gen 0.2.1 → 0.3.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 +120 -0
- package/README.md +256 -8
- package/dist/cli.js +26 -0
- package/dist/commands/commit.js +4 -0
- package/dist/commands/createApp.js +7 -0
- package/dist/commands/diff.js +4 -0
- package/dist/commands/generateAll.js +159 -29
- package/dist/commands/migrateCommit.d.ts +1 -0
- package/dist/commands/migrateCommit.js +201 -0
- package/dist/generators/controllerGenerator.d.ts +7 -0
- package/dist/generators/controllerGenerator.js +60 -29
- package/dist/generators/domainModelGenerator.d.ts +8 -0
- package/dist/generators/domainModelGenerator.js +71 -4
- package/dist/generators/serviceGenerator.d.ts +17 -1
- package/dist/generators/serviceGenerator.js +139 -12
- package/dist/generators/storeGenerator.d.ts +9 -0
- package/dist/generators/storeGenerator.js +148 -8
- package/dist/generators/templateGenerator.d.ts +19 -0
- package/dist/generators/templateGenerator.js +216 -11
- package/dist/generators/templates/appTemplates.d.ts +8 -7
- package/dist/generators/templates/appTemplates.js +11 -1572
- package/dist/generators/templates/data/appTsTemplate +39 -0
- package/dist/generators/templates/data/appYamlTemplate +4 -0
- package/dist/generators/templates/data/cursorRulesTemplate +671 -0
- package/dist/generators/templates/data/errorTemplate +28 -0
- package/dist/generators/templates/data/frontendScriptTemplate +739 -0
- package/dist/generators/templates/data/mainViewTemplate +16 -0
- package/dist/generators/templates/data/translationsTemplate +68 -0
- package/dist/generators/templates/data/tsConfigTemplate +19 -0
- package/dist/generators/templates/viewTemplates.d.ts +10 -1
- package/dist/generators/templates/viewTemplates.js +138 -6
- package/dist/generators/validationGenerator.d.ts +5 -0
- package/dist/generators/validationGenerator.js +51 -0
- package/dist/utils/cliUtils.d.ts +6 -0
- package/dist/utils/cliUtils.js +24 -0
- package/dist/utils/constants.d.ts +3 -0
- package/dist/utils/constants.js +5 -2
- package/dist/utils/migrationUtils.d.ts +49 -0
- package/dist/utils/migrationUtils.js +291 -0
- package/howto.md +158 -66
- package/package.json +3 -2
|
@@ -50,6 +50,7 @@ class DomainModelGenerator {
|
|
|
50
50
|
array: 'any[]',
|
|
51
51
|
object: 'object'
|
|
52
52
|
};
|
|
53
|
+
this.availableModels = new Set();
|
|
53
54
|
}
|
|
54
55
|
getDefaultValue(type) {
|
|
55
56
|
switch (type) {
|
|
@@ -71,8 +72,27 @@ class DomainModelGenerator {
|
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
74
|
mapType(yamlType) {
|
|
75
|
+
// Check if this is a known model (relationship)
|
|
76
|
+
if (this.availableModels.has(yamlType)) {
|
|
77
|
+
return yamlType;
|
|
78
|
+
}
|
|
74
79
|
return this.typeMapping[yamlType] || 'any';
|
|
75
80
|
}
|
|
81
|
+
setAvailableModels(models) {
|
|
82
|
+
this.availableModels.clear();
|
|
83
|
+
models.forEach(model => {
|
|
84
|
+
this.availableModels.add(model.name);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
getRelatedModelImports(modelConfig) {
|
|
88
|
+
const imports = [];
|
|
89
|
+
modelConfig.fields.forEach(field => {
|
|
90
|
+
if (this.availableModels.has(field.type) && field.type !== modelConfig.name) {
|
|
91
|
+
imports.push(`import { ${field.type} } from './${field.type}';`);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
return imports;
|
|
95
|
+
}
|
|
76
96
|
generateConstructorParameter(field) {
|
|
77
97
|
const tsType = this.mapType(field.type);
|
|
78
98
|
const isOptional = !field.required && !field.auto;
|
|
@@ -87,14 +107,34 @@ class DomainModelGenerator {
|
|
|
87
107
|
}
|
|
88
108
|
return param;
|
|
89
109
|
}
|
|
110
|
+
isRelationshipField(field) {
|
|
111
|
+
return this.availableModels.has(field.type);
|
|
112
|
+
}
|
|
113
|
+
getForeignKeyFieldName(field) {
|
|
114
|
+
// Convention: fieldName + 'Id' (e.g., owner -> ownerId)
|
|
115
|
+
return field.name + 'Id';
|
|
116
|
+
}
|
|
117
|
+
generateForeignKeyParameter(field) {
|
|
118
|
+
const foreignKeyName = this.getForeignKeyFieldName(field);
|
|
119
|
+
const isOptional = !field.required && !field.auto;
|
|
120
|
+
let param = `public ${foreignKeyName}`;
|
|
121
|
+
if (isOptional) {
|
|
122
|
+
param += '?';
|
|
123
|
+
}
|
|
124
|
+
param += ': number';
|
|
125
|
+
return param;
|
|
126
|
+
}
|
|
90
127
|
generateSetterMethods(modelConfig) {
|
|
91
128
|
const setterMethods = [];
|
|
92
129
|
modelConfig.fields.forEach(field => {
|
|
93
130
|
if (!field.auto && field.name !== 'id') {
|
|
94
131
|
const tsType = this.mapType(field.type);
|
|
95
132
|
const methodName = `set${field.name.charAt(0).toUpperCase() + field.name.slice(1)}`;
|
|
133
|
+
// For all fields (including relationships), generate simple setter
|
|
134
|
+
// Domain model doesn't care about FKs - that's infrastructure concern
|
|
135
|
+
const isOptional = !field.required && !field.auto;
|
|
96
136
|
const setter = `
|
|
97
|
-
${methodName}(${field.name}: ${tsType}): void {
|
|
137
|
+
${methodName}(${field.name}: ${tsType}${isOptional ? ' | undefined' : ''}): void {
|
|
98
138
|
this.${field.name} = ${field.name};
|
|
99
139
|
}`;
|
|
100
140
|
setterMethods.push(setter);
|
|
@@ -102,17 +142,35 @@ class DomainModelGenerator {
|
|
|
102
142
|
});
|
|
103
143
|
return setterMethods.join('\n');
|
|
104
144
|
}
|
|
145
|
+
sortFieldsByRequired(fields) {
|
|
146
|
+
// Sort fields: required fields first, then optional fields
|
|
147
|
+
return [...fields].sort((a, b) => {
|
|
148
|
+
const aRequired = a.required !== false && !a.auto;
|
|
149
|
+
const bRequired = b.required !== false && !b.auto;
|
|
150
|
+
if (aRequired === bRequired) {
|
|
151
|
+
return 0; // Keep original order if both have same required status
|
|
152
|
+
}
|
|
153
|
+
return aRequired ? -1 : 1; // Required fields come first
|
|
154
|
+
});
|
|
155
|
+
}
|
|
105
156
|
generateModel(modelConfig) {
|
|
106
157
|
const className = modelConfig.name;
|
|
107
158
|
// Always add id field first
|
|
108
159
|
const constructorParams = ['public id: number'];
|
|
160
|
+
// Sort fields to put required fields before optional ones
|
|
161
|
+
const sortedFields = this.sortFieldsByRequired(modelConfig.fields);
|
|
109
162
|
// Process other fields
|
|
110
|
-
|
|
163
|
+
sortedFields.forEach(field => {
|
|
164
|
+
// For relationship fields, only add the relationship object (not FK)
|
|
165
|
+
// Domain model works with objects only - FK is infrastructure concern
|
|
111
166
|
constructorParams.push(this.generateConstructorParameter(field));
|
|
112
167
|
});
|
|
113
168
|
const constructorParamsStr = constructorParams.join(',\n ');
|
|
114
169
|
const setterMethods = this.generateSetterMethods(modelConfig);
|
|
115
|
-
|
|
170
|
+
// Generate imports for related models
|
|
171
|
+
const imports = this.getRelatedModelImports(modelConfig);
|
|
172
|
+
const importsStr = imports.length > 0 ? imports.join('\n') + '\n\n' : '';
|
|
173
|
+
return `${importsStr}export class ${className} {
|
|
116
174
|
public constructor(
|
|
117
175
|
${constructorParamsStr}
|
|
118
176
|
) { }
|
|
@@ -130,6 +188,8 @@ ${setterMethods}
|
|
|
130
188
|
const app = config;
|
|
131
189
|
Object.values(app.modules).forEach(moduleConfig => {
|
|
132
190
|
if (moduleConfig.models && moduleConfig.models.length > 0) {
|
|
191
|
+
// Set available models for relationship detection
|
|
192
|
+
this.setAvailableModels(moduleConfig.models);
|
|
133
193
|
moduleConfig.models.forEach(m => {
|
|
134
194
|
result[m.name] = this.generateModel(m);
|
|
135
195
|
});
|
|
@@ -138,6 +198,8 @@ ${setterMethods}
|
|
|
138
198
|
}
|
|
139
199
|
else if (config.models) {
|
|
140
200
|
const module = config;
|
|
201
|
+
// Set available models for relationship detection
|
|
202
|
+
this.setAvailableModels(module.models);
|
|
141
203
|
module.models.forEach(m => {
|
|
142
204
|
result[m.name] = this.generateModel(m);
|
|
143
205
|
});
|
|
@@ -149,6 +211,8 @@ ${setterMethods}
|
|
|
149
211
|
if (config.modules) {
|
|
150
212
|
Object.values(config.modules).forEach(moduleConfig => {
|
|
151
213
|
if (moduleConfig.models && moduleConfig.models.length > 0) {
|
|
214
|
+
// Set available models for relationship detection
|
|
215
|
+
this.setAvailableModels(moduleConfig.models);
|
|
152
216
|
moduleConfig.models.forEach(m => {
|
|
153
217
|
result[m.name] = this.generateModel(m);
|
|
154
218
|
});
|
|
@@ -156,7 +220,10 @@ ${setterMethods}
|
|
|
156
220
|
});
|
|
157
221
|
}
|
|
158
222
|
else if (config.models) {
|
|
159
|
-
|
|
223
|
+
const module = config;
|
|
224
|
+
// Set available models for relationship detection
|
|
225
|
+
this.setAvailableModels(module.models);
|
|
226
|
+
module.models.forEach(m => {
|
|
160
227
|
result[m.name] = this.generateModel(m);
|
|
161
228
|
});
|
|
162
229
|
}
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
interface FieldConfig {
|
|
2
|
+
name: string;
|
|
3
|
+
type: string;
|
|
4
|
+
required?: boolean;
|
|
5
|
+
unique?: boolean;
|
|
6
|
+
auto?: boolean;
|
|
7
|
+
displayFields?: string[];
|
|
8
|
+
}
|
|
1
9
|
interface ActionConfig {
|
|
2
10
|
handlers: string[];
|
|
3
11
|
}
|
|
@@ -7,7 +15,7 @@ interface PermissionConfig {
|
|
|
7
15
|
}
|
|
8
16
|
interface ModelConfig {
|
|
9
17
|
name: string;
|
|
10
|
-
fields:
|
|
18
|
+
fields: FieldConfig[];
|
|
11
19
|
}
|
|
12
20
|
type ModuleConfig = {
|
|
13
21
|
models?: ModelConfig[];
|
|
@@ -15,6 +23,10 @@ type ModuleConfig = {
|
|
|
15
23
|
permissions?: PermissionConfig[];
|
|
16
24
|
};
|
|
17
25
|
export declare class ServiceGenerator {
|
|
26
|
+
private availableModels;
|
|
27
|
+
private setAvailableModels;
|
|
28
|
+
private isRelationshipField;
|
|
29
|
+
private getForeignKeyFieldName;
|
|
18
30
|
private hasPermissions;
|
|
19
31
|
private getActionPermissions;
|
|
20
32
|
private generatePermissionCheck;
|
|
@@ -24,13 +36,17 @@ export declare class ServiceGenerator {
|
|
|
24
36
|
private generateMethodImplementation;
|
|
25
37
|
private extractFunctionName;
|
|
26
38
|
private getMethodCallParams;
|
|
39
|
+
private sortFieldsByRequired;
|
|
27
40
|
private generateConstructorArgs;
|
|
41
|
+
private generateRelationshipLoading;
|
|
28
42
|
private generateUpdateSetterCalls;
|
|
29
43
|
private replaceTemplateVars;
|
|
30
44
|
private getServiceMethodName;
|
|
31
45
|
private generateHandlerMethod;
|
|
32
46
|
generateServiceForModel(model: ModelConfig, moduleName: string, moduleConfig: ModuleConfig, hasGlobalPermissions: boolean): string;
|
|
33
47
|
generateService(moduleName: string, moduleConfig: ModuleConfig, hasGlobalPermissions: boolean): string;
|
|
48
|
+
private generateForeignStoreImports;
|
|
49
|
+
private generateForeignStoreConstructorParams;
|
|
34
50
|
private generateCustomImports;
|
|
35
51
|
generateFromYamlFile(yamlFilePath: string): Record<string, string>;
|
|
36
52
|
generateAndSaveFiles(yamlFilePath?: string, outputDir?: string, opts?: {
|
|
@@ -42,6 +42,22 @@ const generationRegistry_1 = require("../utils/generationRegistry");
|
|
|
42
42
|
const colors_1 = require("../utils/colors");
|
|
43
43
|
const constants_1 = require("../utils/constants");
|
|
44
44
|
class ServiceGenerator {
|
|
45
|
+
constructor() {
|
|
46
|
+
this.availableModels = new Set();
|
|
47
|
+
}
|
|
48
|
+
setAvailableModels(models) {
|
|
49
|
+
this.availableModels.clear();
|
|
50
|
+
models.forEach(model => {
|
|
51
|
+
this.availableModels.add(model.name);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
isRelationshipField(field) {
|
|
55
|
+
return this.availableModels.has(field.type);
|
|
56
|
+
}
|
|
57
|
+
getForeignKeyFieldName(field) {
|
|
58
|
+
// Convention: fieldName + 'Id' (e.g., owner -> ownerId)
|
|
59
|
+
return field.name + 'Id';
|
|
60
|
+
}
|
|
45
61
|
hasPermissions(config) {
|
|
46
62
|
if (config.modules) {
|
|
47
63
|
return Object.values(config.modules).some(module => module.permissions && module.permissions.length > 0);
|
|
@@ -198,12 +214,17 @@ class ServiceGenerator {
|
|
|
198
214
|
.replace(/{{ENTITY_LOWER}}/g, entityLower);
|
|
199
215
|
// Handle constructor args for create action
|
|
200
216
|
if (actionName === 'create') {
|
|
217
|
+
const relationshipLoading = this.generateRelationshipLoading(moduleConfig, entityName);
|
|
201
218
|
const constructorArgs = this.generateConstructorArgs(moduleConfig, entityName);
|
|
219
|
+
if (relationshipLoading) {
|
|
220
|
+
// Insert relationship loading before the entity creation
|
|
221
|
+
processedTemplate = relationshipLoading + '\n ' + processedTemplate;
|
|
222
|
+
}
|
|
202
223
|
processedTemplate = processedTemplate.replace(/{{CONSTRUCTOR_ARGS}}/g, constructorArgs);
|
|
203
224
|
}
|
|
204
225
|
// Handle setter calls for update action
|
|
205
226
|
if (actionName === 'update') {
|
|
206
|
-
const setterCalls = this.generateUpdateSetterCalls(moduleConfig, entityName);
|
|
227
|
+
const setterCalls = this.generateUpdateSetterCalls(moduleConfig, entityName, true);
|
|
207
228
|
processedTemplate = processedTemplate.replace(/{{UPDATE_SETTER_CALLS}}/g, setterCalls);
|
|
208
229
|
}
|
|
209
230
|
// Special-case: list action with only owner role → fetch by userId
|
|
@@ -288,34 +309,105 @@ class ServiceGenerator {
|
|
|
288
309
|
return '/* custom params */';
|
|
289
310
|
}
|
|
290
311
|
}
|
|
312
|
+
sortFieldsByRequired(fields) {
|
|
313
|
+
// Sort fields: required fields first, then optional fields
|
|
314
|
+
// This must match the order used in domainModelGenerator
|
|
315
|
+
return [...fields].sort((a, b) => {
|
|
316
|
+
const aRequired = a.required !== false && !a.auto;
|
|
317
|
+
const bRequired = b.required !== false && !b.auto;
|
|
318
|
+
if (aRequired === bRequired) {
|
|
319
|
+
return 0; // Keep original order if both have same required status
|
|
320
|
+
}
|
|
321
|
+
return aRequired ? -1 : 1; // Required fields come first
|
|
322
|
+
});
|
|
323
|
+
}
|
|
291
324
|
generateConstructorArgs(moduleConfig, entityName) {
|
|
292
325
|
if (!moduleConfig.models || moduleConfig.models.length === 0) {
|
|
293
326
|
return '';
|
|
294
327
|
}
|
|
295
328
|
// Find the correct model by entityName instead of always using first model
|
|
296
|
-
const model = moduleConfig.models.find(m => m.name === entityName) || moduleConfig.models[0];
|
|
329
|
+
const model = moduleConfig.models.find((m) => m.name === entityName) || moduleConfig.models[0];
|
|
297
330
|
const entityLower = entityName.toLowerCase();
|
|
298
|
-
|
|
331
|
+
// Sort fields to match the constructor parameter order
|
|
332
|
+
const sortedFields = this.sortFieldsByRequired(model.fields);
|
|
333
|
+
const args = [];
|
|
334
|
+
sortedFields
|
|
299
335
|
.filter(field => !field.auto && field.name !== 'id')
|
|
300
|
-
.
|
|
301
|
-
|
|
336
|
+
.forEach(field => {
|
|
337
|
+
// For relationship fields, reference the loaded object variable
|
|
338
|
+
if (this.isRelationshipField(field)) {
|
|
339
|
+
args.push(`${field.name}Object`);
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
args.push(`${entityLower}Data.${field.name}`);
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
return args.join(', ');
|
|
346
|
+
}
|
|
347
|
+
generateRelationshipLoading(moduleConfig, entityName) {
|
|
348
|
+
if (!moduleConfig.models || moduleConfig.models.length === 0) {
|
|
349
|
+
return '';
|
|
350
|
+
}
|
|
351
|
+
const model = moduleConfig.models.find((m) => m.name === entityName) || moduleConfig.models[0];
|
|
352
|
+
const entityLower = entityName.toLowerCase();
|
|
353
|
+
const relationshipFields = model.fields.filter(f => this.isRelationshipField(f));
|
|
354
|
+
if (relationshipFields.length === 0) {
|
|
355
|
+
return '';
|
|
356
|
+
}
|
|
357
|
+
const loadingCode = relationshipFields.map(field => {
|
|
358
|
+
const foreignKeyName = this.getForeignKeyFieldName(field);
|
|
359
|
+
const relatedModel = field.type;
|
|
360
|
+
const relatedModelLower = relatedModel.toLowerCase();
|
|
361
|
+
const varName = `${field.name}Object`;
|
|
362
|
+
if (field.required) {
|
|
363
|
+
return `const ${varName} = await this.${relatedModelLower}Store.getById(${entityLower}Data.${foreignKeyName});
|
|
364
|
+
if (!${varName}) {
|
|
365
|
+
throw new Error('${relatedModel} not found with id ' + ${entityLower}Data.${foreignKeyName});
|
|
366
|
+
}`;
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
return `const ${varName} = ${entityLower}Data.${foreignKeyName}
|
|
370
|
+
? await this.${relatedModelLower}Store.getById(${entityLower}Data.${foreignKeyName})
|
|
371
|
+
: null;`;
|
|
372
|
+
}
|
|
373
|
+
}).join('\n ');
|
|
374
|
+
return ' // Load relationship objects\n ' + loadingCode;
|
|
302
375
|
}
|
|
303
|
-
generateUpdateSetterCalls(moduleConfig, entityName) {
|
|
376
|
+
generateUpdateSetterCalls(moduleConfig, entityName, includeRelationshipLoading = false) {
|
|
304
377
|
if (!moduleConfig.models || moduleConfig.models.length === 0) {
|
|
305
378
|
return '';
|
|
306
379
|
}
|
|
307
380
|
// Find the correct model by entityName instead of always using first model
|
|
308
381
|
const model = moduleConfig.models.find(m => m.name === entityName) || moduleConfig.models[0];
|
|
309
382
|
const entityLower = entityName.toLowerCase();
|
|
310
|
-
|
|
383
|
+
let code = '';
|
|
384
|
+
// Add relationship loading if requested
|
|
385
|
+
if (includeRelationshipLoading) {
|
|
386
|
+
const relationshipLoading = this.generateRelationshipLoading(moduleConfig, entityName);
|
|
387
|
+
if (relationshipLoading) {
|
|
388
|
+
code = relationshipLoading + '\n ';
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
const setterCalls = model.fields
|
|
311
392
|
.filter(field => !field.auto && field.name !== 'id')
|
|
312
393
|
.map(field => {
|
|
313
|
-
|
|
314
|
-
|
|
394
|
+
// For relationship fields, set the loaded object
|
|
395
|
+
if (this.isRelationshipField(field)) {
|
|
396
|
+
const foreignKeyName = this.getForeignKeyFieldName(field);
|
|
397
|
+
const methodName = `set${field.name.charAt(0).toUpperCase() + field.name.slice(1)}`;
|
|
398
|
+
return `if (${entityLower}Data.${foreignKeyName} !== undefined) {
|
|
399
|
+
existing${entityName}.${methodName}(${field.name}Object);
|
|
400
|
+
}`;
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
const methodName = `set${field.name.charAt(0).toUpperCase() + field.name.slice(1)}`;
|
|
404
|
+
return `if (${entityLower}Data.${field.name} !== undefined) {
|
|
315
405
|
existing${entityName}.${methodName}(${entityLower}Data.${field.name});
|
|
316
406
|
}`;
|
|
407
|
+
}
|
|
317
408
|
})
|
|
318
409
|
.join('\n ');
|
|
410
|
+
return code + setterCalls;
|
|
319
411
|
}
|
|
320
412
|
replaceTemplateVars(template, variables) {
|
|
321
413
|
let result = template;
|
|
@@ -393,12 +485,17 @@ class ServiceGenerator {
|
|
|
393
485
|
.replace(/{{ENTITY_LOWER}}/g, entityLower);
|
|
394
486
|
// Handle constructor args for create action
|
|
395
487
|
if (actionName === 'create') {
|
|
488
|
+
const relationshipLoading = this.generateRelationshipLoading(moduleConfig, entityName);
|
|
396
489
|
const constructorArgs = this.generateConstructorArgs(moduleConfig, entityName);
|
|
490
|
+
if (relationshipLoading) {
|
|
491
|
+
// Insert relationship loading before the entity creation
|
|
492
|
+
methodImplementation = relationshipLoading + '\n ' + methodImplementation;
|
|
493
|
+
}
|
|
397
494
|
methodImplementation = methodImplementation.replace(/{{CONSTRUCTOR_ARGS}}/g, constructorArgs);
|
|
398
495
|
}
|
|
399
496
|
// Handle setter calls for update action
|
|
400
497
|
if (actionName === 'update') {
|
|
401
|
-
const setterCalls = this.generateUpdateSetterCalls(moduleConfig, entityName);
|
|
498
|
+
const setterCalls = this.generateUpdateSetterCalls(moduleConfig, entityName, true);
|
|
402
499
|
methodImplementation = methodImplementation.replace(/{{UPDATE_SETTER_CALLS}}/g, setterCalls);
|
|
403
500
|
}
|
|
404
501
|
// Special-case: list action with only owner role → fetch by userId
|
|
@@ -464,17 +561,20 @@ class ServiceGenerator {
|
|
|
464
561
|
})
|
|
465
562
|
.filter(method => method) // Remove empty methods
|
|
466
563
|
.join('\n\n');
|
|
564
|
+
// Add foreign store constructor params
|
|
565
|
+
const foreignStoreParams = this.generateForeignStoreConstructorParams(model);
|
|
467
566
|
const serviceClass = this.replaceTemplateVars(serviceTemplates_1.serviceTemplates.serviceClass, {
|
|
468
567
|
ENTITY_NAME: entityName,
|
|
469
568
|
ENTITY_LOWER: entityLower,
|
|
470
|
-
AUTH_SERVICE_PARAM:
|
|
569
|
+
AUTH_SERVICE_PARAM: foreignStoreParams,
|
|
471
570
|
SERVICE_METHODS: serviceMethods
|
|
472
571
|
});
|
|
473
572
|
const customImports = this.generateCustomImports(moduleConfig);
|
|
573
|
+
const foreignStoreImports = this.generateForeignStoreImports(model);
|
|
474
574
|
return this.replaceTemplateVars(serviceTemplates_1.serviceFileTemplate, {
|
|
475
575
|
ENTITY_NAME: entityName,
|
|
476
576
|
PERMISSIONS_IMPORT: hasPermissions ? "\nimport type { AuthenticatedUser } from '@currentjs/router';" : '',
|
|
477
|
-
CUSTOM_IMPORTS: customImports,
|
|
577
|
+
CUSTOM_IMPORTS: customImports + foreignStoreImports,
|
|
478
578
|
SERVICE_CLASS: serviceClass
|
|
479
579
|
});
|
|
480
580
|
}
|
|
@@ -485,6 +585,29 @@ class ServiceGenerator {
|
|
|
485
585
|
}
|
|
486
586
|
return this.generateServiceForModel(moduleConfig.models[0], moduleName, moduleConfig, hasGlobalPermissions);
|
|
487
587
|
}
|
|
588
|
+
generateForeignStoreImports(model) {
|
|
589
|
+
const relationshipFields = model.fields.filter(f => this.isRelationshipField(f));
|
|
590
|
+
if (relationshipFields.length === 0) {
|
|
591
|
+
return '';
|
|
592
|
+
}
|
|
593
|
+
const imports = relationshipFields.map(field => {
|
|
594
|
+
const relatedModel = field.type;
|
|
595
|
+
return `import { ${relatedModel}Store } from '../../infrastructure/stores/${relatedModel}Store';`;
|
|
596
|
+
});
|
|
597
|
+
return '\n' + imports.join('\n');
|
|
598
|
+
}
|
|
599
|
+
generateForeignStoreConstructorParams(model) {
|
|
600
|
+
const relationshipFields = model.fields.filter(f => this.isRelationshipField(f));
|
|
601
|
+
if (relationshipFields.length === 0) {
|
|
602
|
+
return '';
|
|
603
|
+
}
|
|
604
|
+
const params = relationshipFields.map(field => {
|
|
605
|
+
const relatedModel = field.type;
|
|
606
|
+
const relatedModelLower = relatedModel.toLowerCase();
|
|
607
|
+
return `,\n private ${relatedModelLower}Store: ${relatedModel}Store`;
|
|
608
|
+
});
|
|
609
|
+
return params.join('');
|
|
610
|
+
}
|
|
488
611
|
generateCustomImports(moduleConfig) {
|
|
489
612
|
if (!moduleConfig.actions)
|
|
490
613
|
return '';
|
|
@@ -510,6 +633,8 @@ class ServiceGenerator {
|
|
|
510
633
|
if (config.modules) {
|
|
511
634
|
Object.entries(config.modules).forEach(([moduleName, moduleConfig]) => {
|
|
512
635
|
if (moduleConfig.models && moduleConfig.models.length > 0) {
|
|
636
|
+
// Set available models for relationship detection
|
|
637
|
+
this.setAvailableModels(moduleConfig.models);
|
|
513
638
|
// Generate a service for each model
|
|
514
639
|
moduleConfig.models.forEach(model => {
|
|
515
640
|
const serviceCode = this.generateServiceForModel(model, moduleName, moduleConfig, hasGlobalPermissions);
|
|
@@ -524,6 +649,8 @@ class ServiceGenerator {
|
|
|
524
649
|
const moduleName = 'Module';
|
|
525
650
|
const moduleConfig = config;
|
|
526
651
|
if (moduleConfig.models && moduleConfig.models.length > 0) {
|
|
652
|
+
// Set available models for relationship detection
|
|
653
|
+
this.setAvailableModels(moduleConfig.models);
|
|
527
654
|
// Generate a service for each model
|
|
528
655
|
moduleConfig.models.forEach(model => {
|
|
529
656
|
const serviceCode = this.generateServiceForModel(model, moduleName, moduleConfig, hasGlobalPermissions);
|
|
@@ -4,6 +4,7 @@ interface FieldConfig {
|
|
|
4
4
|
required?: boolean;
|
|
5
5
|
unique?: boolean;
|
|
6
6
|
auto?: boolean;
|
|
7
|
+
displayFields?: string[];
|
|
7
8
|
}
|
|
8
9
|
interface ModelConfig {
|
|
9
10
|
name: string;
|
|
@@ -11,15 +12,23 @@ interface ModelConfig {
|
|
|
11
12
|
}
|
|
12
13
|
export declare class StoreGenerator {
|
|
13
14
|
private typeMapping;
|
|
15
|
+
private availableModels;
|
|
14
16
|
private mapType;
|
|
17
|
+
private setAvailableModels;
|
|
18
|
+
private isRelationshipField;
|
|
19
|
+
private getForeignKeyFieldName;
|
|
15
20
|
private generateRowFields;
|
|
16
21
|
private generateFilterableFields;
|
|
17
22
|
private generateFilterableFieldsArray;
|
|
18
23
|
private generateUpdatableFieldsArray;
|
|
24
|
+
private sortFieldsByRequired;
|
|
19
25
|
private generateRowToModelMapping;
|
|
20
26
|
private generateModelToRowMapping;
|
|
21
27
|
private replaceTemplateVars;
|
|
22
28
|
generateStoreInterface(): string;
|
|
29
|
+
private generateRelationshipMethods;
|
|
30
|
+
private generateStoreConstructorParams;
|
|
31
|
+
private generateRelationshipImports;
|
|
23
32
|
generateStore(modelConfig: ModelConfig): string;
|
|
24
33
|
generateStores(models: ModelConfig[]): Record<string, string>;
|
|
25
34
|
generateFromYamlFile(yamlFilePath: string): Record<string, string>;
|