@currentjs/gen 0.5.1 → 0.5.2

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.
@@ -38,6 +38,7 @@ const fs = __importStar(require("fs"));
38
38
  const path = __importStar(require("path"));
39
39
  const cliUtils_1 = require("../utils/cliUtils");
40
40
  const yaml_1 = require("yaml");
41
+ const colors_1 = require("../utils/colors");
41
42
  function moduleYamlTemplate(moduleName) {
42
43
  const entityName = moduleName.charAt(0).toUpperCase() + moduleName.slice(1);
43
44
  const lower = moduleName.charAt(0).toLowerCase() + moduleName.slice(1);
@@ -226,4 +227,16 @@ function handleCreateModule(name) {
226
227
  appConfig.modules[moduleKey] = { path: moduleYamlRel };
227
228
  }
228
229
  fs.writeFileSync(appYamlPath, (0, yaml_1.stringify)(appConfig), 'utf8');
230
+ const output = `
231
+ ${colors_1.colors.green(`Module ${colors_1.colors.bold(name)} has been created`)}
232
+
233
+ Run command ${colors_1.colors.green(colors_1.colors.bold(`current create model ${name}:modelname`))}
234
+ where ${colors_1.colors.italic(colors_1.colors.yellow('modelname'))} is name of the model in your module.
235
+ At the end, that command will suggest you to create CRUD actions for the model and further steps.
236
+ You can run this command as many times as needed.
237
+
238
+ Alternatively, you may consider modifying module's config manually, and then run ${colors_1.colors.bold(colors_1.colors.green('current generate'))}
239
+ ${colors_1.colors.gray('config:')} ${colors_1.colors.cyan(colors_1.colors.italic(moduleYamlFile))}
240
+ `;
241
+ console.log(output);
229
242
  }
@@ -1,4 +1,5 @@
1
1
  export declare function handleGenerateAll(yamlPathArg?: string, _outArg?: string, moduleName?: string, opts?: {
2
2
  force?: boolean;
3
3
  skip?: boolean;
4
+ withTemplates?: boolean;
4
5
  }): Promise<void>;
@@ -94,7 +94,7 @@ async function handleGenerateAll(yamlPathArg, _outArg, moduleName, opts) {
94
94
  // eslint-disable-next-line no-await-in-loop
95
95
  await controllerGen.generateAndSaveFiles(moduleYamlPath, moduleDir, opts);
96
96
  // eslint-disable-next-line no-await-in-loop
97
- await templateGen.generateAndSaveFiles(moduleYamlPath, moduleDir, opts);
97
+ await templateGen.generateAndSaveFiles(moduleYamlPath, moduleDir, { force: opts === null || opts === void 0 ? void 0 : opts.force, skipOnConflict: opts === null || opts === void 0 ? void 0 : opts.skip, onlyIfMissing: !(opts === null || opts === void 0 ? void 0 : opts.withTemplates) });
98
98
  // Find srcDir by probing upward for app.ts
99
99
  let probeDir = moduleDir;
100
100
  let srcDir = null;
@@ -0,0 +1 @@
1
+ export declare function handleInit(rawName?: string): void;
@@ -33,11 +33,11 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.handleCreateApp = handleCreateApp;
36
+ exports.handleInit = handleInit;
37
37
  const path = __importStar(require("path"));
38
38
  const cliUtils_1 = require("../utils/cliUtils");
39
39
  const appTemplates_1 = require("../generators/templates/appTemplates");
40
- function handleCreateApp(rawName) {
40
+ function handleInit(rawName) {
41
41
  const targetRoot = rawName ? (0, cliUtils_1.toAbsolute)(rawName) : process.cwd();
42
42
  (0, cliUtils_1.ensureDir)(targetRoot);
43
43
  // Basic structure using constants
@@ -39,70 +39,41 @@ const path = __importStar(require("path"));
39
39
  const yaml_1 = require("yaml");
40
40
  const colors_1 = require("../utils/colors");
41
41
  const cliUtils_1 = require("../utils/cliUtils");
42
+ const commandUtils_1 = require("../utils/commandUtils");
43
+ const configTypes_1 = require("../types/configTypes");
42
44
  const migrationUtils_1 = require("../utils/migrationUtils");
43
- function collectModelsFromYaml(yamlPath) {
44
- const yamlContent = fs.readFileSync(yamlPath, 'utf8');
45
- const config = (0, yaml_1.parse)(yamlContent);
46
- const projectRoot = path.dirname(yamlPath);
47
- const allModels = [];
45
+ function collectAggregatesFromModules(appYamlPath) {
46
+ const appConfig = (0, commandUtils_1.loadAppConfig)(appYamlPath);
47
+ const moduleEntries = (0, commandUtils_1.getModuleEntries)(appConfig);
48
+ const projectRoot = path.dirname(appYamlPath);
49
+ const allAggregates = {};
48
50
  const sources = [];
49
- // Check if it's a module YAML (has models directly)
50
- if (config.models) {
51
- allModels.push(...config.models);
52
- sources.push(`app.yaml (${config.models.length} model(s))`);
53
- }
54
- // App YAML: modules as Record<string, { path }> — resolve path and read module YAML for .models
55
- if (config.modules && typeof config.modules === 'object' && !Array.isArray(config.modules)) {
56
- let moduleCount = 0;
57
- for (const entry of Object.values(config.modules)) {
58
- const modulePath = entry.path;
59
- if (!modulePath)
60
- continue;
61
- const moduleYamlPath = path.isAbsolute(modulePath)
62
- ? modulePath
63
- : path.resolve(projectRoot, modulePath);
64
- if (fs.existsSync(moduleYamlPath)) {
65
- const moduleYamlContent = fs.readFileSync(moduleYamlPath, 'utf8');
66
- const moduleConfig = (0, yaml_1.parse)(moduleYamlContent);
67
- if (moduleConfig.models) {
68
- allModels.push(...moduleConfig.models);
69
- moduleCount++;
70
- }
71
- }
72
- }
73
- if (moduleCount > 0) {
74
- sources.push(`app.yaml modules section (${moduleCount} module(s))`);
75
- }
76
- }
77
- // Also check for module YAMLs in src/modules/*/module.yaml (as fallback)
78
- const modulesDir = path.join(projectRoot, 'src', 'modules');
79
- if (fs.existsSync(modulesDir)) {
80
- const moduleFolders = fs.readdirSync(modulesDir).filter(f => {
81
- const stat = fs.statSync(path.join(modulesDir, f));
82
- return stat.isDirectory();
83
- });
84
- let moduleYamlCount = 0;
85
- for (const moduleFolder of moduleFolders) {
86
- const moduleYamlPath = path.join(modulesDir, moduleFolder, 'module.yaml');
87
- if (fs.existsSync(moduleYamlPath)) {
88
- const moduleYamlContent = fs.readFileSync(moduleYamlPath, 'utf8');
89
- const moduleConfig = (0, yaml_1.parse)(moduleYamlContent);
90
- if (moduleConfig.models) {
91
- allModels.push(...moduleConfig.models);
92
- moduleYamlCount++;
93
- }
94
- }
51
+ for (const entry of moduleEntries) {
52
+ const moduleYamlPath = path.isAbsolute(entry.path)
53
+ ? entry.path
54
+ : path.resolve(projectRoot, entry.path);
55
+ if (!fs.existsSync(moduleYamlPath)) {
56
+ // eslint-disable-next-line no-console
57
+ console.warn(colors_1.colors.yellow(` Module YAML not found: ${moduleYamlPath}`));
58
+ continue;
95
59
  }
96
- if (moduleYamlCount > 0) {
97
- sources.push(`src/modules/*/module.yaml (${moduleYamlCount} module(s))`);
60
+ const moduleYamlContent = fs.readFileSync(moduleYamlPath, 'utf8');
61
+ const moduleConfig = (0, yaml_1.parse)(moduleYamlContent);
62
+ if (!(0, configTypes_1.isValidModuleConfig)(moduleConfig)) {
63
+ // eslint-disable-next-line no-console
64
+ console.warn(colors_1.colors.yellow(` Skipping ${moduleYamlPath}: not a valid module config (missing domain/useCases)`));
65
+ continue;
98
66
  }
67
+ const aggregates = moduleConfig.domain.aggregates;
68
+ const count = Object.keys(aggregates).length;
69
+ Object.assign(allAggregates, aggregates);
70
+ sources.push(`${entry.name} (${count} aggregate(s))`);
99
71
  }
100
- // Log sources
101
72
  if (sources.length > 0) {
102
73
  // eslint-disable-next-line no-console
103
74
  console.log(colors_1.colors.gray(` Sources: ${sources.join(', ')}`));
104
75
  }
105
- return allModels;
76
+ return allAggregates;
106
77
  }
107
78
  function handleMigrateCommit(yamlPath) {
108
79
  try {
@@ -116,24 +87,21 @@ function handleMigrateCommit(yamlPath) {
116
87
  console.log(colors_1.colors.gray(` Project root: ${projectRoot}`));
117
88
  // eslint-disable-next-line no-console
118
89
  console.log(colors_1.colors.gray(` Migrations dir: ${migrationsDir}`));
119
- // Ensure migrations directory exists
120
90
  if (!fs.existsSync(migrationsDir)) {
121
91
  fs.mkdirSync(migrationsDir, { recursive: true });
122
92
  // eslint-disable-next-line no-console
123
93
  console.log(colors_1.colors.green(` ✓ Created migrations directory`));
124
94
  }
125
- // Collect all models from YAML files
126
95
  // eslint-disable-next-line no-console
127
- console.log(colors_1.colors.cyan('\n📋 Collecting models from all modules...'));
128
- const currentModels = collectModelsFromYaml(resolvedYamlPath);
129
- if (currentModels.length === 0) {
96
+ console.log(colors_1.colors.cyan('\n📋 Collecting aggregates from all modules...'));
97
+ const currentAggregates = collectAggregatesFromModules(resolvedYamlPath);
98
+ if (Object.keys(currentAggregates).length === 0) {
130
99
  // eslint-disable-next-line no-console
131
- console.log(colors_1.colors.yellow('⚠️ No models found in YAML configuration.'));
100
+ console.log(colors_1.colors.yellow('⚠️ No aggregates found in module configuration.'));
132
101
  return;
133
102
  }
134
103
  // eslint-disable-next-line no-console
135
- console.log(colors_1.colors.green(`✓ Found ${currentModels.length} model(s): ${currentModels.map(m => m.name).join(', ')}`));
136
- // Load previous state
104
+ console.log(colors_1.colors.green(`✓ Found ${Object.keys(currentAggregates).length} aggregate(s): ${Object.keys(currentAggregates).join(', ')}`));
137
105
  const oldState = (0, migrationUtils_1.loadSchemaState)(stateFilePath);
138
106
  if (oldState) {
139
107
  // eslint-disable-next-line no-console
@@ -143,16 +111,14 @@ function handleMigrateCommit(yamlPath) {
143
111
  // eslint-disable-next-line no-console
144
112
  console.log(colors_1.colors.cyan('📖 No previous schema state found - will generate initial migration'));
145
113
  }
146
- // Compare schemas and generate SQL
147
114
  // eslint-disable-next-line no-console
148
115
  console.log(colors_1.colors.cyan('\n🔍 Comparing schemas...'));
149
- const sqlStatements = (0, migrationUtils_1.compareSchemas)(oldState, currentModels);
116
+ const sqlStatements = (0, migrationUtils_1.compareSchemas)(oldState, currentAggregates);
150
117
  if (sqlStatements.length === 0 || sqlStatements.every(s => s.trim() === '' || s.startsWith('--'))) {
151
118
  // eslint-disable-next-line no-console
152
119
  console.log(colors_1.colors.yellow('⚠️ No changes detected. Schema is up to date.'));
153
120
  return;
154
121
  }
155
- // Generate migration file
156
122
  const timestamp = (0, migrationUtils_1.generateTimestamp)();
157
123
  const migrationFileName = (0, migrationUtils_1.getMigrationFileName)(timestamp);
158
124
  const migrationFilePath = path.join(migrationsDir, migrationFileName);
@@ -163,9 +129,8 @@ function handleMigrateCommit(yamlPath) {
163
129
  `;
164
130
  const migrationContent = migrationHeader + sqlStatements.join('\n');
165
131
  fs.writeFileSync(migrationFilePath, migrationContent);
166
- // Update state file
167
132
  const newState = {
168
- models: currentModels,
133
+ aggregates: currentAggregates,
169
134
  version: timestamp,
170
135
  timestamp: new Date().toISOString()
171
136
  };
@@ -215,12 +215,45 @@ class DomainLayerGenerator {
215
215
  }`;
216
216
  })
217
217
  .join('\n');
218
+ // Generate validation logic from field constraints
219
+ // we don't use constraints at models, since we use DTOs (use cases) for validation
220
+ // Model – is a place not for validation, but for business logic!
221
+ // kept this code for reference
222
+ /*
223
+ const validations: string[] = [];
224
+ sortedFields.forEach(([fieldName, fieldConfig]) => {
225
+ const { constraints } = fieldConfig;
226
+ if (!constraints) return;
227
+
228
+ if (constraints.min !== undefined) {
229
+ validations.push(` if (this.${fieldName} < ${constraints.min}) {
230
+ throw new Error('${name}.${fieldName} must be at least ${constraints.min}');
231
+ }`);
232
+ }
233
+ if (constraints.max !== undefined) {
234
+ validations.push(` if (this.${fieldName} > ${constraints.max}) {
235
+ throw new Error('${name}.${fieldName} must be at most ${constraints.max}');
236
+ }`);
237
+ }
238
+ if (constraints.pattern) {
239
+ validations.push(` if (!/${constraints.pattern}/.test(String(this.${fieldName}))) {
240
+ throw new Error('${name}.${fieldName} does not match required pattern');
241
+ }`);
242
+ }
243
+ });
244
+
245
+ const constructorBody = validations.length > 0
246
+ ? `\n this.validate();\n }\n\n private validate(): void {\n${validations.join('\n')}\n }`
247
+ : ' }';
248
+ */
249
+ const constructorBody = '';
218
250
  const rootComment = config.root ? '// Aggregate Root\n' : '';
219
251
  const enumTypeDefsCode = enumTypeDefinitions.length > 0 ? enumTypeDefinitions.join('\n') + '\n\n' : '';
220
252
  return `${imports ? imports + '\n\n' : ''}${enumTypeDefsCode}${rootComment}export class ${name} {
221
253
  public constructor(
222
254
  ${constructorParamsStr}
223
- ) { }
255
+ ) {${constructorBody}
256
+ }
224
257
  ${setterMethods}
225
258
  }`;
226
259
  }
@@ -26,5 +26,6 @@ export declare class TemplateGenerator {
26
26
  generateAndSaveFiles(yamlFilePath: string, moduleDir: string, opts?: {
27
27
  force?: boolean;
28
28
  skipOnConflict?: boolean;
29
+ onlyIfMissing?: boolean;
29
30
  }): Promise<void>;
30
31
  }
@@ -458,16 +458,22 @@ ${options}
458
458
  return this.generateFromConfig(config);
459
459
  }
460
460
  async generateAndSaveFiles(yamlFilePath, moduleDir, opts) {
461
+ let isGenerated = false;
461
462
  const templatesByName = this.generateFromYamlFile(yamlFilePath);
462
463
  const viewsDir = path.join(moduleDir, 'views');
463
464
  fs.mkdirSync(viewsDir, { recursive: true });
464
465
  for (const [name, content] of Object.entries(templatesByName)) {
465
466
  const filePath = path.join(viewsDir, `${name}.html`);
467
+ if ((opts === null || opts === void 0 ? void 0 : opts.onlyIfMissing) && fs.existsSync(filePath))
468
+ continue;
466
469
  // eslint-disable-next-line no-await-in-loop
467
470
  await (0, generationRegistry_1.writeGeneratedFile)(filePath, content, { force: !!(opts === null || opts === void 0 ? void 0 : opts.force), skipOnConflict: !!(opts === null || opts === void 0 ? void 0 : opts.skipOnConflict) });
471
+ isGenerated = true;
472
+ }
473
+ if (isGenerated) {
474
+ // eslint-disable-next-line no-console
475
+ console.log('\n' + colors_1.colors.green('Template files generated successfully!') + '\n');
468
476
  }
469
- // eslint-disable-next-line no-console
470
- console.log('\n' + colors_1.colors.green('Template files generated successfully!') + '\n');
471
477
  }
472
478
  }
473
479
  exports.TemplateGenerator = TemplateGenerator;