@ingenyus/swarm-wasp 0.2.0 → 0.2.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.
Files changed (47) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/common/index.d.ts +0 -1
  3. package/dist/common/index.d.ts.map +1 -1
  4. package/dist/common/index.js +9 -34
  5. package/dist/generators/action/action-generator.js +50 -58
  6. package/dist/generators/action/index.js +50 -58
  7. package/dist/generators/action/schema.js +1 -5
  8. package/dist/generators/api/api-generator.js +51 -59
  9. package/dist/generators/api/index.js +51 -59
  10. package/dist/generators/api/schema.js +1 -5
  11. package/dist/generators/api-namespace/api-namespace-generator.js +51 -59
  12. package/dist/generators/api-namespace/index.js +51 -59
  13. package/dist/generators/api-namespace/schema.js +1 -5
  14. package/dist/generators/base/component-generator.base.d.ts +4 -7
  15. package/dist/generators/base/component-generator.base.d.ts.map +1 -1
  16. package/dist/generators/base/component-generator.base.js +49 -57
  17. package/dist/generators/base/index.js +50 -58
  18. package/dist/generators/base/operation-generator.base.js +50 -58
  19. package/dist/generators/base/wasp-generator.base.d.ts +3 -5
  20. package/dist/generators/base/wasp-generator.base.d.ts.map +1 -1
  21. package/dist/generators/base/wasp-generator.base.js +22 -26
  22. package/dist/generators/config/index.js +12 -16
  23. package/dist/generators/config/wasp-config-generator.js +12 -16
  24. package/dist/generators/crud/crud-generator.js +50 -58
  25. package/dist/generators/crud/index.js +50 -58
  26. package/dist/generators/crud/schema.js +1 -5
  27. package/dist/generators/feature/feature-generator.d.ts +2 -4
  28. package/dist/generators/feature/feature-generator.d.ts.map +1 -1
  29. package/dist/generators/feature/feature-generator.js +32 -42
  30. package/dist/generators/feature/index.js +32 -42
  31. package/dist/generators/feature/schema.js +1 -5
  32. package/dist/generators/index.js +54 -62
  33. package/dist/generators/job/index.js +49 -57
  34. package/dist/generators/job/job-generator.js +49 -57
  35. package/dist/generators/job/schema.js +1 -5
  36. package/dist/generators/query/index.js +50 -58
  37. package/dist/generators/query/query-generator.js +50 -58
  38. package/dist/generators/query/schema.js +1 -5
  39. package/dist/generators/route/index.js +49 -57
  40. package/dist/generators/route/route-generator.js +49 -57
  41. package/dist/generators/route/schema.js +1 -5
  42. package/dist/index.js +60 -90
  43. package/dist/plugins/wasp.d.ts.map +1 -1
  44. package/package.json +2 -2
  45. package/dist/common/plugin.d.ts +0 -2
  46. package/dist/common/plugin.d.ts.map +0 -1
  47. package/dist/common/plugin.js +0 -41
@@ -59,13 +59,13 @@ var CONFIG_TYPES = {
59
59
 
60
60
  // src/generators/base/component-generator.base.ts
61
61
  import {
62
+ GeneratorRuntime,
62
63
  hasHelperMethodCall,
63
- logger as singletonLogger4,
64
64
  toCamelCase,
65
65
  toKebabCase as toKebabCase2,
66
66
  validateFeaturePath as validateFeaturePath3
67
67
  } from "@ingenyus/swarm";
68
- import path7 from "path";
68
+ import path6 from "path";
69
69
 
70
70
  // src/common/filesystem.ts
71
71
  import { toPascalCase, validateFeaturePath } from "@ingenyus/swarm";
@@ -143,19 +143,15 @@ function getRouteNameFromPath(routePath) {
143
143
  return `${toPascalCase(cleanSegment)}Page`;
144
144
  }
145
145
 
146
- // src/common/plugin.ts
147
- import path2 from "path";
148
- import { fileURLToPath } from "url";
149
-
150
146
  // src/common/prisma.ts
151
147
  import {
152
148
  getSchema
153
149
  } from "@mrleebo/prisma-ast";
154
150
  import fs2 from "fs";
155
- import path3 from "path";
151
+ import path2 from "path";
156
152
  async function getEntityMetadata(modelName) {
157
153
  try {
158
- const schemaPath = path3.join(process.cwd(), "schema.prisma");
154
+ const schemaPath = path2.join(process.cwd(), "schema.prisma");
159
155
  const schemaContent = fs2.readFileSync(schemaPath, "utf8");
160
156
  const schema9 = getSchema(schemaContent);
161
157
  const model = schema9.list?.find(
@@ -330,7 +326,7 @@ var commonSchemas = {
330
326
  // src/common/templates.ts
331
327
  import { toKebabCase } from "@ingenyus/swarm";
332
328
  import { Eta } from "eta";
333
- import path4 from "path";
329
+ import path3 from "path";
334
330
  var TemplateUtility = class {
335
331
  constructor(fileSystem) {
336
332
  this.fileSystem = fileSystem;
@@ -338,14 +334,14 @@ var TemplateUtility = class {
338
334
  processTemplate(templatePath, replacements) {
339
335
  const declarations = Object.keys(replacements).map((key) => `${key}=it.${key}`).join(", ");
340
336
  const functionHeader = declarations ? `const ${declarations};` : void 0;
341
- const templateDir = path4.dirname(templatePath);
337
+ const templateDir = path3.dirname(templatePath);
342
338
  const eta = new Eta({
343
339
  autoTrim: false,
344
340
  autoEscape: false,
345
341
  views: templateDir,
346
342
  functionHeader
347
343
  });
348
- const templateName = path4.basename(templatePath).replace(/\.eta$/, "");
344
+ const templateName = path3.basename(templatePath).replace(/\.eta$/, "");
349
345
  if (this.fileSystem.existsSync(templatePath)) {
350
346
  return eta.render(templateName, replacements);
351
347
  } else {
@@ -363,11 +359,11 @@ var TemplateUtility = class {
363
359
  resolveTemplatePath(relativePath, generatorName, currentFileUrl) {
364
360
  const generatorDirName = toKebabCase(generatorName);
365
361
  const currentFilePath = new URL(currentFileUrl).pathname;
366
- const currentFileDir = path4.dirname(currentFilePath);
367
- const currentFileName = path4.basename(currentFilePath);
362
+ const currentFileDir = path3.dirname(currentFilePath);
363
+ const currentFileName = path3.basename(currentFilePath);
368
364
  const isInstalledPackage = currentFileDir.includes("node_modules") && currentFileDir.endsWith("/dist") && currentFileName === "index.js";
369
- const startDir = isInstalledPackage ? currentFileDir : path4.dirname(path4.dirname(currentFileDir));
370
- return path4.join(
365
+ const startDir = isInstalledPackage ? currentFileDir : path3.dirname(path3.dirname(currentFileDir));
366
+ return path3.join(
371
367
  startDir,
372
368
  "generators",
373
369
  generatorDirName,
@@ -378,17 +374,12 @@ var TemplateUtility = class {
378
374
  };
379
375
 
380
376
  // src/generators/feature/feature-generator.ts
381
- import {
382
- handleFatalError as handleFatalError2,
383
- logger as singletonLogger3,
384
- validateFeaturePath as validateFeaturePath2
385
- } from "@ingenyus/swarm";
386
- import path6 from "path";
377
+ import { handleFatalError as handleFatalError2, validateFeaturePath as validateFeaturePath2 } from "@ingenyus/swarm";
378
+ import path5 from "path";
387
379
 
388
380
  // src/generators/base/wasp-generator.base.ts
389
381
  import {
390
382
  GeneratorBase,
391
- logger as singletonLogger2,
392
383
  SwarmConfigManager,
393
384
  TemplateResolver
394
385
  } from "@ingenyus/swarm";
@@ -399,14 +390,14 @@ import {
399
390
  parseHelperMethodDefinition,
400
391
  logger as singletonLogger
401
392
  } from "@ingenyus/swarm";
402
- import path5 from "path";
393
+ import path4 from "path";
403
394
  var WaspConfigGenerator = class {
404
395
  constructor(logger = singletonLogger, fileSystem = realFileSystem) {
405
396
  this.logger = logger;
406
397
  this.fileSystem = fileSystem;
407
398
  this.templateUtility = new TemplateUtility(fileSystem);
408
399
  }
409
- path = path5;
400
+ path = path4;
410
401
  templateUtility;
411
402
  /**
412
403
  * Gets the template path for feature config templates.
@@ -435,7 +426,7 @@ var WaspConfigGenerator = class {
435
426
  this.logger.error(`Template not found: ${templatePath}`);
436
427
  return;
437
428
  }
438
- const configFilePath = path5.join(featureDir, `feature.wasp.ts`);
429
+ const configFilePath = path4.join(featureDir, `feature.wasp.ts`);
439
430
  if (this.fileSystem.existsSync(configFilePath)) {
440
431
  this.logger.warn(`Feature config already exists: ${configFilePath}`);
441
432
  return;
@@ -451,7 +442,7 @@ var WaspConfigGenerator = class {
451
442
  */
452
443
  update(featurePath, declaration) {
453
444
  const configDir = getFeatureDir(this.fileSystem, featurePath);
454
- const configFilePath = path5.join(configDir, `feature.wasp.ts`);
445
+ const configFilePath = path4.join(configDir, `feature.wasp.ts`);
455
446
  if (!this.fileSystem.existsSync(configFilePath)) {
456
447
  const templatePath = this.getTemplatePath("feature.wasp.eta");
457
448
  if (!this.fileSystem.existsSync(templatePath)) {
@@ -831,14 +822,6 @@ var WaspConfigGenerator = class {
831
822
 
832
823
  // src/generators/base/wasp-generator.base.ts
833
824
  var WaspGeneratorBase = class extends GeneratorBase {
834
- constructor(fileSystem = realFileSystem, logger = singletonLogger2) {
835
- super(fileSystem, logger);
836
- this.fileSystem = fileSystem;
837
- this.logger = logger;
838
- this.configGenerator = new WaspConfigGenerator(logger, fileSystem);
839
- this.templateUtility = new TemplateUtility(fileSystem);
840
- this.templateResolver = new TemplateResolver(fileSystem);
841
- }
842
825
  configGenerator;
843
826
  templateUtility;
844
827
  templateResolver;
@@ -846,6 +829,15 @@ var WaspGeneratorBase = class extends GeneratorBase {
846
829
  configLoaded = false;
847
830
  // Plugin name from swarm.config.json
848
831
  pluginName = PLUGIN_NAME;
832
+ constructor() {
833
+ super();
834
+ this.configGenerator = new WaspConfigGenerator(
835
+ this.logger,
836
+ this.fileSystem
837
+ );
838
+ this.templateUtility = new TemplateUtility(this.fileSystem);
839
+ this.templateResolver = new TemplateResolver(this.fileSystem);
840
+ }
849
841
  async loadSwarmConfig() {
850
842
  if (this.configLoaded) return;
851
843
  const configManager = new SwarmConfigManager();
@@ -896,7 +888,7 @@ var WaspGeneratorBase = class extends GeneratorBase {
896
888
  }
897
889
  /**
898
890
  * Generic existence check with force flag handling
899
- * Consolidates the pattern used in both file and config checks
891
+ * Consolidates the pattern used in both file and config existence checks
900
892
  */
901
893
  checkExistence(exists, itemDescription, force, errorMessage) {
902
894
  if (exists && !force) {
@@ -936,16 +928,14 @@ var schema = z2.object({
936
928
 
937
929
  // src/generators/feature/feature-generator.ts
938
930
  var FeatureGenerator = class extends WaspGeneratorBase {
939
- constructor(logger = singletonLogger3, fileSystem = realFileSystem) {
940
- super(fileSystem, logger);
941
- this.logger = logger;
942
- this.fileSystem = fileSystem;
943
- this.name = "feature";
944
- this.description = "Generates a feature directory containing a Wasp configuration file";
945
- }
946
931
  name;
947
932
  description;
948
933
  schema = schema;
934
+ constructor() {
935
+ super();
936
+ this.name = "feature";
937
+ this.description = "Generates a feature directory containing a Wasp configuration file";
938
+ }
949
939
  getDefaultTemplatePath(templateName) {
950
940
  return this.templateUtility.resolveTemplatePath(
951
941
  templateName,
@@ -961,18 +951,18 @@ var FeatureGenerator = class extends WaspGeneratorBase {
961
951
  const { target } = args;
962
952
  const segments = validateFeaturePath2(target);
963
953
  const normalisedPath = normaliseFeaturePath(target);
964
- const sourceRoot = path6.join(findWaspRoot(this.fileSystem), "src");
954
+ const sourceRoot = path5.join(findWaspRoot(this.fileSystem), "src");
965
955
  if (segments.length > 1) {
966
956
  const parentPath = segments.slice(0, -1).join("/");
967
957
  const parentNormalisedPath = normaliseFeaturePath(parentPath);
968
- const parentFeatureDir = path6.join(sourceRoot, parentNormalisedPath);
958
+ const parentFeatureDir = path5.join(sourceRoot, parentNormalisedPath);
969
959
  if (!this.fileSystem.existsSync(parentFeatureDir)) {
970
960
  handleFatalError2(
971
961
  `Parent feature '${parentPath}' does not exist. Please create it first.`
972
962
  );
973
963
  }
974
964
  }
975
- const featureDir = path6.join(sourceRoot, normalisedPath);
965
+ const featureDir = path5.join(sourceRoot, normalisedPath);
976
966
  this.fileSystem.mkdirSync(featureDir, { recursive: true });
977
967
  this.configGenerator.generate(normalisedPath);
978
968
  this.logger.success(`Generated feature: ${normalisedPath}`);
@@ -981,13 +971,6 @@ var FeatureGenerator = class extends WaspGeneratorBase {
981
971
 
982
972
  // src/generators/base/component-generator.base.ts
983
973
  var ComponentGeneratorBase = class extends WaspGeneratorBase {
984
- constructor(logger = singletonLogger4, fileSystem = realFileSystem, featureDirectoryGenerator = new FeatureGenerator(logger, fileSystem)) {
985
- super(fileSystem, logger);
986
- this.logger = logger;
987
- this.fileSystem = fileSystem;
988
- this.featureDirectoryGenerator = featureDirectoryGenerator;
989
- this.featureDirectoryGenerator = featureDirectoryGenerator;
990
- }
991
974
  getDefaultTemplatePath(templateName) {
992
975
  return this.templateUtility.resolveTemplatePath(
993
976
  templateName,
@@ -995,6 +978,17 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
995
978
  import.meta.url
996
979
  );
997
980
  }
981
+ featureDirectoryGenerator;
982
+ constructor() {
983
+ super();
984
+ const runtime = GeneratorRuntime.current();
985
+ if (runtime.featureGeneratorFactory) {
986
+ const factoryResult = runtime.featureGeneratorFactory(runtime);
987
+ this.featureDirectoryGenerator = factoryResult;
988
+ } else {
989
+ this.featureDirectoryGenerator = new FeatureGenerator();
990
+ }
991
+ }
998
992
  get name() {
999
993
  return toKebabCase2(this.componentType);
1000
994
  }
@@ -1009,7 +1003,7 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
1009
1003
  const currentPath = pathSegments.join("/");
1010
1004
  const featureName = pathSegments[pathSegments.length - 1];
1011
1005
  const featureDir = getFeatureDir(this.fileSystem, currentPath);
1012
- const configPath = path7.join(featureDir, `feature.wasp.ts`);
1006
+ const configPath = path6.join(featureDir, `feature.wasp.ts`);
1013
1007
  if (this.fileSystem.existsSync(configPath)) {
1014
1008
  return configPath;
1015
1009
  }
@@ -1071,18 +1065,17 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
1071
1065
  }
1072
1066
  /**
1073
1067
  * Gets the appropriate directory for a feature based on its path.
1074
- * @param fileSystem - The filesystem abstraction
1075
1068
  * @param featurePath - The full feature path
1076
1069
  * @param type - The type of file being generated
1077
1070
  * @returns The target directory and import path
1078
1071
  */
1079
- getFeatureTargetDir(fileSystem, featurePath, type) {
1072
+ getFeatureTargetDir(featurePath, type) {
1080
1073
  validateFeaturePath3(featurePath);
1081
1074
  const normalisedPath = normaliseFeaturePath(featurePath);
1082
- const featureDir = getFeatureDir(fileSystem, normalisedPath);
1075
+ const featureDir = getFeatureDir(this.fileSystem, normalisedPath);
1083
1076
  const typeKey = type.toLowerCase();
1084
1077
  const typeDirectory = TYPE_DIRECTORIES[typeKey];
1085
- const targetDirectory = path7.join(featureDir, typeDirectory);
1078
+ const targetDirectory = path6.join(featureDir, typeDirectory);
1086
1079
  const importDirectory = `@src/${normalisedPath}/${typeDirectory}`;
1087
1080
  return { targetDirectory, importDirectory };
1088
1081
  }
@@ -1091,7 +1084,6 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
1091
1084
  */
1092
1085
  ensureTargetDirectory(featurePath, type) {
1093
1086
  const { targetDirectory, importDirectory } = this.getFeatureTargetDir(
1094
- this.fileSystem,
1095
1087
  featurePath,
1096
1088
  type
1097
1089
  );
@@ -1530,7 +1522,7 @@ var ApiGenerator = class extends ComponentGeneratorBase {
1530
1522
  force = false,
1531
1523
  entities,
1532
1524
  method,
1533
- path: path9,
1525
+ path: path8,
1534
1526
  auth,
1535
1527
  customMiddleware
1536
1528
  } = args;
@@ -1540,7 +1532,7 @@ var ApiGenerator = class extends ComponentGeneratorBase {
1540
1532
  feature,
1541
1533
  Array.isArray(entities) ? entities : entities ? [entities] : [],
1542
1534
  method,
1543
- path9,
1535
+ path8,
1544
1536
  apiFile,
1545
1537
  auth,
1546
1538
  importPath,
@@ -1596,7 +1588,7 @@ var ApiGenerator = class extends ComponentGeneratorBase {
1596
1588
 
1597
1589
  // src/generators/api-namespace/api-namespace-generator.ts
1598
1590
  import { toCamelCase as toCamelCase3 } from "@ingenyus/swarm";
1599
- import path8 from "path";
1591
+ import path7 from "path";
1600
1592
 
1601
1593
  // src/generators/api-namespace/schema.ts
1602
1594
  import { z as z5 } from "zod";
@@ -1644,7 +1636,7 @@ var ApiNamespaceGenerator = class extends ComponentGeneratorBase {
1644
1636
  }
1645
1637
  async updateConfigFile(namespaceName, importDirectory, namespacePath, args, configFilePath) {
1646
1638
  const { force = false } = args;
1647
- const importPath = path8.join(importDirectory, namespaceName);
1639
+ const importPath = path7.join(importDirectory, namespaceName);
1648
1640
  const definition = await this.getDefinition(
1649
1641
  namespaceName,
1650
1642
  importPath,
@@ -29,13 +29,13 @@ var CONFIG_TYPES = {
29
29
 
30
30
  // src/generators/base/component-generator.base.ts
31
31
  import {
32
+ GeneratorRuntime,
32
33
  hasHelperMethodCall,
33
- logger as singletonLogger4,
34
34
  toCamelCase,
35
35
  toKebabCase as toKebabCase2,
36
36
  validateFeaturePath as validateFeaturePath3
37
37
  } from "@ingenyus/swarm";
38
- import path7 from "path";
38
+ import path6 from "path";
39
39
 
40
40
  // src/common/filesystem.ts
41
41
  import { toPascalCase, validateFeaturePath } from "@ingenyus/swarm";
@@ -89,16 +89,12 @@ function getFeatureDir(fileSystem, featureName) {
89
89
  return path.join(waspRoot, "src", normalisedPath);
90
90
  }
91
91
 
92
- // src/common/plugin.ts
93
- import path2 from "path";
94
- import { fileURLToPath } from "url";
95
-
96
92
  // src/common/prisma.ts
97
93
  import {
98
94
  getSchema
99
95
  } from "@mrleebo/prisma-ast";
100
96
  import fs2 from "fs";
101
- import path3 from "path";
97
+ import path2 from "path";
102
98
 
103
99
  // src/common/schemas.ts
104
100
  import { commandRegistry } from "@ingenyus/swarm";
@@ -155,7 +151,7 @@ var commonSchemas = {
155
151
  // src/common/templates.ts
156
152
  import { toKebabCase } from "@ingenyus/swarm";
157
153
  import { Eta } from "eta";
158
- import path4 from "path";
154
+ import path3 from "path";
159
155
  var TemplateUtility = class {
160
156
  constructor(fileSystem) {
161
157
  this.fileSystem = fileSystem;
@@ -163,14 +159,14 @@ var TemplateUtility = class {
163
159
  processTemplate(templatePath, replacements) {
164
160
  const declarations = Object.keys(replacements).map((key) => `${key}=it.${key}`).join(", ");
165
161
  const functionHeader = declarations ? `const ${declarations};` : void 0;
166
- const templateDir = path4.dirname(templatePath);
162
+ const templateDir = path3.dirname(templatePath);
167
163
  const eta = new Eta({
168
164
  autoTrim: false,
169
165
  autoEscape: false,
170
166
  views: templateDir,
171
167
  functionHeader
172
168
  });
173
- const templateName = path4.basename(templatePath).replace(/\.eta$/, "");
169
+ const templateName = path3.basename(templatePath).replace(/\.eta$/, "");
174
170
  if (this.fileSystem.existsSync(templatePath)) {
175
171
  return eta.render(templateName, replacements);
176
172
  } else {
@@ -188,11 +184,11 @@ var TemplateUtility = class {
188
184
  resolveTemplatePath(relativePath, generatorName, currentFileUrl) {
189
185
  const generatorDirName = toKebabCase(generatorName);
190
186
  const currentFilePath = new URL(currentFileUrl).pathname;
191
- const currentFileDir = path4.dirname(currentFilePath);
192
- const currentFileName = path4.basename(currentFilePath);
187
+ const currentFileDir = path3.dirname(currentFilePath);
188
+ const currentFileName = path3.basename(currentFilePath);
193
189
  const isInstalledPackage = currentFileDir.includes("node_modules") && currentFileDir.endsWith("/dist") && currentFileName === "index.js";
194
- const startDir = isInstalledPackage ? currentFileDir : path4.dirname(path4.dirname(currentFileDir));
195
- return path4.join(
190
+ const startDir = isInstalledPackage ? currentFileDir : path3.dirname(path3.dirname(currentFileDir));
191
+ return path3.join(
196
192
  startDir,
197
193
  "generators",
198
194
  generatorDirName,
@@ -203,17 +199,12 @@ var TemplateUtility = class {
203
199
  };
204
200
 
205
201
  // src/generators/feature/feature-generator.ts
206
- import {
207
- handleFatalError as handleFatalError2,
208
- logger as singletonLogger3,
209
- validateFeaturePath as validateFeaturePath2
210
- } from "@ingenyus/swarm";
211
- import path6 from "path";
202
+ import { handleFatalError as handleFatalError2, validateFeaturePath as validateFeaturePath2 } from "@ingenyus/swarm";
203
+ import path5 from "path";
212
204
 
213
205
  // src/generators/base/wasp-generator.base.ts
214
206
  import {
215
207
  GeneratorBase,
216
- logger as singletonLogger2,
217
208
  SwarmConfigManager,
218
209
  TemplateResolver
219
210
  } from "@ingenyus/swarm";
@@ -224,14 +215,14 @@ import {
224
215
  parseHelperMethodDefinition,
225
216
  logger as singletonLogger
226
217
  } from "@ingenyus/swarm";
227
- import path5 from "path";
218
+ import path4 from "path";
228
219
  var WaspConfigGenerator = class {
229
220
  constructor(logger = singletonLogger, fileSystem = realFileSystem) {
230
221
  this.logger = logger;
231
222
  this.fileSystem = fileSystem;
232
223
  this.templateUtility = new TemplateUtility(fileSystem);
233
224
  }
234
- path = path5;
225
+ path = path4;
235
226
  templateUtility;
236
227
  /**
237
228
  * Gets the template path for feature config templates.
@@ -260,7 +251,7 @@ var WaspConfigGenerator = class {
260
251
  this.logger.error(`Template not found: ${templatePath}`);
261
252
  return;
262
253
  }
263
- const configFilePath = path5.join(featureDir, `feature.wasp.ts`);
254
+ const configFilePath = path4.join(featureDir, `feature.wasp.ts`);
264
255
  if (this.fileSystem.existsSync(configFilePath)) {
265
256
  this.logger.warn(`Feature config already exists: ${configFilePath}`);
266
257
  return;
@@ -276,7 +267,7 @@ var WaspConfigGenerator = class {
276
267
  */
277
268
  update(featurePath, declaration) {
278
269
  const configDir = getFeatureDir(this.fileSystem, featurePath);
279
- const configFilePath = path5.join(configDir, `feature.wasp.ts`);
270
+ const configFilePath = path4.join(configDir, `feature.wasp.ts`);
280
271
  if (!this.fileSystem.existsSync(configFilePath)) {
281
272
  const templatePath = this.getTemplatePath("feature.wasp.eta");
282
273
  if (!this.fileSystem.existsSync(templatePath)) {
@@ -656,14 +647,6 @@ var WaspConfigGenerator = class {
656
647
 
657
648
  // src/generators/base/wasp-generator.base.ts
658
649
  var WaspGeneratorBase = class extends GeneratorBase {
659
- constructor(fileSystem = realFileSystem, logger = singletonLogger2) {
660
- super(fileSystem, logger);
661
- this.fileSystem = fileSystem;
662
- this.logger = logger;
663
- this.configGenerator = new WaspConfigGenerator(logger, fileSystem);
664
- this.templateUtility = new TemplateUtility(fileSystem);
665
- this.templateResolver = new TemplateResolver(fileSystem);
666
- }
667
650
  configGenerator;
668
651
  templateUtility;
669
652
  templateResolver;
@@ -671,6 +654,15 @@ var WaspGeneratorBase = class extends GeneratorBase {
671
654
  configLoaded = false;
672
655
  // Plugin name from swarm.config.json
673
656
  pluginName = PLUGIN_NAME;
657
+ constructor() {
658
+ super();
659
+ this.configGenerator = new WaspConfigGenerator(
660
+ this.logger,
661
+ this.fileSystem
662
+ );
663
+ this.templateUtility = new TemplateUtility(this.fileSystem);
664
+ this.templateResolver = new TemplateResolver(this.fileSystem);
665
+ }
674
666
  async loadSwarmConfig() {
675
667
  if (this.configLoaded) return;
676
668
  const configManager = new SwarmConfigManager();
@@ -721,7 +713,7 @@ var WaspGeneratorBase = class extends GeneratorBase {
721
713
  }
722
714
  /**
723
715
  * Generic existence check with force flag handling
724
- * Consolidates the pattern used in both file and config checks
716
+ * Consolidates the pattern used in both file and config existence checks
725
717
  */
726
718
  checkExistence(exists, itemDescription, force, errorMessage) {
727
719
  if (exists && !force) {
@@ -761,16 +753,14 @@ var schema = z2.object({
761
753
 
762
754
  // src/generators/feature/feature-generator.ts
763
755
  var FeatureGenerator = class extends WaspGeneratorBase {
764
- constructor(logger = singletonLogger3, fileSystem = realFileSystem) {
765
- super(fileSystem, logger);
766
- this.logger = logger;
767
- this.fileSystem = fileSystem;
768
- this.name = "feature";
769
- this.description = "Generates a feature directory containing a Wasp configuration file";
770
- }
771
756
  name;
772
757
  description;
773
758
  schema = schema;
759
+ constructor() {
760
+ super();
761
+ this.name = "feature";
762
+ this.description = "Generates a feature directory containing a Wasp configuration file";
763
+ }
774
764
  getDefaultTemplatePath(templateName) {
775
765
  return this.templateUtility.resolveTemplatePath(
776
766
  templateName,
@@ -786,18 +776,18 @@ var FeatureGenerator = class extends WaspGeneratorBase {
786
776
  const { target } = args;
787
777
  const segments = validateFeaturePath2(target);
788
778
  const normalisedPath = normaliseFeaturePath(target);
789
- const sourceRoot = path6.join(findWaspRoot(this.fileSystem), "src");
779
+ const sourceRoot = path5.join(findWaspRoot(this.fileSystem), "src");
790
780
  if (segments.length > 1) {
791
781
  const parentPath = segments.slice(0, -1).join("/");
792
782
  const parentNormalisedPath = normaliseFeaturePath(parentPath);
793
- const parentFeatureDir = path6.join(sourceRoot, parentNormalisedPath);
783
+ const parentFeatureDir = path5.join(sourceRoot, parentNormalisedPath);
794
784
  if (!this.fileSystem.existsSync(parentFeatureDir)) {
795
785
  handleFatalError2(
796
786
  `Parent feature '${parentPath}' does not exist. Please create it first.`
797
787
  );
798
788
  }
799
789
  }
800
- const featureDir = path6.join(sourceRoot, normalisedPath);
790
+ const featureDir = path5.join(sourceRoot, normalisedPath);
801
791
  this.fileSystem.mkdirSync(featureDir, { recursive: true });
802
792
  this.configGenerator.generate(normalisedPath);
803
793
  this.logger.success(`Generated feature: ${normalisedPath}`);
@@ -806,13 +796,6 @@ var FeatureGenerator = class extends WaspGeneratorBase {
806
796
 
807
797
  // src/generators/base/component-generator.base.ts
808
798
  var ComponentGeneratorBase = class extends WaspGeneratorBase {
809
- constructor(logger = singletonLogger4, fileSystem = realFileSystem, featureDirectoryGenerator = new FeatureGenerator(logger, fileSystem)) {
810
- super(fileSystem, logger);
811
- this.logger = logger;
812
- this.fileSystem = fileSystem;
813
- this.featureDirectoryGenerator = featureDirectoryGenerator;
814
- this.featureDirectoryGenerator = featureDirectoryGenerator;
815
- }
816
799
  getDefaultTemplatePath(templateName) {
817
800
  return this.templateUtility.resolveTemplatePath(
818
801
  templateName,
@@ -820,6 +803,17 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
820
803
  import.meta.url
821
804
  );
822
805
  }
806
+ featureDirectoryGenerator;
807
+ constructor() {
808
+ super();
809
+ const runtime = GeneratorRuntime.current();
810
+ if (runtime.featureGeneratorFactory) {
811
+ const factoryResult = runtime.featureGeneratorFactory(runtime);
812
+ this.featureDirectoryGenerator = factoryResult;
813
+ } else {
814
+ this.featureDirectoryGenerator = new FeatureGenerator();
815
+ }
816
+ }
823
817
  get name() {
824
818
  return toKebabCase2(this.componentType);
825
819
  }
@@ -834,7 +828,7 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
834
828
  const currentPath = pathSegments.join("/");
835
829
  const featureName = pathSegments[pathSegments.length - 1];
836
830
  const featureDir = getFeatureDir(this.fileSystem, currentPath);
837
- const configPath = path7.join(featureDir, `feature.wasp.ts`);
831
+ const configPath = path6.join(featureDir, `feature.wasp.ts`);
838
832
  if (this.fileSystem.existsSync(configPath)) {
839
833
  return configPath;
840
834
  }
@@ -896,18 +890,17 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
896
890
  }
897
891
  /**
898
892
  * Gets the appropriate directory for a feature based on its path.
899
- * @param fileSystem - The filesystem abstraction
900
893
  * @param featurePath - The full feature path
901
894
  * @param type - The type of file being generated
902
895
  * @returns The target directory and import path
903
896
  */
904
- getFeatureTargetDir(fileSystem, featurePath, type) {
897
+ getFeatureTargetDir(featurePath, type) {
905
898
  validateFeaturePath3(featurePath);
906
899
  const normalisedPath = normaliseFeaturePath(featurePath);
907
- const featureDir = getFeatureDir(fileSystem, normalisedPath);
900
+ const featureDir = getFeatureDir(this.fileSystem, normalisedPath);
908
901
  const typeKey = type.toLowerCase();
909
902
  const typeDirectory = TYPE_DIRECTORIES[typeKey];
910
- const targetDirectory = path7.join(featureDir, typeDirectory);
903
+ const targetDirectory = path6.join(featureDir, typeDirectory);
911
904
  const importDirectory = `@src/${normalisedPath}/${typeDirectory}`;
912
905
  return { targetDirectory, importDirectory };
913
906
  }
@@ -916,7 +909,6 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
916
909
  */
917
910
  ensureTargetDirectory(featurePath, type) {
918
911
  const { targetDirectory, importDirectory } = this.getFeatureTargetDir(
919
- this.fileSystem,
920
912
  featurePath,
921
913
  type
922
914
  );