@currentjs/gen 0.3.2 → 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 +10 -611
- 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 +45 -11
- 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,21 @@
|
|
|
1
|
+
import { ModuleConfig } from '../types/configTypes';
|
|
2
|
+
export declare class DomainLayerGenerator {
|
|
3
|
+
private availableAggregates;
|
|
4
|
+
private availableValueObjects;
|
|
5
|
+
private mapType;
|
|
6
|
+
private getDefaultValue;
|
|
7
|
+
private generateValueObject;
|
|
8
|
+
private generateAggregate;
|
|
9
|
+
generateFromConfig(config: ModuleConfig): Record<string, {
|
|
10
|
+
code: string;
|
|
11
|
+
type: 'entity' | 'valueObject';
|
|
12
|
+
}>;
|
|
13
|
+
generateFromYamlFile(yamlFilePath: string): Record<string, {
|
|
14
|
+
code: string;
|
|
15
|
+
type: 'entity' | 'valueObject';
|
|
16
|
+
}>;
|
|
17
|
+
generateAndSaveFiles(yamlFilePath: string, moduleDir: string, opts?: {
|
|
18
|
+
force?: boolean;
|
|
19
|
+
skipOnConflict?: boolean;
|
|
20
|
+
}): Promise<void>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,276 @@
|
|
|
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.DomainLayerGenerator = 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 typeUtils_1 = require("../utils/typeUtils");
|
|
45
|
+
class DomainLayerGenerator {
|
|
46
|
+
constructor() {
|
|
47
|
+
this.availableAggregates = new Set();
|
|
48
|
+
this.availableValueObjects = new Set();
|
|
49
|
+
}
|
|
50
|
+
mapType(yamlType) {
|
|
51
|
+
return (0, typeUtils_1.mapType)(yamlType, this.availableAggregates, this.availableValueObjects);
|
|
52
|
+
}
|
|
53
|
+
getDefaultValue(type) {
|
|
54
|
+
switch (type) {
|
|
55
|
+
case 'datetime':
|
|
56
|
+
case 'date':
|
|
57
|
+
return 'new Date()';
|
|
58
|
+
case 'string':
|
|
59
|
+
return "''";
|
|
60
|
+
case 'number':
|
|
61
|
+
case 'integer':
|
|
62
|
+
case 'decimal':
|
|
63
|
+
return '0';
|
|
64
|
+
case 'boolean':
|
|
65
|
+
return 'false';
|
|
66
|
+
case 'array':
|
|
67
|
+
return '[]';
|
|
68
|
+
case 'object':
|
|
69
|
+
case 'json':
|
|
70
|
+
return '{}';
|
|
71
|
+
default:
|
|
72
|
+
return 'undefined';
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
generateValueObject(name, config) {
|
|
76
|
+
const fields = Object.entries(config.fields);
|
|
77
|
+
// Collect type definitions for enum fields
|
|
78
|
+
const typeDefinitions = [];
|
|
79
|
+
// Generate constructor parameters
|
|
80
|
+
const constructorParams = fields.map(([fieldName, fieldConfig]) => {
|
|
81
|
+
if (typeof fieldConfig === 'object' && 'values' in fieldConfig) {
|
|
82
|
+
// Enum type - generate a type alias
|
|
83
|
+
const typeName = `${name}${(0, typeUtils_1.capitalize)(fieldName)}`;
|
|
84
|
+
const uniqueValues = [...new Set(fieldConfig.values)]; // dedupe
|
|
85
|
+
const enumValues = uniqueValues.map(v => `'${v}'`).join(' | ');
|
|
86
|
+
typeDefinitions.push(`export type ${typeName} = ${enumValues};`);
|
|
87
|
+
return `public ${fieldName}: ${typeName}`;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
const tsType = this.mapType(fieldConfig.type);
|
|
91
|
+
return `public ${fieldName}: ${tsType}`;
|
|
92
|
+
}
|
|
93
|
+
}).join(',\n ');
|
|
94
|
+
// Generate validation logic
|
|
95
|
+
const validations = [];
|
|
96
|
+
fields.forEach(([fieldName, fieldConfig]) => {
|
|
97
|
+
if (typeof fieldConfig === 'object' && 'constraints' in fieldConfig && fieldConfig.constraints) {
|
|
98
|
+
const constraints = fieldConfig.constraints;
|
|
99
|
+
if (constraints.min !== undefined) {
|
|
100
|
+
validations.push(` if (this.${fieldName} < ${constraints.min}) {
|
|
101
|
+
throw new Error('${name}.${fieldName} must be at least ${constraints.min}');
|
|
102
|
+
}`);
|
|
103
|
+
}
|
|
104
|
+
if (constraints.max !== undefined) {
|
|
105
|
+
validations.push(` if (this.${fieldName} > ${constraints.max}) {
|
|
106
|
+
throw new Error('${name}.${fieldName} must be at most ${constraints.max}');
|
|
107
|
+
}`);
|
|
108
|
+
}
|
|
109
|
+
if (constraints.pattern) {
|
|
110
|
+
validations.push(` if (!/${constraints.pattern}/.test(String(this.${fieldName}))) {
|
|
111
|
+
throw new Error('${name}.${fieldName} does not match required pattern');
|
|
112
|
+
}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (typeof fieldConfig === 'object' && 'values' in fieldConfig) {
|
|
116
|
+
const uniqueValues = [...new Set(fieldConfig.values)]; // dedupe
|
|
117
|
+
const values = uniqueValues.map(v => `'${v}'`).join(', ');
|
|
118
|
+
validations.push(` if (![${values}].includes(this.${fieldName})) {
|
|
119
|
+
throw new Error(\`${name}.${fieldName} must be one of: ${values}\`);
|
|
120
|
+
}`);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
const validationCode = validations.length > 0 ? `\n this.validate();\n }\n\n private validate(): void {\n${validations.join('\n')}\n }` : '\n }';
|
|
124
|
+
const typeDefsCode = typeDefinitions.length > 0 ? typeDefinitions.join('\n') + '\n\n' : '';
|
|
125
|
+
return `${typeDefsCode}export class ${name} {
|
|
126
|
+
public constructor(
|
|
127
|
+
${constructorParams}
|
|
128
|
+
) {${validationCode}
|
|
129
|
+
}`;
|
|
130
|
+
}
|
|
131
|
+
generateAggregate(name, config, allAggregates, childInfo) {
|
|
132
|
+
const fields = Object.entries(config.fields);
|
|
133
|
+
// Determine which entities are contained in this aggregate
|
|
134
|
+
const containedEntities = config.entities || [];
|
|
135
|
+
// Generate imports for contained entities
|
|
136
|
+
const entityImports = containedEntities
|
|
137
|
+
.filter(entityName => entityName !== name && allAggregates[entityName])
|
|
138
|
+
.map(entityName => `import { ${entityName} } from './${entityName}';`)
|
|
139
|
+
.join('\n');
|
|
140
|
+
// Generate imports for value objects used in fields
|
|
141
|
+
const valueObjectImports = fields
|
|
142
|
+
.filter(([, fieldConfig]) => this.availableValueObjects.has((0, typeUtils_1.capitalize)(fieldConfig.type)))
|
|
143
|
+
.map(([, fieldConfig]) => {
|
|
144
|
+
const voName = (0, typeUtils_1.capitalize)(fieldConfig.type);
|
|
145
|
+
return `import { ${voName} } from '../valueObjects/${voName}';`;
|
|
146
|
+
})
|
|
147
|
+
.filter((imp, idx, arr) => arr.indexOf(imp) === idx) // dedupe
|
|
148
|
+
.join('\n');
|
|
149
|
+
const imports = [entityImports, valueObjectImports].filter(Boolean).join('\n');
|
|
150
|
+
// Generate constructor parameters: id, then ownerId (root) or parentId field (child)
|
|
151
|
+
const constructorParams = ['public id: number'];
|
|
152
|
+
if (childInfo) {
|
|
153
|
+
constructorParams.push(`public ${childInfo.parentIdField}: number`);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
constructorParams.push('public ownerId: number');
|
|
157
|
+
}
|
|
158
|
+
// Sort fields: required first, then optional
|
|
159
|
+
// Fields are required by default unless required: false
|
|
160
|
+
const sortedFields = fields.sort((a, b) => {
|
|
161
|
+
const aRequired = a[1].required !== false && !a[1].auto;
|
|
162
|
+
const bRequired = b[1].required !== false && !b[1].auto;
|
|
163
|
+
if (aRequired === bRequired)
|
|
164
|
+
return 0;
|
|
165
|
+
return aRequired ? -1 : 1;
|
|
166
|
+
});
|
|
167
|
+
const enumTypeDefinitions = [];
|
|
168
|
+
const enumTypeNames = {};
|
|
169
|
+
sortedFields.forEach(([fieldName, fieldConfig]) => {
|
|
170
|
+
if (fieldConfig.type === 'enum' && fieldConfig.values && fieldConfig.values.length > 0) {
|
|
171
|
+
const typeName = `${name}${(0, typeUtils_1.capitalize)(fieldName)}`;
|
|
172
|
+
const uniqueValues = [...new Set(fieldConfig.values)];
|
|
173
|
+
const enumValues = uniqueValues.map(v => `'${v}'`).join(' | ');
|
|
174
|
+
enumTypeDefinitions.push(`export type ${typeName} = ${enumValues};`);
|
|
175
|
+
enumTypeNames[fieldName] = typeName;
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
sortedFields.forEach(([fieldName, fieldConfig]) => {
|
|
179
|
+
const tsType = enumTypeNames[fieldName] || this.mapType(fieldConfig.type);
|
|
180
|
+
// Fields are required by default, only optional if explicitly set to required: false
|
|
181
|
+
const isOptional = fieldConfig.required === false;
|
|
182
|
+
const hasDefault = fieldConfig.auto;
|
|
183
|
+
let param = `public ${fieldName}`;
|
|
184
|
+
if (isOptional && !hasDefault) {
|
|
185
|
+
param += '?';
|
|
186
|
+
}
|
|
187
|
+
param += `: ${tsType}`;
|
|
188
|
+
if (hasDefault) {
|
|
189
|
+
param += ` = ${this.getDefaultValue(fieldConfig.type)}`;
|
|
190
|
+
}
|
|
191
|
+
constructorParams.push(param);
|
|
192
|
+
});
|
|
193
|
+
const constructorParamsStr = constructorParams.join(',\n ');
|
|
194
|
+
// Generate setter methods
|
|
195
|
+
const setterMethods = sortedFields
|
|
196
|
+
.filter(([fieldName, fieldConfig]) => !fieldConfig.auto && fieldName !== 'id')
|
|
197
|
+
.map(([fieldName, fieldConfig]) => {
|
|
198
|
+
const tsType = enumTypeNames[fieldName] || this.mapType(fieldConfig.type);
|
|
199
|
+
const methodName = `set${(0, typeUtils_1.capitalize)(fieldName)}`;
|
|
200
|
+
// Fields are required by default, only optional if explicitly set to required: false
|
|
201
|
+
const isOptional = fieldConfig.required === false;
|
|
202
|
+
return `
|
|
203
|
+
${methodName}(${fieldName}: ${tsType}${isOptional ? ' | undefined' : ''}): void {
|
|
204
|
+
this.${fieldName} = ${fieldName};
|
|
205
|
+
}`;
|
|
206
|
+
})
|
|
207
|
+
.join('\n');
|
|
208
|
+
const rootComment = config.root ? '// Aggregate Root\n' : '';
|
|
209
|
+
const enumTypeDefsCode = enumTypeDefinitions.length > 0 ? enumTypeDefinitions.join('\n') + '\n\n' : '';
|
|
210
|
+
return `${imports ? imports + '\n\n' : ''}${enumTypeDefsCode}${rootComment}export class ${name} {
|
|
211
|
+
public constructor(
|
|
212
|
+
${constructorParamsStr}
|
|
213
|
+
) { }
|
|
214
|
+
${setterMethods}
|
|
215
|
+
}`;
|
|
216
|
+
}
|
|
217
|
+
generateFromConfig(config) {
|
|
218
|
+
const result = {};
|
|
219
|
+
// First pass: collect all aggregate and value object names
|
|
220
|
+
if (config.domain.aggregates) {
|
|
221
|
+
Object.keys(config.domain.aggregates).forEach(name => {
|
|
222
|
+
this.availableAggregates.add(name);
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
if (config.domain.valueObjects) {
|
|
226
|
+
Object.keys(config.domain.valueObjects).forEach(name => {
|
|
227
|
+
this.availableValueObjects.add(name);
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
// Generate value objects first (they may be used by aggregates)
|
|
231
|
+
if (config.domain.valueObjects) {
|
|
232
|
+
Object.entries(config.domain.valueObjects).forEach(([name, voConfig]) => {
|
|
233
|
+
result[name] = {
|
|
234
|
+
code: this.generateValueObject(name, voConfig),
|
|
235
|
+
type: 'valueObject'
|
|
236
|
+
};
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
// Generate aggregates
|
|
240
|
+
const childEntityMap = (0, childEntityUtils_1.buildChildEntityMap)(config);
|
|
241
|
+
if (config.domain.aggregates) {
|
|
242
|
+
Object.entries(config.domain.aggregates).forEach(([name, aggConfig]) => {
|
|
243
|
+
const childInfo = childEntityMap.get(name);
|
|
244
|
+
result[name] = {
|
|
245
|
+
code: this.generateAggregate(name, aggConfig, config.domain.aggregates, childInfo),
|
|
246
|
+
type: 'entity'
|
|
247
|
+
};
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
return result;
|
|
251
|
+
}
|
|
252
|
+
generateFromYamlFile(yamlFilePath) {
|
|
253
|
+
const yamlContent = fs.readFileSync(yamlFilePath, 'utf8');
|
|
254
|
+
const config = (0, yaml_1.parse)(yamlContent);
|
|
255
|
+
if (!(0, configTypes_1.isValidModuleConfig)(config)) {
|
|
256
|
+
throw new Error('Configuration does not match new module format. Expected domain.aggregates structure.');
|
|
257
|
+
}
|
|
258
|
+
return this.generateFromConfig(config);
|
|
259
|
+
}
|
|
260
|
+
async generateAndSaveFiles(yamlFilePath, moduleDir, opts) {
|
|
261
|
+
const codeByEntity = this.generateFromYamlFile(yamlFilePath);
|
|
262
|
+
const entitiesDir = path.join(moduleDir, 'domain', 'entities');
|
|
263
|
+
const valueObjectsDir = path.join(moduleDir, 'domain', 'valueObjects');
|
|
264
|
+
fs.mkdirSync(entitiesDir, { recursive: true });
|
|
265
|
+
fs.mkdirSync(valueObjectsDir, { recursive: true });
|
|
266
|
+
for (const [name, { code, type }] of Object.entries(codeByEntity)) {
|
|
267
|
+
const outputDir = type === 'valueObject' ? valueObjectsDir : entitiesDir;
|
|
268
|
+
const filePath = path.join(outputDir, `${name}.ts`);
|
|
269
|
+
// eslint-disable-next-line no-await-in-loop
|
|
270
|
+
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) });
|
|
271
|
+
}
|
|
272
|
+
// eslint-disable-next-line no-console
|
|
273
|
+
console.log('\n' + colors_1.colors.green('Domain layer files generated successfully!') + '\n');
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
exports.DomainLayerGenerator = DomainLayerGenerator;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ModuleConfig } from '../types/configTypes';
|
|
2
|
+
export declare class DtoGenerator {
|
|
3
|
+
private availableAggregates;
|
|
4
|
+
private availableValueObjects;
|
|
5
|
+
private mapType;
|
|
6
|
+
private isValueObjectType;
|
|
7
|
+
private getValidationCode;
|
|
8
|
+
private getTransformCode;
|
|
9
|
+
private generateInputDto;
|
|
10
|
+
private generateOutputDto;
|
|
11
|
+
/**
|
|
12
|
+
* Collect types that need to be imported for a use case DTO.
|
|
13
|
+
*/
|
|
14
|
+
private collectRequiredImports;
|
|
15
|
+
generateFromConfig(config: ModuleConfig): Record<string, string>;
|
|
16
|
+
generateFromYamlFile(yamlFilePath: string): Record<string, string>;
|
|
17
|
+
generateAndSaveFiles(yamlFilePath: string, moduleDir: string, opts?: {
|
|
18
|
+
force?: boolean;
|
|
19
|
+
skipOnConflict?: boolean;
|
|
20
|
+
}): Promise<void>;
|
|
21
|
+
}
|