stackkit 0.1.4 → 0.1.6

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.
@@ -45,13 +45,13 @@ class AdvancedCodeGenerator {
45
45
  this.frameworkConfig = frameworkConfig;
46
46
  }
47
47
  async loadGenerators(modulesPath) {
48
- const moduleTypes = ['auth', 'database'];
48
+ const moduleTypes = ["auth", "database"];
49
49
  for (const type of moduleTypes) {
50
50
  const typePath = path.join(modulesPath, type);
51
51
  if (await fs.pathExists(typePath)) {
52
52
  const modules = await fs.readdir(typePath);
53
53
  for (const moduleName of modules) {
54
- const generatorPath = path.join(typePath, moduleName, 'generator.json');
54
+ const generatorPath = path.join(typePath, moduleName, "generator.json");
55
55
  if (await fs.pathExists(generatorPath)) {
56
56
  try {
57
57
  const config = await fs.readJson(generatorPath);
@@ -71,10 +71,10 @@ class AdvancedCodeGenerator {
71
71
  if (!condition)
72
72
  return true;
73
73
  for (const [key, value] of Object.entries(condition)) {
74
- if (key === 'features') {
74
+ if (key === "features") {
75
75
  const requiredFeatures = value;
76
76
  const contextFeatures = context.features || [];
77
- if (!requiredFeatures.every(feature => contextFeatures.includes(feature))) {
77
+ if (!requiredFeatures.every((feature) => contextFeatures.includes(feature))) {
78
78
  return false;
79
79
  }
80
80
  }
@@ -101,19 +101,19 @@ class AdvancedCodeGenerator {
101
101
  // Process the rest of the template with the extended context
102
102
  content = this.processTemplateRecursive(content, templateContext);
103
103
  // Remove leading newlines that might be left from {{#var}} removal
104
- content = content.replace(/^\n+/, '');
104
+ content = content.replace(/^\n+/, "");
105
105
  // Reduce multiple consecutive newlines to maximum 2
106
- content = content.replace(/\n{3,}/g, '\n\n');
106
+ content = content.replace(/\n{3,}/g, "\n\n");
107
107
  return content;
108
108
  }
109
109
  processVariableDefinitions(content, context) {
110
110
  let result = content;
111
111
  let index = 0;
112
112
  while (true) {
113
- const varStart = result.indexOf('{{#var ', index);
113
+ const varStart = result.indexOf("{{#var ", index);
114
114
  if (varStart === -1)
115
115
  break;
116
- const equalsIndex = result.indexOf('=', varStart);
116
+ const equalsIndex = result.indexOf("=", varStart);
117
117
  if (equalsIndex === -1)
118
118
  break;
119
119
  const varNameMatch = result.substring(varStart + 7, equalsIndex).trim();
@@ -125,11 +125,11 @@ class AdvancedCodeGenerator {
125
125
  const valueStart = equalsIndex + 1;
126
126
  let valueEnd = valueStart;
127
127
  for (let i = valueStart; i < result.length; i++) {
128
- if (result[i] === '{' && result[i + 1] === '{') {
128
+ if (result[i] === "{" && result[i + 1] === "{") {
129
129
  braceCount++;
130
130
  i++; // Skip next character
131
131
  }
132
- else if (result[i] === '}' && result[i + 1] === '}') {
132
+ else if (result[i] === "}" && result[i + 1] === "}") {
133
133
  braceCount--;
134
134
  if (braceCount === 0) {
135
135
  valueEnd = i;
@@ -146,71 +146,74 @@ class AdvancedCodeGenerator {
146
146
  const processedValue = this.processTemplateRecursive(varValue, context);
147
147
  context[varNameMatch] = processedValue;
148
148
  // Remove the variable definition
149
- result = result.replace(fullMatch, '');
149
+ result = result.replace(fullMatch, "");
150
150
  index = varStart;
151
151
  }
152
152
  return result;
153
153
  }
154
154
  processTemplateRecursive(content, context) {
155
- content = content.replace(/\{\{#if\s+([^}\s]+)\s+([^}\s]+)\s+([^}]+)\}\}([\s\S]*?)\{\{\/if\}\}/g, (match, varName, operator, expectedValue, blockContent) => {
155
+ content = content.replace(/\{\{#if\s+([^}\s]+)\s+([^}\s]+)\s+([^}]+)\}\}([\s\S]*?)(?:\{\{else\}\}([\s\S]*?))?\{\{\/if\}\}/g, (match, varName, operator, expectedValue, blockContent, elseContent) => {
156
156
  const actualVal = context[varName.trim()];
157
- const cleanExpectedVal = expectedValue.trim().replace(/['"]/g, '');
157
+ const cleanExpectedVal = expectedValue.trim().replace(/['"]/g, "");
158
158
  let conditionMet = false;
159
159
  switch (operator) {
160
- case '==':
161
- case '===':
160
+ case "==":
161
+ case "===":
162
162
  conditionMet = actualVal === cleanExpectedVal;
163
163
  break;
164
- case '!=':
165
- case '!==':
164
+ case "!=":
165
+ case "!==":
166
166
  conditionMet = actualVal !== cleanExpectedVal;
167
167
  break;
168
- case 'includes':
168
+ case "includes":
169
169
  conditionMet = Array.isArray(actualVal) && actualVal.includes(cleanExpectedVal);
170
170
  break;
171
- case 'startsWith':
172
- conditionMet = typeof actualVal === 'string' && actualVal.startsWith(cleanExpectedVal);
171
+ case "startsWith":
172
+ conditionMet = typeof actualVal === "string" && actualVal.startsWith(cleanExpectedVal);
173
173
  break;
174
- case 'endsWith':
175
- conditionMet = typeof actualVal === 'string' && actualVal.endsWith(cleanExpectedVal);
174
+ case "endsWith":
175
+ conditionMet = typeof actualVal === "string" && actualVal.endsWith(cleanExpectedVal);
176
176
  break;
177
177
  }
178
- return conditionMet ? this.processTemplateRecursive(blockContent, context).replace(/^\n+/, '').replace(/\n+$/, '') : '';
178
+ const contentToProcess = conditionMet ? blockContent : (elseContent || "");
179
+ return this.processTemplateRecursive(contentToProcess, context)
180
+ .replace(/^\n+/, "")
181
+ .replace(/\n+$/, "");
179
182
  });
180
183
  // Handle simple conditional blocks {{#if condition}}...{{/if}} (backward compatibility)
181
- content = content.replace(/\{\{#if\s+([^}]+)\}\}([\s\S]*?)\{\{\/if\}\}/g, (match, condition, blockContent) => {
182
- const conditionParts = condition.split('==');
184
+ content = content.replace(/\{\{#if\s+([^}]+)\}\}([\s\S]*?)(?:\{\{else\}\}([\s\S]*?))?\{\{\/if\}\}/g, (match, condition, blockContent, elseContent) => {
185
+ const conditionParts = condition.split("==");
183
186
  if (conditionParts.length === 2) {
184
- const [varName, expectedValue] = conditionParts.map((s) => s.trim().replace(/['"]/g, ''));
185
- if (context[varName] === expectedValue) {
186
- return this.processTemplateRecursive(blockContent, context).replace(/^\n+/, '').replace(/\n+$/, '');
187
- }
188
- return '';
187
+ const [varName, expectedValue] = conditionParts.map((s) => s.trim().replace(/['"]/g, ""));
188
+ const contentToProcess = context[varName] === expectedValue ? blockContent : (elseContent || "");
189
+ return this.processTemplateRecursive(contentToProcess, context)
190
+ .replace(/^\n+/, "")
191
+ .replace(/\n+$/, "");
189
192
  }
190
- const conditionFunc = condition.split('.');
191
- if (conditionFunc.length === 2 && conditionFunc[1] === 'includes') {
192
- const [arrayName, item] = conditionFunc[0].split('(');
193
- const itemValue = item.replace(')', '').replace(/['"]/g, '');
193
+ const conditionFunc = condition.split(".");
194
+ if (conditionFunc.length === 2 && conditionFunc[1] === "includes") {
195
+ const [arrayName, item] = conditionFunc[0].split("(");
196
+ const itemValue = item.replace(")", "").replace(/['"]/g, "");
194
197
  const array = context[arrayName] || [];
195
- if (Array.isArray(array) && array.includes(itemValue)) {
196
- return this.processTemplateRecursive(blockContent, context).replace(/^\n+/, '').replace(/\n+$/, '');
197
- }
198
- return '';
198
+ const contentToProcess = Array.isArray(array) && array.includes(itemValue) ? blockContent : (elseContent || "");
199
+ return this.processTemplateRecursive(contentToProcess, context)
200
+ .replace(/^\n+/, "")
201
+ .replace(/\n+$/, "");
199
202
  }
200
- return '';
203
+ return "";
201
204
  });
202
205
  // Handle switch statements {{#switch variable}}...{{/switch}}
203
206
  content = content.replace(/\{\{#switch\s+([^}]+)\}\}([\s\S]*?)\{\{\/switch\}\}/g, (match, varName, switchContent) => {
204
207
  const actualVal = context[varName.trim()];
205
208
  // Parse cases
206
- const caseRegex = /\{\{#case\s+([^}]+)\}\}([\s\S]*?)(?=\{\{#case|\{\{\/switch\})/g;
207
- let result = '';
208
- let defaultCase = '';
209
+ const caseRegex = /\{\{#case\s+([^}]+)\}\}([\s\S]*?)(?=\{\{#case|\{\{\/case\}|\{\{\/switch\})/g;
210
+ let result = "";
211
+ let defaultCase = "";
209
212
  let caseMatch;
210
213
  while ((caseMatch = caseRegex.exec(switchContent)) !== null) {
211
214
  const [, caseValue, caseContent] = caseMatch;
212
- const cleanCaseValue = caseValue.trim().replace(/['"]/g, '');
213
- if (cleanCaseValue === 'default') {
215
+ const cleanCaseValue = caseValue.trim().replace(/['"]/g, "");
216
+ if (cleanCaseValue === "default") {
214
217
  defaultCase = caseContent;
215
218
  }
216
219
  else if (actualVal === cleanCaseValue) {
@@ -218,7 +221,7 @@ class AdvancedCodeGenerator {
218
221
  break;
219
222
  }
220
223
  }
221
- return result || defaultCase || '';
224
+ return result || defaultCase || "";
222
225
  });
223
226
  // Handle variable replacement with advanced expressions
224
227
  content = content.replace(/\{\{([^}]+)\}\}/g, (match, varExpr) => {
@@ -231,10 +234,10 @@ class AdvancedCodeGenerator {
231
234
  if (conditionMatch) {
232
235
  const [, varName, expectedVal] = conditionMatch;
233
236
  const cleanVarName = varName.trim();
234
- const cleanExpectedVal = expectedVal.trim().replace(/['"]/g, '');
237
+ const cleanExpectedVal = expectedVal.trim().replace(/['"]/g, "");
235
238
  const actualVal = context[cleanVarName];
236
239
  const result = actualVal === cleanExpectedVal ? trueVal.trim() : falseVal.trim();
237
- return result.replace(/['"]/g, ''); // Remove quotes from result
240
+ return result.replace(/['"]/g, ""); // Remove quotes from result
238
241
  }
239
242
  }
240
243
  // Handle switch expressions {{switch variable case1: value1, case2: value2, default: defaultValue}}
@@ -242,21 +245,21 @@ class AdvancedCodeGenerator {
242
245
  if (switchMatch) {
243
246
  const [, varName, casesStr] = switchMatch;
244
247
  const actualVal = context[varName.trim()];
245
- const cases = casesStr.split(',').map((c) => c.trim());
248
+ const cases = casesStr.split(",").map((c) => c.trim());
246
249
  for (const caseStr of cases) {
247
- const [caseVal, result] = caseStr.split(':').map((s) => s.trim());
248
- const cleanCaseVal = caseVal.replace(/['"]/g, '');
249
- if (cleanCaseVal === actualVal || cleanCaseVal === 'default') {
250
- return result.replace(/['"]/g, '');
250
+ const [caseVal, result] = caseStr.split(":").map((s) => s.trim());
251
+ const cleanCaseVal = caseVal.replace(/['"]/g, "");
252
+ if (cleanCaseVal === actualVal || cleanCaseVal === "default") {
253
+ return result.replace(/['"]/g, "");
251
254
  }
252
255
  }
253
- return '';
256
+ return "";
254
257
  }
255
258
  // Handle feature flags {{feature:name}}
256
- if (trimmedExpr.startsWith('feature:')) {
259
+ if (trimmedExpr.startsWith("feature:")) {
257
260
  const featureName = trimmedExpr.substring(8);
258
261
  const features = context.features || [];
259
- return features.includes(featureName) ? 'true' : 'false';
262
+ return features.includes(featureName) ? "true" : "false";
260
263
  }
261
264
  // Handle conditional expressions {{if condition then:value else:value}}
262
265
  const conditionalMatch = trimmedExpr.match(/^if\s+(.+?)\s+then:([^,]+),\s*else:(.+)$/);
@@ -266,10 +269,10 @@ class AdvancedCodeGenerator {
266
269
  if (conditionMatch2) {
267
270
  const [, varName, expectedVal] = conditionMatch2;
268
271
  const cleanVarName = varName.trim();
269
- const cleanExpectedVal = expectedVal.trim().replace(/['"]/g, '');
272
+ const cleanExpectedVal = expectedVal.trim().replace(/['"]/g, "");
270
273
  const actualVal = context[cleanVarName];
271
274
  const result = actualVal === cleanExpectedVal ? thenVal.trim() : elseVal.trim();
272
- return result.replace(/['"]/g, '');
275
+ return result.replace(/['"]/g, "");
273
276
  }
274
277
  }
275
278
  // Simple variable replacement
@@ -286,21 +289,21 @@ class AdvancedCodeGenerator {
286
289
  features,
287
290
  };
288
291
  // Set default prismaProvider if database is prisma but no provider specified
289
- if (selectedModules.database === 'prisma' && !context.prismaProvider) {
290
- context.prismaProvider = 'postgresql';
292
+ if (selectedModules.database === "prisma" && !context.prismaProvider) {
293
+ context.prismaProvider = "postgresql";
291
294
  }
292
295
  // Collect all applicable operations
293
296
  const applicableOperations = [];
294
297
  for (const [key, generator] of this.generators) {
295
- const [genType, name] = key.split(':');
298
+ const [genType, name] = key.split(":");
296
299
  // Check if this generator is selected
297
- if (genType === 'framework' && name === selectedModules.framework) {
300
+ if (genType === "framework" && name === selectedModules.framework) {
298
301
  // Framework is always included
299
302
  }
300
- else if (genType === 'database' && name === selectedModules.database) {
303
+ else if (genType === "database" && name === selectedModules.database) {
301
304
  // Database is selected
302
305
  }
303
- else if (genType === 'auth' && name === selectedModules.auth) {
306
+ else if (genType === "auth" && name === selectedModules.auth) {
304
307
  // Auth is selected
305
308
  }
306
309
  else {
@@ -341,22 +344,22 @@ class AdvancedCodeGenerator {
341
344
  // Process templates in operation content
342
345
  const processedOperation = this.processOperationTemplates(operation, context);
343
346
  switch (processedOperation.type) {
344
- case 'create-file':
347
+ case "create-file":
345
348
  await this.executeCreateFile(processedOperation, context, outputPath);
346
349
  break;
347
- case 'patch-file':
350
+ case "patch-file":
348
351
  await this.executePatchFile(processedOperation, context, outputPath);
349
352
  break;
350
- case 'add-dependency':
353
+ case "add-dependency":
351
354
  await this.executeAddDependency(processedOperation, context, outputPath);
352
355
  break;
353
- case 'add-script':
356
+ case "add-script":
354
357
  await this.executeAddScript(processedOperation, context, outputPath);
355
358
  break;
356
- case 'add-env':
359
+ case "add-env":
357
360
  await this.executeAddEnv(processedOperation, context, outputPath);
358
361
  break;
359
- case 'run-command':
362
+ case "run-command":
360
363
  this.executeRunCommand(processedOperation, context);
361
364
  break;
362
365
  default:
@@ -365,15 +368,15 @@ class AdvancedCodeGenerator {
365
368
  }
366
369
  async copyTemplate(frameworkName, outputPath) {
367
370
  const packageRoot = (0, package_root_1.getPackageRoot)();
368
- const templatePath = path.join(packageRoot, 'templates', frameworkName);
371
+ const templatePath = path.join(packageRoot, "templates", frameworkName);
369
372
  if (await fs.pathExists(templatePath)) {
370
373
  await fs.copy(templatePath, outputPath, {
371
374
  filter: (src) => {
372
375
  const relativePath = path.relative(templatePath, src);
373
- return relativePath !== 'template.json' &&
374
- relativePath !== 'node_modules' &&
375
- !relativePath.startsWith('node_modules/');
376
- }
376
+ return (relativePath !== "template.json" &&
377
+ relativePath !== "node_modules" &&
378
+ !relativePath.startsWith("node_modules/"));
379
+ },
377
380
  });
378
381
  }
379
382
  }
@@ -394,10 +397,10 @@ class AdvancedCodeGenerator {
394
397
  }
395
398
  // Process templates in patch operations
396
399
  if (processed.operations) {
397
- processed.operations = processed.operations.map(op => {
400
+ processed.operations = processed.operations.map((op) => {
398
401
  const processedOp = { ...op };
399
402
  if (processedOp.imports) {
400
- processedOp.imports = processedOp.imports.map(imp => this.processTemplate(imp, context));
403
+ processedOp.imports = processedOp.imports.map((imp) => this.processTemplate(imp, context));
401
404
  }
402
405
  if (processedOp.code) {
403
406
  processedOp.code = this.processTemplate(processedOp.code, context);
@@ -434,9 +437,9 @@ class AdvancedCodeGenerator {
434
437
  content = this.processTemplate(operation.content, context);
435
438
  }
436
439
  else if (operation.source) {
437
- const sourcePath = (0, generator_utils_1.locateOperationSource)(operation.generatorType, operation.generator, operation.source || '');
438
- if (sourcePath && await fs.pathExists(sourcePath)) {
439
- content = await fs.readFile(sourcePath, 'utf-8');
440
+ const sourcePath = (0, generator_utils_1.locateOperationSource)(operation.generatorType, operation.generator, operation.source || "");
441
+ if (sourcePath && (await fs.pathExists(sourcePath))) {
442
+ content = await fs.readFile(sourcePath, "utf-8");
440
443
  content = this.processTemplate(content, context);
441
444
  }
442
445
  else {
@@ -447,14 +450,14 @@ class AdvancedCodeGenerator {
447
450
  throw new Error(`Create file operation must have either 'content' or 'source' field`);
448
451
  }
449
452
  // Write destination file
450
- await fs.writeFile(destinationPath, content, 'utf-8');
453
+ await fs.writeFile(destinationPath, content, "utf-8");
451
454
  }
452
455
  async executePatchFile(operation, context, outputPath) {
453
456
  if (!operation.destination)
454
457
  return;
455
458
  const filePath = path.join(outputPath, this.processTemplate(operation.destination, context));
456
459
  // Read existing file
457
- let content = await fs.readFile(filePath, 'utf-8');
460
+ let content = await fs.readFile(filePath, "utf-8");
458
461
  if (operation.content) {
459
462
  content += this.processTemplate(operation.content, context).trim();
460
463
  }
@@ -464,14 +467,16 @@ class AdvancedCodeGenerator {
464
467
  if (!this.evaluateCondition(patchOp.condition, context))
465
468
  continue;
466
469
  switch (patchOp.type) {
467
- case 'add-import':
470
+ case "add-import":
468
471
  if (patchOp.imports) {
469
- const imports = patchOp.imports.map(imp => this.processTemplate(imp, context)).join('\n');
472
+ const imports = patchOp.imports
473
+ .map((imp) => this.processTemplate(imp, context))
474
+ .join("\n");
470
475
  // Add imports at the top, after existing imports
471
- const lines = content.split('\n');
476
+ const lines = content.split("\n");
472
477
  let insertIndex = 0;
473
478
  for (let i = 0; i < lines.length; i++) {
474
- if (lines[i].trim().startsWith('import') || lines[i].trim() === '') {
479
+ if (lines[i].trim().startsWith("import") || lines[i].trim() === "") {
475
480
  insertIndex = i + 1;
476
481
  }
477
482
  else {
@@ -479,59 +484,62 @@ class AdvancedCodeGenerator {
479
484
  }
480
485
  }
481
486
  lines.splice(insertIndex, 0, imports);
482
- content = lines.join('\n');
487
+ content = lines.join("\n");
483
488
  }
484
489
  break;
485
- case 'add-code':
490
+ case "add-code":
486
491
  if (patchOp.code && patchOp.after) {
487
492
  const processedCode = this.processTemplate(patchOp.code, context);
488
493
  const afterPattern = this.processTemplate(patchOp.after, context);
489
494
  const index = content.indexOf(afterPattern);
490
495
  if (index !== -1) {
491
- content = content.slice(0, index + afterPattern.length) + processedCode + content.slice(index + afterPattern.length);
496
+ content =
497
+ content.slice(0, index + afterPattern.length) +
498
+ processedCode +
499
+ content.slice(index + afterPattern.length);
492
500
  }
493
501
  }
494
502
  break;
495
- case 'replace-code':
503
+ case "replace-code":
496
504
  if (patchOp.code && patchOp.replace) {
497
505
  const processedCode = this.processTemplate(patchOp.code, context);
498
506
  const replacePattern = this.processTemplate(patchOp.replace, context);
499
507
  content = content.replace(replacePattern, processedCode);
500
508
  }
501
509
  break;
502
- case 'add-to-top': {
503
- let processedContentTop = '';
510
+ case "add-to-top": {
511
+ let processedContentTop = "";
504
512
  if (patchOp.content) {
505
513
  processedContentTop = this.processTemplate(patchOp.content, context).trim();
506
514
  }
507
515
  else if (patchOp.source) {
508
- const modulesPath = path.join((0, package_root_1.getPackageRoot)(), 'modules');
509
- const sourcePath = path.join(modulesPath, operation.generatorType, operation.generator, 'files', patchOp.source);
516
+ const modulesPath = path.join((0, package_root_1.getPackageRoot)(), "modules");
517
+ const sourcePath = path.join(modulesPath, operation.generatorType, operation.generator, "files", patchOp.source);
510
518
  if (await fs.pathExists(sourcePath)) {
511
- processedContentTop = await fs.readFile(sourcePath, 'utf-8');
519
+ processedContentTop = await fs.readFile(sourcePath, "utf-8");
512
520
  processedContentTop = this.processTemplate(processedContentTop, context).trim();
513
521
  }
514
522
  }
515
523
  if (processedContentTop) {
516
- content = processedContentTop + '\n' + content;
524
+ content = processedContentTop + "\n" + content;
517
525
  }
518
526
  break;
519
527
  }
520
- case 'add-to-bottom': {
521
- let processedContentBottom = '';
528
+ case "add-to-bottom": {
529
+ let processedContentBottom = "";
522
530
  if (patchOp.content) {
523
531
  processedContentBottom = this.processTemplate(patchOp.content, context).trim();
524
532
  }
525
533
  else if (patchOp.source) {
526
- const modulesPath = path.join((0, package_root_1.getPackageRoot)(), 'modules');
527
- const sourcePath = path.join(modulesPath, operation.generatorType, operation.generator, 'files', patchOp.source);
534
+ const modulesPath = path.join((0, package_root_1.getPackageRoot)(), "modules");
535
+ const sourcePath = path.join(modulesPath, operation.generatorType, operation.generator, "files", patchOp.source);
528
536
  if (await fs.pathExists(sourcePath)) {
529
- processedContentBottom = await fs.readFile(sourcePath, 'utf-8');
537
+ processedContentBottom = await fs.readFile(sourcePath, "utf-8");
530
538
  processedContentBottom = this.processTemplate(processedContentBottom, context).trim();
531
539
  }
532
540
  }
533
541
  if (processedContentBottom) {
534
- content = content + '\n' + processedContentBottom;
542
+ content = content + "\n" + processedContentBottom;
535
543
  }
536
544
  break;
537
545
  }
@@ -539,44 +547,56 @@ class AdvancedCodeGenerator {
539
547
  }
540
548
  }
541
549
  // Write back the modified content
542
- await fs.writeFile(filePath, content, 'utf-8');
550
+ await fs.writeFile(filePath, content, "utf-8");
543
551
  }
544
552
  async executeAddDependency(operation, context, outputPath) {
545
- const packageJsonPath = path.join(outputPath, 'package.json');
553
+ const packageJsonPath = path.join(outputPath, "package.json");
546
554
  let packageJson = {};
547
555
  if (await fs.pathExists(packageJsonPath)) {
548
556
  packageJson = await fs.readJson(packageJsonPath);
549
557
  }
550
558
  if (operation.dependencies) {
551
- packageJson.dependencies = { ...(packageJson.dependencies || {}), ...operation.dependencies };
559
+ packageJson.dependencies = {
560
+ ...(packageJson.dependencies || {}),
561
+ ...operation.dependencies,
562
+ };
552
563
  }
553
564
  if (operation.devDependencies) {
554
- packageJson.devDependencies = { ...(packageJson.devDependencies || {}), ...operation.devDependencies };
565
+ packageJson.devDependencies = {
566
+ ...(packageJson.devDependencies || {}),
567
+ ...operation.devDependencies,
568
+ };
555
569
  }
556
570
  await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
557
571
  }
558
572
  async executeAddScript(operation, context, outputPath) {
559
- const packageJsonPath = path.join(outputPath, 'package.json');
573
+ const packageJsonPath = path.join(outputPath, "package.json");
560
574
  let packageJson = {};
561
575
  if (await fs.pathExists(packageJsonPath)) {
562
576
  packageJson = await fs.readJson(packageJsonPath);
563
577
  }
564
578
  if (operation.scripts) {
565
- packageJson.scripts = { ...(packageJson.scripts || {}), ...operation.scripts };
579
+ packageJson.scripts = {
580
+ ...(packageJson.scripts || {}),
581
+ ...operation.scripts,
582
+ };
566
583
  }
567
584
  await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
568
585
  }
569
586
  async executeAddEnv(operation, context, outputPath) {
570
- const envPath = path.join(outputPath, '.env');
571
- let envContent = '';
587
+ const envPath = path.join(outputPath, ".env");
588
+ let envContent = "";
572
589
  if (await fs.pathExists(envPath)) {
573
- envContent = await fs.readFile(envPath, 'utf-8');
590
+ envContent = await fs.readFile(envPath, "utf-8");
574
591
  }
575
592
  if (operation.envVars) {
576
- const envLines = Object.entries(operation.envVars).map(([key, value]) => `${key}=${value}`);
577
- envContent += '\n' + envLines.join('\n');
593
+ const envLines = Object.entries(operation.envVars).map(([key, value]) => {
594
+ const processedValue = this.processTemplate(value, context);
595
+ return `${key}=${processedValue}`;
596
+ });
597
+ envContent += "\n" + envLines.join("\n");
578
598
  }
579
- await fs.writeFile(envPath, envContent.trim(), 'utf-8');
599
+ await fs.writeFile(envPath, envContent.trim(), "utf-8");
580
600
  }
581
601
  executeRunCommand(operation, context) {
582
602
  if (operation.command) {
@@ -586,7 +606,7 @@ class AdvancedCodeGenerator {
586
606
  }
587
607
  }
588
608
  async generatePackageJson(selectedModules, features, outputPath) {
589
- const packageJsonPath = path.join(outputPath, 'package.json');
609
+ const packageJsonPath = path.join(outputPath, "package.json");
590
610
  let packageJson = {};
591
611
  if (await fs.pathExists(packageJsonPath)) {
592
612
  packageJson = await fs.readJson(packageJsonPath);
@@ -596,19 +616,28 @@ class AdvancedCodeGenerator {
596
616
  const allDevDeps = {};
597
617
  const allScripts = {};
598
618
  for (const [key, generator] of this.generators) {
599
- const [type, name] = key.split(':');
600
- if ((type === 'framework' && name === selectedModules.framework) ||
601
- (type === 'database' && name === selectedModules.database) ||
602
- (type === 'auth' && name === selectedModules.auth)) {
619
+ const [type, name] = key.split(":");
620
+ if ((type === "framework" && name === selectedModules.framework) ||
621
+ (type === "database" && name === selectedModules.database) ||
622
+ (type === "auth" && name === selectedModules.auth)) {
603
623
  Object.assign(allDeps, generator.dependencies);
604
624
  Object.assign(allDevDeps, generator.devDependencies);
605
625
  Object.assign(allScripts, generator.scripts);
606
626
  }
607
627
  }
608
628
  // Update package.json
609
- packageJson.dependencies = { ...(packageJson.dependencies || {}), ...allDeps };
610
- packageJson.devDependencies = { ...(packageJson.devDependencies || {}), ...allDevDeps };
611
- packageJson.scripts = { ...(packageJson.scripts || {}), ...allScripts };
629
+ packageJson.dependencies = {
630
+ ...(packageJson.dependencies || {}),
631
+ ...allDeps,
632
+ };
633
+ packageJson.devDependencies = {
634
+ ...(packageJson.devDependencies || {}),
635
+ ...allDevDeps,
636
+ };
637
+ packageJson.scripts = {
638
+ ...(packageJson.scripts || {}),
639
+ ...allScripts,
640
+ };
612
641
  await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
613
642
  }
614
643
  /**
@@ -620,19 +649,19 @@ class AdvancedCodeGenerator {
620
649
  ...selectedModules,
621
650
  features,
622
651
  };
623
- if (selectedModules.database === 'prisma' && !context.prismaProvider) {
624
- context.prismaProvider = 'postgresql';
652
+ if (selectedModules.database === "prisma" && !context.prismaProvider) {
653
+ context.prismaProvider = "postgresql";
625
654
  }
626
655
  const applicableOperations = [];
627
656
  for (const [key, generator] of this.generators) {
628
- const [genType, name] = key.split(':');
629
- if (genType === 'framework' && name === selectedModules.framework) {
657
+ const [genType, name] = key.split(":");
658
+ if (genType === "framework" && name === selectedModules.framework) {
630
659
  // framework
631
660
  }
632
- else if (genType === 'database' && name === selectedModules.database) {
661
+ else if (genType === "database" && name === selectedModules.database) {
633
662
  // database
634
663
  }
635
- else if (genType === 'auth' && name === selectedModules.auth) {
664
+ else if (genType === "auth" && name === selectedModules.auth) {
636
665
  // auth
637
666
  }
638
667
  else {
@@ -644,7 +673,12 @@ class AdvancedCodeGenerator {
644
673
  const items = generator.operations || [];
645
674
  for (const item of items) {
646
675
  if (this.evaluateCondition(item.condition, context)) {
647
- applicableOperations.push({ ...item, generator: name, generatorType: genType, priority: generator.priority });
676
+ applicableOperations.push({
677
+ ...item,
678
+ generator: name,
679
+ generatorType: genType,
680
+ priority: generator.priority,
681
+ });
648
682
  }
649
683
  }
650
684
  }
@@ -660,15 +694,15 @@ class AdvancedCodeGenerator {
660
694
  const databases = [];
661
695
  const auths = [];
662
696
  for (const [key] of this.generators) {
663
- const [type, name] = key.split(':');
697
+ const [type, name] = key.split(":");
664
698
  switch (type) {
665
- case 'framework':
699
+ case "framework":
666
700
  frameworks.push(name);
667
701
  break;
668
- case 'database':
702
+ case "database":
669
703
  databases.push(name);
670
704
  break;
671
- case 'auth':
705
+ case "auth":
672
706
  auths.push(name);
673
707
  break;
674
708
  }
@@ -1,5 +1,5 @@
1
- import type { GeneratorConfig } from './code-generator';
2
- import type { ModuleMetadata } from '../../types';
1
+ import type { GeneratorConfig } from "./code-generator";
2
+ import type { ModuleMetadata } from "../../types";
3
3
  export declare function mergeModuleIntoGeneratorConfig(config: GeneratorConfig, modulePath: string): Promise<GeneratorConfig>;
4
4
  export declare function mergeGeneratorIntoModuleMetadata(metadata: ModuleMetadata, modulePath: string): Promise<ModuleMetadata>;
5
5
  export declare function locateOperationSource(generatorType: string, generatorName: string, sourceRel: string): string | null;