@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.
Files changed (69) hide show
  1. package/CHANGELOG.md +10 -611
  2. package/README.md +623 -427
  3. package/dist/cli.js +2 -1
  4. package/dist/commands/commit.js +25 -42
  5. package/dist/commands/createApp.js +1 -0
  6. package/dist/commands/createModule.js +151 -45
  7. package/dist/commands/diff.js +27 -40
  8. package/dist/commands/generateAll.js +141 -291
  9. package/dist/commands/migrateCommit.js +6 -18
  10. package/dist/commands/migratePush.d.ts +1 -0
  11. package/dist/commands/migratePush.js +135 -0
  12. package/dist/commands/migrateUpdate.d.ts +1 -0
  13. package/dist/commands/migrateUpdate.js +147 -0
  14. package/dist/commands/newGenerateAll.d.ts +4 -0
  15. package/dist/commands/newGenerateAll.js +336 -0
  16. package/dist/generators/controllerGenerator.d.ts +43 -19
  17. package/dist/generators/controllerGenerator.js +547 -329
  18. package/dist/generators/domainLayerGenerator.d.ts +21 -0
  19. package/dist/generators/domainLayerGenerator.js +276 -0
  20. package/dist/generators/dtoGenerator.d.ts +21 -0
  21. package/dist/generators/dtoGenerator.js +518 -0
  22. package/dist/generators/newControllerGenerator.d.ts +55 -0
  23. package/dist/generators/newControllerGenerator.js +644 -0
  24. package/dist/generators/newServiceGenerator.d.ts +19 -0
  25. package/dist/generators/newServiceGenerator.js +266 -0
  26. package/dist/generators/newStoreGenerator.d.ts +39 -0
  27. package/dist/generators/newStoreGenerator.js +408 -0
  28. package/dist/generators/newTemplateGenerator.d.ts +29 -0
  29. package/dist/generators/newTemplateGenerator.js +510 -0
  30. package/dist/generators/serviceGenerator.d.ts +16 -51
  31. package/dist/generators/serviceGenerator.js +167 -586
  32. package/dist/generators/storeGenerator.d.ts +35 -32
  33. package/dist/generators/storeGenerator.js +291 -238
  34. package/dist/generators/storeGeneratorV2.d.ts +31 -0
  35. package/dist/generators/storeGeneratorV2.js +190 -0
  36. package/dist/generators/templateGenerator.d.ts +21 -21
  37. package/dist/generators/templateGenerator.js +393 -268
  38. package/dist/generators/templates/appTemplates.d.ts +3 -1
  39. package/dist/generators/templates/appTemplates.js +15 -10
  40. package/dist/generators/templates/data/appYamlTemplate +5 -2
  41. package/dist/generators/templates/data/cursorRulesTemplate +315 -221
  42. package/dist/generators/templates/data/frontendScriptTemplate +45 -11
  43. package/dist/generators/templates/data/mainViewTemplate +1 -1
  44. package/dist/generators/templates/data/systemTsTemplate +5 -0
  45. package/dist/generators/templates/index.d.ts +0 -3
  46. package/dist/generators/templates/index.js +0 -3
  47. package/dist/generators/templates/newStoreTemplates.d.ts +5 -0
  48. package/dist/generators/templates/newStoreTemplates.js +141 -0
  49. package/dist/generators/templates/storeTemplates.d.ts +1 -5
  50. package/dist/generators/templates/storeTemplates.js +102 -219
  51. package/dist/generators/templates/viewTemplates.js +1 -1
  52. package/dist/generators/useCaseGenerator.d.ts +13 -0
  53. package/dist/generators/useCaseGenerator.js +188 -0
  54. package/dist/types/configTypes.d.ts +148 -0
  55. package/dist/types/configTypes.js +10 -0
  56. package/dist/utils/childEntityUtils.d.ts +18 -0
  57. package/dist/utils/childEntityUtils.js +78 -0
  58. package/dist/utils/commandUtils.d.ts +43 -0
  59. package/dist/utils/commandUtils.js +124 -0
  60. package/dist/utils/commitUtils.d.ts +4 -1
  61. package/dist/utils/constants.d.ts +10 -0
  62. package/dist/utils/constants.js +13 -1
  63. package/dist/utils/diResolver.d.ts +32 -0
  64. package/dist/utils/diResolver.js +204 -0
  65. package/dist/utils/new_parts_of_migrationUtils.d.ts +0 -0
  66. package/dist/utils/new_parts_of_migrationUtils.js +164 -0
  67. package/dist/utils/typeUtils.d.ts +19 -0
  68. package/dist/utils/typeUtils.js +70 -0
  69. package/package.json +7 -3
@@ -0,0 +1,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
+ }