@ingenyus/swarm-wasp 1.0.3 → 1.2.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 (51) hide show
  1. package/README.md +14 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/common/index.d.ts +1 -0
  4. package/dist/common/index.d.ts.map +1 -1
  5. package/dist/common/index.js +81 -0
  6. package/dist/common/wasp-compatibility.d.ts +10 -0
  7. package/dist/common/wasp-compatibility.d.ts.map +1 -0
  8. package/dist/common/wasp-compatibility.js +82 -0
  9. package/dist/generators/action/action-generator.d.ts.map +1 -1
  10. package/dist/generators/action/action-generator.js +102 -13
  11. package/dist/generators/action/index.js +102 -13
  12. package/dist/generators/action/schema.js +7 -0
  13. package/dist/generators/api/api-generator.d.ts.map +1 -1
  14. package/dist/generators/api/api-generator.js +104 -15
  15. package/dist/generators/api/index.js +104 -15
  16. package/dist/generators/api/schema.js +7 -0
  17. package/dist/generators/api-namespace/api-namespace-generator.d.ts.map +1 -1
  18. package/dist/generators/api-namespace/api-namespace-generator.js +104 -15
  19. package/dist/generators/api-namespace/index.js +104 -15
  20. package/dist/generators/api-namespace/schema.js +7 -0
  21. package/dist/generators/base/component-generator.base.js +101 -13
  22. package/dist/generators/base/index.js +101 -13
  23. package/dist/generators/base/operation-generator.base.js +101 -13
  24. package/dist/generators/base/wasp-generator.base.d.ts +5 -0
  25. package/dist/generators/base/wasp-generator.base.d.ts.map +1 -1
  26. package/dist/generators/base/wasp-generator.base.js +93 -6
  27. package/dist/generators/config/index.js +11 -4
  28. package/dist/generators/config/wasp-config-generator.js +11 -4
  29. package/dist/generators/crud/crud-generator.d.ts.map +1 -1
  30. package/dist/generators/crud/crud-generator.js +102 -13
  31. package/dist/generators/crud/index.js +102 -13
  32. package/dist/generators/crud/schema.js +7 -0
  33. package/dist/generators/feature/feature-generator.d.ts.map +1 -1
  34. package/dist/generators/feature/feature-generator.js +98 -10
  35. package/dist/generators/feature/index.js +98 -10
  36. package/dist/generators/feature/schema.js +7 -0
  37. package/dist/generators/index.js +112 -17
  38. package/dist/generators/job/index.js +102 -13
  39. package/dist/generators/job/job-generator.d.ts.map +1 -1
  40. package/dist/generators/job/job-generator.js +102 -13
  41. package/dist/generators/job/schema.js +7 -0
  42. package/dist/generators/query/index.js +102 -13
  43. package/dist/generators/query/query-generator.d.ts.map +1 -1
  44. package/dist/generators/query/query-generator.js +102 -13
  45. package/dist/generators/query/schema.js +7 -0
  46. package/dist/generators/route/index.js +102 -13
  47. package/dist/generators/route/route-generator.d.ts.map +1 -1
  48. package/dist/generators/route/route-generator.js +102 -13
  49. package/dist/generators/route/schema.js +7 -0
  50. package/dist/index.js +120 -25
  51. package/package.json +11 -6
@@ -366,22 +366,102 @@ var TemplateUtility = class {
366
366
  }
367
367
  };
368
368
 
369
+ // src/common/wasp-compatibility.ts
370
+ import { findPackageJson, getVersion } from "@ingenyus/swarm";
371
+ import { execSync } from "child_process";
372
+ import path4 from "path";
373
+ import { fileURLToPath } from "url";
374
+ import * as semver from "semver";
375
+ var cachedSupportedRange = null;
376
+ function getWaspSupportedRange() {
377
+ if (cachedSupportedRange) {
378
+ return cachedSupportedRange;
379
+ }
380
+ const currentFile = fileURLToPath(import.meta.url);
381
+ const currentDir = path4.dirname(currentFile);
382
+ const result = findPackageJson(currentDir, {
383
+ packageName: "@ingenyus/swarm-wasp"
384
+ });
385
+ if (!result) {
386
+ throw new Error(
387
+ "Unable to find package.json for @ingenyus/swarm-wasp. Wasp supported version range must be specified in swarm.wasp field."
388
+ );
389
+ }
390
+ const swarm = result.packageJson.swarm;
391
+ const waspRange = swarm?.wasp;
392
+ if (!waspRange) {
393
+ throw new Error(
394
+ `Wasp supported version range not found in package.json. Please specify swarm.wasp field in @ingenyus/swarm-wasp package.json (e.g., "swarm": { "wasp": ">=0.18.0 <0.20.0" }).`
395
+ );
396
+ }
397
+ cachedSupportedRange = waspRange;
398
+ return cachedSupportedRange;
399
+ }
400
+ function getInstalledWaspVersion(logger) {
401
+ try {
402
+ const output = execSync("wasp version", {
403
+ encoding: "utf8",
404
+ stdio: "pipe"
405
+ });
406
+ const firstLine = output.split("\n")[0]?.trim();
407
+ if (!firstLine) {
408
+ logger.error(
409
+ "Unable to parse Wasp version from command output. Expected version number on first line."
410
+ );
411
+ throw new Error("Unable to parse Wasp version from command output");
412
+ }
413
+ if (!semver.valid(firstLine)) {
414
+ logger.error(
415
+ `Invalid Wasp version format: "${firstLine}". Expected a valid semver version (e.g., "0.18.2").`
416
+ );
417
+ throw new Error("Invalid Wasp version format");
418
+ }
419
+ return firstLine;
420
+ } catch (error) {
421
+ if (error.code === "ENOENT" || error.message?.includes("wasp")) {
422
+ logger.error(
423
+ "Wasp CLI not found. Install using: curl -sSL https://get.wasp.sh/installer.sh | sh -s"
424
+ );
425
+ throw new Error("Wasp CLI not found");
426
+ }
427
+ throw new Error("Unable to determine installed Wasp version");
428
+ }
429
+ }
430
+ function isTestEnvironment() {
431
+ return process.env.NODE_ENV === "test" || process.env.VITEST === "true" || typeof process.env.VITEST !== "undefined";
432
+ }
433
+ function assertWaspCompatible(logger) {
434
+ if (isTestEnvironment()) {
435
+ return;
436
+ }
437
+ const version = getInstalledWaspVersion(logger);
438
+ const supportedRange = getWaspSupportedRange();
439
+ if (!semver.satisfies(version, supportedRange)) {
440
+ const startDir = path4.dirname(fileURLToPath(import.meta.url));
441
+ const packageVersion = getVersion("@ingenyus/swarm-wasp", startDir);
442
+ logger.error(
443
+ `Incompatible Wasp version detected: ${version}. @ingenyus/swarm-wasp@${packageVersion} supports Wasp ${supportedRange}.`
444
+ );
445
+ throw new Error("Incompatible Wasp version");
446
+ }
447
+ }
448
+
369
449
  // src/generators/base/component-generator.base.ts
370
450
  import {
371
451
  hasHelperMethodCall,
372
452
  toKebabCase as toKebabCase2
373
453
  } from "@ingenyus/swarm";
374
- import path6 from "path";
454
+ import path7 from "path";
375
455
 
376
456
  // src/generators/feature/feature-generator.ts
377
457
  import { handleFatalError as handleFatalError2 } from "@ingenyus/swarm";
378
- import path5 from "path";
458
+ import path6 from "path";
379
459
 
380
460
  // src/generators/base/wasp-generator.base.ts
381
461
  import {
382
462
  GeneratorBase,
383
- getConfigManager,
384
- TemplateResolver
463
+ TemplateResolver,
464
+ getConfigManager
385
465
  } from "@ingenyus/swarm";
386
466
 
387
467
  // src/generators/config/wasp-config-generator.ts
@@ -390,14 +470,14 @@ import {
390
470
  handleFatalError,
391
471
  parseHelperMethodDefinition
392
472
  } from "@ingenyus/swarm";
393
- import path4 from "path";
473
+ import path5 from "path";
394
474
  var WaspConfigGenerator = class {
395
475
  constructor(logger = getCLILogger(), fileSystem = realFileSystem) {
396
476
  this.logger = logger;
397
477
  this.fileSystem = fileSystem;
398
478
  this.templateUtility = new TemplateUtility(fileSystem);
399
479
  }
400
- path = path4;
480
+ path = path5;
401
481
  templateUtility;
402
482
  /**
403
483
  * Gets the template path for feature config templates.
@@ -426,7 +506,7 @@ var WaspConfigGenerator = class {
426
506
  this.logger.error(`Template not found: ${templatePath}`);
427
507
  return;
428
508
  }
429
- const configFilePath = path4.join(featureDir, `feature.wasp.ts`);
509
+ const configFilePath = path5.join(featureDir, `feature.wasp.ts`);
430
510
  if (this.fileSystem.existsSync(configFilePath)) {
431
511
  this.logger.warn(`Feature config already exists: ${configFilePath}`);
432
512
  return;
@@ -442,7 +522,7 @@ var WaspConfigGenerator = class {
442
522
  */
443
523
  update(featurePath, declaration) {
444
524
  const configDir = getFeatureDir(this.fileSystem, featurePath);
445
- const configFilePath = path4.join(configDir, `feature.wasp.ts`);
525
+ const configFilePath = path5.join(configDir, `feature.wasp.ts`);
446
526
  if (!this.fileSystem.existsSync(configFilePath)) {
447
527
  const templatePath = this.getTemplatePath("feature.wasp.eta");
448
528
  if (!this.fileSystem.existsSync(templatePath)) {
@@ -838,6 +918,13 @@ var WaspGeneratorBase = class extends GeneratorBase {
838
918
  this.templateUtility = new TemplateUtility(this.fileSystem);
839
919
  this.templateResolver = new TemplateResolver(this.fileSystem);
840
920
  }
921
+ /**
922
+ * Ensures that the installed Wasp version is compatible with this package.
923
+ * Should be called at the start of generator execution.
924
+ */
925
+ ensureWaspCompatible() {
926
+ assertWaspCompatible(this.logger);
927
+ }
841
928
  async loadConfig() {
842
929
  if (this.configLoaded) return;
843
930
  const configManager = getConfigManager();
@@ -954,21 +1041,22 @@ var FeatureGenerator = class extends WaspGeneratorBase {
954
1041
  * @param target - The target path of the generated directory
955
1042
  */
956
1043
  async generate(args) {
1044
+ this.ensureWaspCompatible();
957
1045
  const { target } = args;
958
1046
  const segments = validateFeaturePath(target);
959
1047
  const normalisedPath = normaliseFeaturePath(target);
960
- const sourceRoot = path5.join(findWaspRoot(this.fileSystem), "src");
1048
+ const sourceRoot = path6.join(findWaspRoot(this.fileSystem), "src");
961
1049
  if (segments.length > 1) {
962
1050
  const parentPath = segments.slice(0, -1).join("/");
963
1051
  const parentNormalisedPath = normaliseFeaturePath(parentPath);
964
- const parentFeatureDir = path5.join(sourceRoot, parentNormalisedPath);
1052
+ const parentFeatureDir = path6.join(sourceRoot, parentNormalisedPath);
965
1053
  if (!this.fileSystem.existsSync(parentFeatureDir)) {
966
1054
  handleFatalError2(
967
1055
  `Parent feature '${parentPath}' does not exist. Please create it first.`
968
1056
  );
969
1057
  }
970
1058
  }
971
- const featureDir = path5.join(sourceRoot, normalisedPath);
1059
+ const featureDir = path6.join(sourceRoot, normalisedPath);
972
1060
  this.fileSystem.mkdirSync(featureDir, { recursive: true });
973
1061
  this.configGenerator.generate(normalisedPath);
974
1062
  this.logger.success(`Generated feature: ${normalisedPath}`);
@@ -1003,7 +1091,7 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
1003
1091
  const currentPath = pathSegments.join("/");
1004
1092
  const featureName = pathSegments[pathSegments.length - 1];
1005
1093
  const featureDir = getFeatureDir(this.fileSystem, currentPath);
1006
- const configPath = path6.join(featureDir, `feature.wasp.ts`);
1094
+ const configPath = path7.join(featureDir, `feature.wasp.ts`);
1007
1095
  if (this.fileSystem.existsSync(configPath)) {
1008
1096
  return configPath;
1009
1097
  }
@@ -1075,7 +1163,7 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
1075
1163
  const featureDir = getFeatureDir(this.fileSystem, normalisedPath);
1076
1164
  const typeKey = type.toLowerCase();
1077
1165
  const typeDirectory = TYPE_DIRECTORIES[typeKey];
1078
- const targetDirectory = path6.join(featureDir, typeDirectory);
1166
+ const targetDirectory = path7.join(featureDir, typeDirectory);
1079
1167
  const importDirectory = `@src/${normalisedPath}/${typeDirectory}`;
1080
1168
  return { targetDirectory, importDirectory };
1081
1169
  }
@@ -12,6 +12,11 @@ export declare abstract class WaspGeneratorBase<S extends StandardSchemaV1> exte
12
12
  private configLoaded;
13
13
  protected readonly pluginName: "wasp";
14
14
  constructor(services: GeneratorServices);
15
+ /**
16
+ * Ensures that the installed Wasp version is compatible with this package.
17
+ * Should be called at the start of generator execution.
18
+ */
19
+ protected ensureWaspCompatible(): void;
15
20
  private loadConfig;
16
21
  protected getCustomTemplateDir(): Promise<string | undefined>;
17
22
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"wasp-generator.base.d.ts","sourceRoot":"","sources":["../../../src/generators/base/wasp-generator.base.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAEhB,gBAAgB,EACjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAe,eAAe,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEhD;;GAEG;AACH,8BAAsB,iBAAiB,CACrC,CAAC,SAAS,gBAAgB,CAC1B,SAAQ,aAAa,CAAC,CAAC,CAAC;IACxB,SAAS,CAAC,eAAe,EAAE,mBAAmB,CAAC;IAC/C,SAAS,CAAC,eAAe,EAAE,eAAe,CAAC;IAC3C,SAAS,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAC7C,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,YAAY,CAAS;IAG7B,SAAS,CAAC,QAAQ,CAAC,UAAU,SAAe;gBAEhC,QAAQ,EAAE,iBAAiB;YAUzB,UAAU;cASR,oBAAoB,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAMnE;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAEvE;;OAEG;cACa,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAwBtE;;OAEG;cACa,oBAAoB,CAClC,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACjC,UAAU,EAAE,MAAM,EAClB,gBAAgB,EAAE,MAAM,EACxB,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,OAAO,CAAC;IAiBnB;;;OAGG;IACH,SAAS,CAAC,cAAc,CACtB,MAAM,EAAE,OAAO,EACf,eAAe,EAAE,MAAM,EACvB,KAAK,EAAE,OAAO,EACd,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO;IAQV;;OAEG;IACH,SAAS,CAAC,eAAe,CACvB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,MAAM,GACf,OAAO;IAUV;;OAEG;IACH,SAAS,CAAC,SAAS,CACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,OAAO,GAClB,IAAI;CAMR"}
1
+ {"version":3,"file":"wasp-generator.base.d.ts","sourceRoot":"","sources":["../../../src/generators/base/wasp-generator.base.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAEjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAEL,eAAe,EAEhB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEhD;;GAEG;AACH,8BAAsB,iBAAiB,CACrC,CAAC,SAAS,gBAAgB,CAC1B,SAAQ,aAAa,CAAC,CAAC,CAAC;IACxB,SAAS,CAAC,eAAe,EAAE,mBAAmB,CAAC;IAC/C,SAAS,CAAC,eAAe,EAAE,eAAe,CAAC;IAC3C,SAAS,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAC7C,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,YAAY,CAAS;IAG7B,SAAS,CAAC,QAAQ,CAAC,UAAU,SAAe;gBAEhC,QAAQ,EAAE,iBAAiB;IAUvC;;;OAGG;IACH,SAAS,CAAC,oBAAoB,IAAI,IAAI;YAIxB,UAAU;cASR,oBAAoB,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAMnE;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAEvE;;OAEG;cACa,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAwBtE;;OAEG;cACa,oBAAoB,CAClC,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACjC,UAAU,EAAE,MAAM,EAClB,gBAAgB,EAAE,MAAM,EACxB,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,OAAO,CAAC;IAiBnB;;;OAGG;IACH,SAAS,CAAC,cAAc,CACtB,MAAM,EAAE,OAAO,EACf,eAAe,EAAE,MAAM,EACvB,KAAK,EAAE,OAAO,EACd,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO;IAQV;;OAEG;IACH,SAAS,CAAC,eAAe,CACvB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,MAAM,GACf,OAAO;IAUV;;OAEG;IACH,SAAS,CAAC,SAAS,CACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,OAAO,GAClB,IAAI;CAMR"}
@@ -1,8 +1,8 @@
1
1
  // src/generators/base/wasp-generator.base.ts
2
2
  import {
3
3
  GeneratorBase,
4
- getConfigManager,
5
- TemplateResolver
4
+ TemplateResolver,
5
+ getConfigManager
6
6
  } from "@ingenyus/swarm";
7
7
 
8
8
  // src/common/constants.ts
@@ -132,20 +132,100 @@ var TemplateUtility = class {
132
132
  }
133
133
  };
134
134
 
135
+ // src/common/wasp-compatibility.ts
136
+ import { findPackageJson, getVersion } from "@ingenyus/swarm";
137
+ import { execSync } from "child_process";
138
+ import path4 from "path";
139
+ import { fileURLToPath } from "url";
140
+ import * as semver from "semver";
141
+ var cachedSupportedRange = null;
142
+ function getWaspSupportedRange() {
143
+ if (cachedSupportedRange) {
144
+ return cachedSupportedRange;
145
+ }
146
+ const currentFile = fileURLToPath(import.meta.url);
147
+ const currentDir = path4.dirname(currentFile);
148
+ const result = findPackageJson(currentDir, {
149
+ packageName: "@ingenyus/swarm-wasp"
150
+ });
151
+ if (!result) {
152
+ throw new Error(
153
+ "Unable to find package.json for @ingenyus/swarm-wasp. Wasp supported version range must be specified in swarm.wasp field."
154
+ );
155
+ }
156
+ const swarm = result.packageJson.swarm;
157
+ const waspRange = swarm?.wasp;
158
+ if (!waspRange) {
159
+ throw new Error(
160
+ `Wasp supported version range not found in package.json. Please specify swarm.wasp field in @ingenyus/swarm-wasp package.json (e.g., "swarm": { "wasp": ">=0.18.0 <0.20.0" }).`
161
+ );
162
+ }
163
+ cachedSupportedRange = waspRange;
164
+ return cachedSupportedRange;
165
+ }
166
+ function getInstalledWaspVersion(logger) {
167
+ try {
168
+ const output = execSync("wasp version", {
169
+ encoding: "utf8",
170
+ stdio: "pipe"
171
+ });
172
+ const firstLine = output.split("\n")[0]?.trim();
173
+ if (!firstLine) {
174
+ logger.error(
175
+ "Unable to parse Wasp version from command output. Expected version number on first line."
176
+ );
177
+ throw new Error("Unable to parse Wasp version from command output");
178
+ }
179
+ if (!semver.valid(firstLine)) {
180
+ logger.error(
181
+ `Invalid Wasp version format: "${firstLine}". Expected a valid semver version (e.g., "0.18.2").`
182
+ );
183
+ throw new Error("Invalid Wasp version format");
184
+ }
185
+ return firstLine;
186
+ } catch (error) {
187
+ if (error.code === "ENOENT" || error.message?.includes("wasp")) {
188
+ logger.error(
189
+ "Wasp CLI not found. Install using: curl -sSL https://get.wasp.sh/installer.sh | sh -s"
190
+ );
191
+ throw new Error("Wasp CLI not found");
192
+ }
193
+ throw new Error("Unable to determine installed Wasp version");
194
+ }
195
+ }
196
+ function isTestEnvironment() {
197
+ return process.env.NODE_ENV === "test" || process.env.VITEST === "true" || typeof process.env.VITEST !== "undefined";
198
+ }
199
+ function assertWaspCompatible(logger) {
200
+ if (isTestEnvironment()) {
201
+ return;
202
+ }
203
+ const version = getInstalledWaspVersion(logger);
204
+ const supportedRange = getWaspSupportedRange();
205
+ if (!semver.satisfies(version, supportedRange)) {
206
+ const startDir = path4.dirname(fileURLToPath(import.meta.url));
207
+ const packageVersion = getVersion("@ingenyus/swarm-wasp", startDir);
208
+ logger.error(
209
+ `Incompatible Wasp version detected: ${version}. @ingenyus/swarm-wasp@${packageVersion} supports Wasp ${supportedRange}.`
210
+ );
211
+ throw new Error("Incompatible Wasp version");
212
+ }
213
+ }
214
+
135
215
  // src/generators/config/wasp-config-generator.ts
136
216
  import {
137
217
  getCLILogger,
138
218
  handleFatalError,
139
219
  parseHelperMethodDefinition
140
220
  } from "@ingenyus/swarm";
141
- import path4 from "path";
221
+ import path5 from "path";
142
222
  var WaspConfigGenerator = class {
143
223
  constructor(logger = getCLILogger(), fileSystem = realFileSystem) {
144
224
  this.logger = logger;
145
225
  this.fileSystem = fileSystem;
146
226
  this.templateUtility = new TemplateUtility(fileSystem);
147
227
  }
148
- path = path4;
228
+ path = path5;
149
229
  templateUtility;
150
230
  /**
151
231
  * Gets the template path for feature config templates.
@@ -174,7 +254,7 @@ var WaspConfigGenerator = class {
174
254
  this.logger.error(`Template not found: ${templatePath}`);
175
255
  return;
176
256
  }
177
- const configFilePath = path4.join(featureDir, `feature.wasp.ts`);
257
+ const configFilePath = path5.join(featureDir, `feature.wasp.ts`);
178
258
  if (this.fileSystem.existsSync(configFilePath)) {
179
259
  this.logger.warn(`Feature config already exists: ${configFilePath}`);
180
260
  return;
@@ -190,7 +270,7 @@ var WaspConfigGenerator = class {
190
270
  */
191
271
  update(featurePath, declaration) {
192
272
  const configDir = getFeatureDir(this.fileSystem, featurePath);
193
- const configFilePath = path4.join(configDir, `feature.wasp.ts`);
273
+ const configFilePath = path5.join(configDir, `feature.wasp.ts`);
194
274
  if (!this.fileSystem.existsSync(configFilePath)) {
195
275
  const templatePath = this.getTemplatePath("feature.wasp.eta");
196
276
  if (!this.fileSystem.existsSync(templatePath)) {
@@ -586,6 +666,13 @@ var WaspGeneratorBase = class extends GeneratorBase {
586
666
  this.templateUtility = new TemplateUtility(this.fileSystem);
587
667
  this.templateResolver = new TemplateResolver(this.fileSystem);
588
668
  }
669
+ /**
670
+ * Ensures that the installed Wasp version is compatible with this package.
671
+ * Should be called at the start of generator execution.
672
+ */
673
+ ensureWaspCompatible() {
674
+ assertWaspCompatible(this.logger);
675
+ }
589
676
  async loadConfig() {
590
677
  if (this.configLoaded) return;
591
678
  const configManager = getConfigManager();
@@ -4,7 +4,7 @@ import {
4
4
  handleFatalError,
5
5
  parseHelperMethodDefinition
6
6
  } from "@ingenyus/swarm";
7
- import path4 from "path";
7
+ import path5 from "path";
8
8
 
9
9
  // src/common/filesystem.ts
10
10
  import { toPascalCase } from "@ingenyus/swarm";
@@ -130,6 +130,13 @@ var TemplateUtility = class {
130
130
  }
131
131
  };
132
132
 
133
+ // src/common/wasp-compatibility.ts
134
+ import { findPackageJson, getVersion } from "@ingenyus/swarm";
135
+ import { execSync } from "child_process";
136
+ import path4 from "path";
137
+ import { fileURLToPath } from "url";
138
+ import * as semver from "semver";
139
+
133
140
  // src/generators/config/wasp-config-generator.ts
134
141
  var WaspConfigGenerator = class {
135
142
  constructor(logger = getCLILogger(), fileSystem = realFileSystem) {
@@ -137,7 +144,7 @@ var WaspConfigGenerator = class {
137
144
  this.fileSystem = fileSystem;
138
145
  this.templateUtility = new TemplateUtility(fileSystem);
139
146
  }
140
- path = path4;
147
+ path = path5;
141
148
  templateUtility;
142
149
  /**
143
150
  * Gets the template path for feature config templates.
@@ -166,7 +173,7 @@ var WaspConfigGenerator = class {
166
173
  this.logger.error(`Template not found: ${templatePath}`);
167
174
  return;
168
175
  }
169
- const configFilePath = path4.join(featureDir, `feature.wasp.ts`);
176
+ const configFilePath = path5.join(featureDir, `feature.wasp.ts`);
170
177
  if (this.fileSystem.existsSync(configFilePath)) {
171
178
  this.logger.warn(`Feature config already exists: ${configFilePath}`);
172
179
  return;
@@ -182,7 +189,7 @@ var WaspConfigGenerator = class {
182
189
  */
183
190
  update(featurePath, declaration) {
184
191
  const configDir = getFeatureDir(this.fileSystem, featurePath);
185
- const configFilePath = path4.join(configDir, `feature.wasp.ts`);
192
+ const configFilePath = path5.join(configDir, `feature.wasp.ts`);
186
193
  if (!this.fileSystem.existsSync(configFilePath)) {
187
194
  const templatePath = this.getTemplatePath("feature.wasp.eta");
188
195
  if (!this.fileSystem.existsSync(templatePath)) {
@@ -4,7 +4,7 @@ import {
4
4
  handleFatalError,
5
5
  parseHelperMethodDefinition
6
6
  } from "@ingenyus/swarm";
7
- import path4 from "path";
7
+ import path5 from "path";
8
8
 
9
9
  // src/common/filesystem.ts
10
10
  import { toPascalCase } from "@ingenyus/swarm";
@@ -130,6 +130,13 @@ var TemplateUtility = class {
130
130
  }
131
131
  };
132
132
 
133
+ // src/common/wasp-compatibility.ts
134
+ import { findPackageJson, getVersion } from "@ingenyus/swarm";
135
+ import { execSync } from "child_process";
136
+ import path4 from "path";
137
+ import { fileURLToPath } from "url";
138
+ import * as semver from "semver";
139
+
133
140
  // src/generators/config/wasp-config-generator.ts
134
141
  var WaspConfigGenerator = class {
135
142
  constructor(logger = getCLILogger(), fileSystem = realFileSystem) {
@@ -137,7 +144,7 @@ var WaspConfigGenerator = class {
137
144
  this.fileSystem = fileSystem;
138
145
  this.templateUtility = new TemplateUtility(fileSystem);
139
146
  }
140
- path = path4;
147
+ path = path5;
141
148
  templateUtility;
142
149
  /**
143
150
  * Gets the template path for feature config templates.
@@ -166,7 +173,7 @@ var WaspConfigGenerator = class {
166
173
  this.logger.error(`Template not found: ${templatePath}`);
167
174
  return;
168
175
  }
169
- const configFilePath = path4.join(featureDir, `feature.wasp.ts`);
176
+ const configFilePath = path5.join(featureDir, `feature.wasp.ts`);
170
177
  if (this.fileSystem.existsSync(configFilePath)) {
171
178
  this.logger.warn(`Feature config already exists: ${configFilePath}`);
172
179
  return;
@@ -182,7 +189,7 @@ var WaspConfigGenerator = class {
182
189
  */
183
190
  update(featurePath, declaration) {
184
191
  const configDir = getFeatureDir(this.fileSystem, featurePath);
185
- const configFilePath = path4.join(configDir, `feature.wasp.ts`);
192
+ const configFilePath = path5.join(configDir, `feature.wasp.ts`);
186
193
  if (!this.fileSystem.existsSync(configFilePath)) {
187
194
  const templatePath = this.getTemplatePath("feature.wasp.eta");
188
195
  if (!this.fileSystem.existsSync(templatePath)) {
@@ -1 +1 @@
1
- {"version":3,"file":"crud-generator.d.ts","sourceRoot":"","sources":["../../../src/generators/crud/crud-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EAEjB,GAAG,EAGJ,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,YAAY,EAKb,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAUlC,qBAAa,aAAc,SAAQ,sBAAsB,CACvD,OAAO,MAAM,EACb,OAAO,YAAY,CAAC,IAAI,CACzB;IACC,SAAS,KAAK,aAAa,WAE1B;IAED,WAAW,SAAqC;IAChD,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;qCAAU;gBAEJ,QAAQ,EAAE,iBAAiB;IAIjC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;YAuCzC,gBAAgB;IA8B9B;;OAEG;IACH,OAAO,CAAC,mBAAmB;YAsBb,gBAAgB;IAoB9B,OAAO,CAAC,eAAe;IA+BvB;;OAEG;YACW,iBAAiB;IA4B/B;;OAEG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,GAAG,MAAM;CAoB3E"}
1
+ {"version":3,"file":"crud-generator.d.ts","sourceRoot":"","sources":["../../../src/generators/crud/crud-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EAEjB,GAAG,EAGJ,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,YAAY,EAKb,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAUlC,qBAAa,aAAc,SAAQ,sBAAsB,CACvD,OAAO,MAAM,EACb,OAAO,YAAY,CAAC,IAAI,CACzB;IACC,SAAS,KAAK,aAAa,WAE1B;IAED,WAAW,SAAqC;IAChD,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;qCAAU;gBAEJ,QAAQ,EAAE,iBAAiB;IAIjC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;YAyCzC,gBAAgB;IA8B9B;;OAEG;IACH,OAAO,CAAC,mBAAmB;YAsBb,gBAAgB;IAoB9B,OAAO,CAAC,eAAe;IA+BvB;;OAEG;YACW,iBAAiB;IA4B/B;;OAEG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,GAAG,MAAM;CAoB3E"}
@@ -381,22 +381,102 @@ var TemplateUtility = class {
381
381
  }
382
382
  };
383
383
 
384
+ // src/common/wasp-compatibility.ts
385
+ import { findPackageJson, getVersion } from "@ingenyus/swarm";
386
+ import { execSync } from "child_process";
387
+ import path4 from "path";
388
+ import { fileURLToPath } from "url";
389
+ import * as semver from "semver";
390
+ var cachedSupportedRange = null;
391
+ function getWaspSupportedRange() {
392
+ if (cachedSupportedRange) {
393
+ return cachedSupportedRange;
394
+ }
395
+ const currentFile = fileURLToPath(import.meta.url);
396
+ const currentDir = path4.dirname(currentFile);
397
+ const result = findPackageJson(currentDir, {
398
+ packageName: "@ingenyus/swarm-wasp"
399
+ });
400
+ if (!result) {
401
+ throw new Error(
402
+ "Unable to find package.json for @ingenyus/swarm-wasp. Wasp supported version range must be specified in swarm.wasp field."
403
+ );
404
+ }
405
+ const swarm = result.packageJson.swarm;
406
+ const waspRange = swarm?.wasp;
407
+ if (!waspRange) {
408
+ throw new Error(
409
+ `Wasp supported version range not found in package.json. Please specify swarm.wasp field in @ingenyus/swarm-wasp package.json (e.g., "swarm": { "wasp": ">=0.18.0 <0.20.0" }).`
410
+ );
411
+ }
412
+ cachedSupportedRange = waspRange;
413
+ return cachedSupportedRange;
414
+ }
415
+ function getInstalledWaspVersion(logger) {
416
+ try {
417
+ const output = execSync("wasp version", {
418
+ encoding: "utf8",
419
+ stdio: "pipe"
420
+ });
421
+ const firstLine = output.split("\n")[0]?.trim();
422
+ if (!firstLine) {
423
+ logger.error(
424
+ "Unable to parse Wasp version from command output. Expected version number on first line."
425
+ );
426
+ throw new Error("Unable to parse Wasp version from command output");
427
+ }
428
+ if (!semver.valid(firstLine)) {
429
+ logger.error(
430
+ `Invalid Wasp version format: "${firstLine}". Expected a valid semver version (e.g., "0.18.2").`
431
+ );
432
+ throw new Error("Invalid Wasp version format");
433
+ }
434
+ return firstLine;
435
+ } catch (error) {
436
+ if (error.code === "ENOENT" || error.message?.includes("wasp")) {
437
+ logger.error(
438
+ "Wasp CLI not found. Install using: curl -sSL https://get.wasp.sh/installer.sh | sh -s"
439
+ );
440
+ throw new Error("Wasp CLI not found");
441
+ }
442
+ throw new Error("Unable to determine installed Wasp version");
443
+ }
444
+ }
445
+ function isTestEnvironment() {
446
+ return process.env.NODE_ENV === "test" || process.env.VITEST === "true" || typeof process.env.VITEST !== "undefined";
447
+ }
448
+ function assertWaspCompatible(logger) {
449
+ if (isTestEnvironment()) {
450
+ return;
451
+ }
452
+ const version = getInstalledWaspVersion(logger);
453
+ const supportedRange = getWaspSupportedRange();
454
+ if (!semver.satisfies(version, supportedRange)) {
455
+ const startDir = path4.dirname(fileURLToPath(import.meta.url));
456
+ const packageVersion = getVersion("@ingenyus/swarm-wasp", startDir);
457
+ logger.error(
458
+ `Incompatible Wasp version detected: ${version}. @ingenyus/swarm-wasp@${packageVersion} supports Wasp ${supportedRange}.`
459
+ );
460
+ throw new Error("Incompatible Wasp version");
461
+ }
462
+ }
463
+
384
464
  // src/generators/base/component-generator.base.ts
385
465
  import {
386
466
  hasHelperMethodCall,
387
467
  toKebabCase as toKebabCase2
388
468
  } from "@ingenyus/swarm";
389
- import path6 from "path";
469
+ import path7 from "path";
390
470
 
391
471
  // src/generators/feature/feature-generator.ts
392
472
  import { handleFatalError as handleFatalError2 } from "@ingenyus/swarm";
393
- import path5 from "path";
473
+ import path6 from "path";
394
474
 
395
475
  // src/generators/base/wasp-generator.base.ts
396
476
  import {
397
477
  GeneratorBase,
398
- getConfigManager,
399
- TemplateResolver
478
+ TemplateResolver,
479
+ getConfigManager
400
480
  } from "@ingenyus/swarm";
401
481
 
402
482
  // src/generators/config/wasp-config-generator.ts
@@ -405,14 +485,14 @@ import {
405
485
  handleFatalError,
406
486
  parseHelperMethodDefinition
407
487
  } from "@ingenyus/swarm";
408
- import path4 from "path";
488
+ import path5 from "path";
409
489
  var WaspConfigGenerator = class {
410
490
  constructor(logger = getCLILogger(), fileSystem = realFileSystem) {
411
491
  this.logger = logger;
412
492
  this.fileSystem = fileSystem;
413
493
  this.templateUtility = new TemplateUtility(fileSystem);
414
494
  }
415
- path = path4;
495
+ path = path5;
416
496
  templateUtility;
417
497
  /**
418
498
  * Gets the template path for feature config templates.
@@ -441,7 +521,7 @@ var WaspConfigGenerator = class {
441
521
  this.logger.error(`Template not found: ${templatePath}`);
442
522
  return;
443
523
  }
444
- const configFilePath = path4.join(featureDir, `feature.wasp.ts`);
524
+ const configFilePath = path5.join(featureDir, `feature.wasp.ts`);
445
525
  if (this.fileSystem.existsSync(configFilePath)) {
446
526
  this.logger.warn(`Feature config already exists: ${configFilePath}`);
447
527
  return;
@@ -457,7 +537,7 @@ var WaspConfigGenerator = class {
457
537
  */
458
538
  update(featurePath, declaration) {
459
539
  const configDir = getFeatureDir(this.fileSystem, featurePath);
460
- const configFilePath = path4.join(configDir, `feature.wasp.ts`);
540
+ const configFilePath = path5.join(configDir, `feature.wasp.ts`);
461
541
  if (!this.fileSystem.existsSync(configFilePath)) {
462
542
  const templatePath = this.getTemplatePath("feature.wasp.eta");
463
543
  if (!this.fileSystem.existsSync(templatePath)) {
@@ -853,6 +933,13 @@ var WaspGeneratorBase = class extends GeneratorBase {
853
933
  this.templateUtility = new TemplateUtility(this.fileSystem);
854
934
  this.templateResolver = new TemplateResolver(this.fileSystem);
855
935
  }
936
+ /**
937
+ * Ensures that the installed Wasp version is compatible with this package.
938
+ * Should be called at the start of generator execution.
939
+ */
940
+ ensureWaspCompatible() {
941
+ assertWaspCompatible(this.logger);
942
+ }
856
943
  async loadConfig() {
857
944
  if (this.configLoaded) return;
858
945
  const configManager = getConfigManager();
@@ -969,21 +1056,22 @@ var FeatureGenerator = class extends WaspGeneratorBase {
969
1056
  * @param target - The target path of the generated directory
970
1057
  */
971
1058
  async generate(args) {
1059
+ this.ensureWaspCompatible();
972
1060
  const { target } = args;
973
1061
  const segments = validateFeaturePath(target);
974
1062
  const normalisedPath = normaliseFeaturePath(target);
975
- const sourceRoot = path5.join(findWaspRoot(this.fileSystem), "src");
1063
+ const sourceRoot = path6.join(findWaspRoot(this.fileSystem), "src");
976
1064
  if (segments.length > 1) {
977
1065
  const parentPath = segments.slice(0, -1).join("/");
978
1066
  const parentNormalisedPath = normaliseFeaturePath(parentPath);
979
- const parentFeatureDir = path5.join(sourceRoot, parentNormalisedPath);
1067
+ const parentFeatureDir = path6.join(sourceRoot, parentNormalisedPath);
980
1068
  if (!this.fileSystem.existsSync(parentFeatureDir)) {
981
1069
  handleFatalError2(
982
1070
  `Parent feature '${parentPath}' does not exist. Please create it first.`
983
1071
  );
984
1072
  }
985
1073
  }
986
- const featureDir = path5.join(sourceRoot, normalisedPath);
1074
+ const featureDir = path6.join(sourceRoot, normalisedPath);
987
1075
  this.fileSystem.mkdirSync(featureDir, { recursive: true });
988
1076
  this.configGenerator.generate(normalisedPath);
989
1077
  this.logger.success(`Generated feature: ${normalisedPath}`);
@@ -1018,7 +1106,7 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
1018
1106
  const currentPath = pathSegments.join("/");
1019
1107
  const featureName = pathSegments[pathSegments.length - 1];
1020
1108
  const featureDir = getFeatureDir(this.fileSystem, currentPath);
1021
- const configPath = path6.join(featureDir, `feature.wasp.ts`);
1109
+ const configPath = path7.join(featureDir, `feature.wasp.ts`);
1022
1110
  if (this.fileSystem.existsSync(configPath)) {
1023
1111
  return configPath;
1024
1112
  }
@@ -1090,7 +1178,7 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
1090
1178
  const featureDir = getFeatureDir(this.fileSystem, normalisedPath);
1091
1179
  const typeKey = type.toLowerCase();
1092
1180
  const typeDirectory = TYPE_DIRECTORIES[typeKey];
1093
- const targetDirectory = path6.join(featureDir, typeDirectory);
1181
+ const targetDirectory = path7.join(featureDir, typeDirectory);
1094
1182
  const importDirectory = `@src/${normalisedPath}/${typeDirectory}`;
1095
1183
  return { targetDirectory, importDirectory };
1096
1184
  }
@@ -1472,6 +1560,7 @@ var CrudGenerator = class extends OperationGeneratorBase {
1472
1560
  const crudName = name || toCamelCase(getPlural2(dataType));
1473
1561
  const crudType = toPascalCase3(crudName);
1474
1562
  return this.handleGeneratorError(this.componentType, crudName, async () => {
1563
+ this.ensureWaspCompatible();
1475
1564
  const configPath = this.validateFeatureConfig(feature);
1476
1565
  const { targetDirectory } = this.ensureTargetDirectory(
1477
1566
  feature,