@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
@@ -412,6 +412,86 @@ var TemplateUtility = class {
412
412
  );
413
413
  }
414
414
  };
415
+
416
+ // src/common/wasp-compatibility.ts
417
+ import { findPackageJson, getVersion } from "@ingenyus/swarm";
418
+ import { execSync } from "child_process";
419
+ import path4 from "path";
420
+ import { fileURLToPath } from "url";
421
+ import * as semver from "semver";
422
+ var cachedSupportedRange = null;
423
+ function getWaspSupportedRange() {
424
+ if (cachedSupportedRange) {
425
+ return cachedSupportedRange;
426
+ }
427
+ const currentFile = fileURLToPath(import.meta.url);
428
+ const currentDir = path4.dirname(currentFile);
429
+ const result = findPackageJson(currentDir, {
430
+ packageName: "@ingenyus/swarm-wasp"
431
+ });
432
+ if (!result) {
433
+ throw new Error(
434
+ "Unable to find package.json for @ingenyus/swarm-wasp. Wasp supported version range must be specified in swarm.wasp field."
435
+ );
436
+ }
437
+ const swarm = result.packageJson.swarm;
438
+ const waspRange = swarm?.wasp;
439
+ if (!waspRange) {
440
+ throw new Error(
441
+ `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" }).`
442
+ );
443
+ }
444
+ cachedSupportedRange = waspRange;
445
+ return cachedSupportedRange;
446
+ }
447
+ function getInstalledWaspVersion(logger) {
448
+ try {
449
+ const output = execSync("wasp version", {
450
+ encoding: "utf8",
451
+ stdio: "pipe"
452
+ });
453
+ const firstLine = output.split("\n")[0]?.trim();
454
+ if (!firstLine) {
455
+ logger.error(
456
+ "Unable to parse Wasp version from command output. Expected version number on first line."
457
+ );
458
+ throw new Error("Unable to parse Wasp version from command output");
459
+ }
460
+ if (!semver.valid(firstLine)) {
461
+ logger.error(
462
+ `Invalid Wasp version format: "${firstLine}". Expected a valid semver version (e.g., "0.18.2").`
463
+ );
464
+ throw new Error("Invalid Wasp version format");
465
+ }
466
+ return firstLine;
467
+ } catch (error) {
468
+ if (error.code === "ENOENT" || error.message?.includes("wasp")) {
469
+ logger.error(
470
+ "Wasp CLI not found. Install using: curl -sSL https://get.wasp.sh/installer.sh | sh -s"
471
+ );
472
+ throw new Error("Wasp CLI not found");
473
+ }
474
+ throw new Error("Unable to determine installed Wasp version");
475
+ }
476
+ }
477
+ function isTestEnvironment() {
478
+ return process.env.NODE_ENV === "test" || process.env.VITEST === "true" || typeof process.env.VITEST !== "undefined";
479
+ }
480
+ function assertWaspCompatible(logger) {
481
+ if (isTestEnvironment()) {
482
+ return;
483
+ }
484
+ const version = getInstalledWaspVersion(logger);
485
+ const supportedRange = getWaspSupportedRange();
486
+ if (!semver.satisfies(version, supportedRange)) {
487
+ const startDir = path4.dirname(fileURLToPath(import.meta.url));
488
+ const packageVersion = getVersion("@ingenyus/swarm-wasp", startDir);
489
+ logger.error(
490
+ `Incompatible Wasp version detected: ${version}. @ingenyus/swarm-wasp@${packageVersion} supports Wasp ${supportedRange}.`
491
+ );
492
+ throw new Error("Incompatible Wasp version");
493
+ }
494
+ }
415
495
  export {
416
496
  ACTION_OPERATIONS,
417
497
  API_HTTP_METHODS,
@@ -423,6 +503,7 @@ export {
423
503
  QUERY_OPERATIONS,
424
504
  TYPE_DIRECTORIES,
425
505
  TemplateUtility,
506
+ assertWaspCompatible,
426
507
  commonFieldMetadata,
427
508
  commonSchemas,
428
509
  copyDirectory,
@@ -0,0 +1,10 @@
1
+ import { Logger } from '@ingenyus/swarm';
2
+ /**
3
+ * Asserts that the installed Wasp version is compatible with this package.
4
+ * Throws an error if the version is outside the supported range.
5
+ * Skips the check in test environments.
6
+ *
7
+ * @throws Error if Wasp version is incompatible or cannot be determined
8
+ */
9
+ export declare function assertWaspCompatible(logger: Logger): void;
10
+ //# sourceMappingURL=wasp-compatibility.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wasp-compatibility.d.ts","sourceRoot":"","sources":["../../src/common/wasp-compatibility.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAA+B,MAAM,iBAAiB,CAAC;AA6GtE;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAoBzD"}
@@ -0,0 +1,82 @@
1
+ // src/common/wasp-compatibility.ts
2
+ import { findPackageJson, getVersion } from "@ingenyus/swarm";
3
+ import { execSync } from "child_process";
4
+ import path from "path";
5
+ import { fileURLToPath } from "url";
6
+ import * as semver from "semver";
7
+ var cachedSupportedRange = null;
8
+ function getWaspSupportedRange() {
9
+ if (cachedSupportedRange) {
10
+ return cachedSupportedRange;
11
+ }
12
+ const currentFile = fileURLToPath(import.meta.url);
13
+ const currentDir = path.dirname(currentFile);
14
+ const result = findPackageJson(currentDir, {
15
+ packageName: "@ingenyus/swarm-wasp"
16
+ });
17
+ if (!result) {
18
+ throw new Error(
19
+ "Unable to find package.json for @ingenyus/swarm-wasp. Wasp supported version range must be specified in swarm.wasp field."
20
+ );
21
+ }
22
+ const swarm = result.packageJson.swarm;
23
+ const waspRange = swarm?.wasp;
24
+ if (!waspRange) {
25
+ throw new Error(
26
+ `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" }).`
27
+ );
28
+ }
29
+ cachedSupportedRange = waspRange;
30
+ return cachedSupportedRange;
31
+ }
32
+ function getInstalledWaspVersion(logger) {
33
+ try {
34
+ const output = execSync("wasp version", {
35
+ encoding: "utf8",
36
+ stdio: "pipe"
37
+ });
38
+ const firstLine = output.split("\n")[0]?.trim();
39
+ if (!firstLine) {
40
+ logger.error(
41
+ "Unable to parse Wasp version from command output. Expected version number on first line."
42
+ );
43
+ throw new Error("Unable to parse Wasp version from command output");
44
+ }
45
+ if (!semver.valid(firstLine)) {
46
+ logger.error(
47
+ `Invalid Wasp version format: "${firstLine}". Expected a valid semver version (e.g., "0.18.2").`
48
+ );
49
+ throw new Error("Invalid Wasp version format");
50
+ }
51
+ return firstLine;
52
+ } catch (error) {
53
+ if (error.code === "ENOENT" || error.message?.includes("wasp")) {
54
+ logger.error(
55
+ "Wasp CLI not found. Install using: curl -sSL https://get.wasp.sh/installer.sh | sh -s"
56
+ );
57
+ throw new Error("Wasp CLI not found");
58
+ }
59
+ throw new Error("Unable to determine installed Wasp version");
60
+ }
61
+ }
62
+ function isTestEnvironment() {
63
+ return process.env.NODE_ENV === "test" || process.env.VITEST === "true" || typeof process.env.VITEST !== "undefined";
64
+ }
65
+ function assertWaspCompatible(logger) {
66
+ if (isTestEnvironment()) {
67
+ return;
68
+ }
69
+ const version = getInstalledWaspVersion(logger);
70
+ const supportedRange = getWaspSupportedRange();
71
+ if (!semver.satisfies(version, supportedRange)) {
72
+ const startDir = path.dirname(fileURLToPath(import.meta.url));
73
+ const packageVersion = getVersion("@ingenyus/swarm-wasp", startDir);
74
+ logger.error(
75
+ `Incompatible Wasp version detected: ${version}. @ingenyus/swarm-wasp@${packageVersion} supports Wasp ${supportedRange}.`
76
+ );
77
+ throw new Error("Incompatible Wasp version");
78
+ }
79
+ }
80
+ export {
81
+ assertWaspCompatible
82
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"action-generator.d.ts","sourceRoot":"","sources":["../../../src/generators/action/action-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,qBAAa,eAAgB,SAAQ,sBAAsB,CACzD,OAAO,MAAM,EACb,OAAO,YAAY,CAAC,MAAM,CAC3B;IACC,SAAS,KAAK,aAAa,aAE1B;IAED,WAAW,SAA6B;IACxC,MAAM;;;;;;;;;;;;qCAAU;gBAEJ,QAAQ,EAAE,iBAAiB;IAIjC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CA0DxD"}
1
+ {"version":3,"file":"action-generator.d.ts","sourceRoot":"","sources":["../../../src/generators/action/action-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,qBAAa,eAAgB,SAAQ,sBAAsB,CACzD,OAAO,MAAM,EACb,OAAO,YAAY,CAAC,MAAM,CAC3B;IACC,SAAS,KAAK,aAAa,aAE1B;IAED,WAAW,SAA6B;IACxC,MAAM;;;;;;;;;;;;qCAAU;gBAEJ,QAAQ,EAAE,iBAAiB;IAIjC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CA4DxD"}
@@ -372,22 +372,102 @@ var TemplateUtility = class {
372
372
  }
373
373
  };
374
374
 
375
+ // src/common/wasp-compatibility.ts
376
+ import { findPackageJson, getVersion } from "@ingenyus/swarm";
377
+ import { execSync } from "child_process";
378
+ import path4 from "path";
379
+ import { fileURLToPath } from "url";
380
+ import * as semver from "semver";
381
+ var cachedSupportedRange = null;
382
+ function getWaspSupportedRange() {
383
+ if (cachedSupportedRange) {
384
+ return cachedSupportedRange;
385
+ }
386
+ const currentFile = fileURLToPath(import.meta.url);
387
+ const currentDir = path4.dirname(currentFile);
388
+ const result = findPackageJson(currentDir, {
389
+ packageName: "@ingenyus/swarm-wasp"
390
+ });
391
+ if (!result) {
392
+ throw new Error(
393
+ "Unable to find package.json for @ingenyus/swarm-wasp. Wasp supported version range must be specified in swarm.wasp field."
394
+ );
395
+ }
396
+ const swarm = result.packageJson.swarm;
397
+ const waspRange = swarm?.wasp;
398
+ if (!waspRange) {
399
+ throw new Error(
400
+ `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" }).`
401
+ );
402
+ }
403
+ cachedSupportedRange = waspRange;
404
+ return cachedSupportedRange;
405
+ }
406
+ function getInstalledWaspVersion(logger) {
407
+ try {
408
+ const output = execSync("wasp version", {
409
+ encoding: "utf8",
410
+ stdio: "pipe"
411
+ });
412
+ const firstLine = output.split("\n")[0]?.trim();
413
+ if (!firstLine) {
414
+ logger.error(
415
+ "Unable to parse Wasp version from command output. Expected version number on first line."
416
+ );
417
+ throw new Error("Unable to parse Wasp version from command output");
418
+ }
419
+ if (!semver.valid(firstLine)) {
420
+ logger.error(
421
+ `Invalid Wasp version format: "${firstLine}". Expected a valid semver version (e.g., "0.18.2").`
422
+ );
423
+ throw new Error("Invalid Wasp version format");
424
+ }
425
+ return firstLine;
426
+ } catch (error) {
427
+ if (error.code === "ENOENT" || error.message?.includes("wasp")) {
428
+ logger.error(
429
+ "Wasp CLI not found. Install using: curl -sSL https://get.wasp.sh/installer.sh | sh -s"
430
+ );
431
+ throw new Error("Wasp CLI not found");
432
+ }
433
+ throw new Error("Unable to determine installed Wasp version");
434
+ }
435
+ }
436
+ function isTestEnvironment() {
437
+ return process.env.NODE_ENV === "test" || process.env.VITEST === "true" || typeof process.env.VITEST !== "undefined";
438
+ }
439
+ function assertWaspCompatible(logger) {
440
+ if (isTestEnvironment()) {
441
+ return;
442
+ }
443
+ const version = getInstalledWaspVersion(logger);
444
+ const supportedRange = getWaspSupportedRange();
445
+ if (!semver.satisfies(version, supportedRange)) {
446
+ const startDir = path4.dirname(fileURLToPath(import.meta.url));
447
+ const packageVersion = getVersion("@ingenyus/swarm-wasp", startDir);
448
+ logger.error(
449
+ `Incompatible Wasp version detected: ${version}. @ingenyus/swarm-wasp@${packageVersion} supports Wasp ${supportedRange}.`
450
+ );
451
+ throw new Error("Incompatible Wasp version");
452
+ }
453
+ }
454
+
375
455
  // src/generators/base/component-generator.base.ts
376
456
  import {
377
457
  hasHelperMethodCall,
378
458
  toKebabCase as toKebabCase2
379
459
  } from "@ingenyus/swarm";
380
- import path6 from "path";
460
+ import path7 from "path";
381
461
 
382
462
  // src/generators/feature/feature-generator.ts
383
463
  import { handleFatalError as handleFatalError2 } from "@ingenyus/swarm";
384
- import path5 from "path";
464
+ import path6 from "path";
385
465
 
386
466
  // src/generators/base/wasp-generator.base.ts
387
467
  import {
388
468
  GeneratorBase,
389
- getConfigManager,
390
- TemplateResolver
469
+ TemplateResolver,
470
+ getConfigManager
391
471
  } from "@ingenyus/swarm";
392
472
 
393
473
  // src/generators/config/wasp-config-generator.ts
@@ -396,14 +476,14 @@ import {
396
476
  handleFatalError,
397
477
  parseHelperMethodDefinition
398
478
  } from "@ingenyus/swarm";
399
- import path4 from "path";
479
+ import path5 from "path";
400
480
  var WaspConfigGenerator = class {
401
481
  constructor(logger = getCLILogger(), fileSystem = realFileSystem) {
402
482
  this.logger = logger;
403
483
  this.fileSystem = fileSystem;
404
484
  this.templateUtility = new TemplateUtility(fileSystem);
405
485
  }
406
- path = path4;
486
+ path = path5;
407
487
  templateUtility;
408
488
  /**
409
489
  * Gets the template path for feature config templates.
@@ -432,7 +512,7 @@ var WaspConfigGenerator = class {
432
512
  this.logger.error(`Template not found: ${templatePath}`);
433
513
  return;
434
514
  }
435
- const configFilePath = path4.join(featureDir, `feature.wasp.ts`);
515
+ const configFilePath = path5.join(featureDir, `feature.wasp.ts`);
436
516
  if (this.fileSystem.existsSync(configFilePath)) {
437
517
  this.logger.warn(`Feature config already exists: ${configFilePath}`);
438
518
  return;
@@ -448,7 +528,7 @@ var WaspConfigGenerator = class {
448
528
  */
449
529
  update(featurePath, declaration) {
450
530
  const configDir = getFeatureDir(this.fileSystem, featurePath);
451
- const configFilePath = path4.join(configDir, `feature.wasp.ts`);
531
+ const configFilePath = path5.join(configDir, `feature.wasp.ts`);
452
532
  if (!this.fileSystem.existsSync(configFilePath)) {
453
533
  const templatePath = this.getTemplatePath("feature.wasp.eta");
454
534
  if (!this.fileSystem.existsSync(templatePath)) {
@@ -844,6 +924,13 @@ var WaspGeneratorBase = class extends GeneratorBase {
844
924
  this.templateUtility = new TemplateUtility(this.fileSystem);
845
925
  this.templateResolver = new TemplateResolver(this.fileSystem);
846
926
  }
927
+ /**
928
+ * Ensures that the installed Wasp version is compatible with this package.
929
+ * Should be called at the start of generator execution.
930
+ */
931
+ ensureWaspCompatible() {
932
+ assertWaspCompatible(this.logger);
933
+ }
847
934
  async loadConfig() {
848
935
  if (this.configLoaded) return;
849
936
  const configManager = getConfigManager();
@@ -960,21 +1047,22 @@ var FeatureGenerator = class extends WaspGeneratorBase {
960
1047
  * @param target - The target path of the generated directory
961
1048
  */
962
1049
  async generate(args) {
1050
+ this.ensureWaspCompatible();
963
1051
  const { target } = args;
964
1052
  const segments = validateFeaturePath(target);
965
1053
  const normalisedPath = normaliseFeaturePath(target);
966
- const sourceRoot = path5.join(findWaspRoot(this.fileSystem), "src");
1054
+ const sourceRoot = path6.join(findWaspRoot(this.fileSystem), "src");
967
1055
  if (segments.length > 1) {
968
1056
  const parentPath = segments.slice(0, -1).join("/");
969
1057
  const parentNormalisedPath = normaliseFeaturePath(parentPath);
970
- const parentFeatureDir = path5.join(sourceRoot, parentNormalisedPath);
1058
+ const parentFeatureDir = path6.join(sourceRoot, parentNormalisedPath);
971
1059
  if (!this.fileSystem.existsSync(parentFeatureDir)) {
972
1060
  handleFatalError2(
973
1061
  `Parent feature '${parentPath}' does not exist. Please create it first.`
974
1062
  );
975
1063
  }
976
1064
  }
977
- const featureDir = path5.join(sourceRoot, normalisedPath);
1065
+ const featureDir = path6.join(sourceRoot, normalisedPath);
978
1066
  this.fileSystem.mkdirSync(featureDir, { recursive: true });
979
1067
  this.configGenerator.generate(normalisedPath);
980
1068
  this.logger.success(`Generated feature: ${normalisedPath}`);
@@ -1009,7 +1097,7 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
1009
1097
  const currentPath = pathSegments.join("/");
1010
1098
  const featureName = pathSegments[pathSegments.length - 1];
1011
1099
  const featureDir = getFeatureDir(this.fileSystem, currentPath);
1012
- const configPath = path6.join(featureDir, `feature.wasp.ts`);
1100
+ const configPath = path7.join(featureDir, `feature.wasp.ts`);
1013
1101
  if (this.fileSystem.existsSync(configPath)) {
1014
1102
  return configPath;
1015
1103
  }
@@ -1081,7 +1169,7 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
1081
1169
  const featureDir = getFeatureDir(this.fileSystem, normalisedPath);
1082
1170
  const typeKey = type.toLowerCase();
1083
1171
  const typeDirectory = TYPE_DIRECTORIES[typeKey];
1084
- const targetDirectory = path6.join(featureDir, typeDirectory);
1172
+ const targetDirectory = path7.join(featureDir, typeDirectory);
1085
1173
  const importDirectory = `@src/${normalisedPath}/${typeDirectory}`;
1086
1174
  return { targetDirectory, importDirectory };
1087
1175
  }
@@ -1447,6 +1535,7 @@ var ActionGenerator = class extends OperationGeneratorBase {
1447
1535
  this.componentType,
1448
1536
  operationName,
1449
1537
  async () => {
1538
+ this.ensureWaspCompatible();
1450
1539
  const configPath = this.validateFeatureConfig(feature);
1451
1540
  const { targetDirectory: operationsDir, importDirectory } = this.ensureTargetDirectory(feature, operationType);
1452
1541
  const importPath = `${importDirectory}/${operationName}`;
@@ -372,22 +372,102 @@ var TemplateUtility = class {
372
372
  }
373
373
  };
374
374
 
375
+ // src/common/wasp-compatibility.ts
376
+ import { findPackageJson, getVersion } from "@ingenyus/swarm";
377
+ import { execSync } from "child_process";
378
+ import path4 from "path";
379
+ import { fileURLToPath } from "url";
380
+ import * as semver from "semver";
381
+ var cachedSupportedRange = null;
382
+ function getWaspSupportedRange() {
383
+ if (cachedSupportedRange) {
384
+ return cachedSupportedRange;
385
+ }
386
+ const currentFile = fileURLToPath(import.meta.url);
387
+ const currentDir = path4.dirname(currentFile);
388
+ const result = findPackageJson(currentDir, {
389
+ packageName: "@ingenyus/swarm-wasp"
390
+ });
391
+ if (!result) {
392
+ throw new Error(
393
+ "Unable to find package.json for @ingenyus/swarm-wasp. Wasp supported version range must be specified in swarm.wasp field."
394
+ );
395
+ }
396
+ const swarm = result.packageJson.swarm;
397
+ const waspRange = swarm?.wasp;
398
+ if (!waspRange) {
399
+ throw new Error(
400
+ `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" }).`
401
+ );
402
+ }
403
+ cachedSupportedRange = waspRange;
404
+ return cachedSupportedRange;
405
+ }
406
+ function getInstalledWaspVersion(logger) {
407
+ try {
408
+ const output = execSync("wasp version", {
409
+ encoding: "utf8",
410
+ stdio: "pipe"
411
+ });
412
+ const firstLine = output.split("\n")[0]?.trim();
413
+ if (!firstLine) {
414
+ logger.error(
415
+ "Unable to parse Wasp version from command output. Expected version number on first line."
416
+ );
417
+ throw new Error("Unable to parse Wasp version from command output");
418
+ }
419
+ if (!semver.valid(firstLine)) {
420
+ logger.error(
421
+ `Invalid Wasp version format: "${firstLine}". Expected a valid semver version (e.g., "0.18.2").`
422
+ );
423
+ throw new Error("Invalid Wasp version format");
424
+ }
425
+ return firstLine;
426
+ } catch (error) {
427
+ if (error.code === "ENOENT" || error.message?.includes("wasp")) {
428
+ logger.error(
429
+ "Wasp CLI not found. Install using: curl -sSL https://get.wasp.sh/installer.sh | sh -s"
430
+ );
431
+ throw new Error("Wasp CLI not found");
432
+ }
433
+ throw new Error("Unable to determine installed Wasp version");
434
+ }
435
+ }
436
+ function isTestEnvironment() {
437
+ return process.env.NODE_ENV === "test" || process.env.VITEST === "true" || typeof process.env.VITEST !== "undefined";
438
+ }
439
+ function assertWaspCompatible(logger) {
440
+ if (isTestEnvironment()) {
441
+ return;
442
+ }
443
+ const version = getInstalledWaspVersion(logger);
444
+ const supportedRange = getWaspSupportedRange();
445
+ if (!semver.satisfies(version, supportedRange)) {
446
+ const startDir = path4.dirname(fileURLToPath(import.meta.url));
447
+ const packageVersion = getVersion("@ingenyus/swarm-wasp", startDir);
448
+ logger.error(
449
+ `Incompatible Wasp version detected: ${version}. @ingenyus/swarm-wasp@${packageVersion} supports Wasp ${supportedRange}.`
450
+ );
451
+ throw new Error("Incompatible Wasp version");
452
+ }
453
+ }
454
+
375
455
  // src/generators/base/component-generator.base.ts
376
456
  import {
377
457
  hasHelperMethodCall,
378
458
  toKebabCase as toKebabCase2
379
459
  } from "@ingenyus/swarm";
380
- import path6 from "path";
460
+ import path7 from "path";
381
461
 
382
462
  // src/generators/feature/feature-generator.ts
383
463
  import { handleFatalError as handleFatalError2 } from "@ingenyus/swarm";
384
- import path5 from "path";
464
+ import path6 from "path";
385
465
 
386
466
  // src/generators/base/wasp-generator.base.ts
387
467
  import {
388
468
  GeneratorBase,
389
- getConfigManager,
390
- TemplateResolver
469
+ TemplateResolver,
470
+ getConfigManager
391
471
  } from "@ingenyus/swarm";
392
472
 
393
473
  // src/generators/config/wasp-config-generator.ts
@@ -396,14 +476,14 @@ import {
396
476
  handleFatalError,
397
477
  parseHelperMethodDefinition
398
478
  } from "@ingenyus/swarm";
399
- import path4 from "path";
479
+ import path5 from "path";
400
480
  var WaspConfigGenerator = class {
401
481
  constructor(logger = getCLILogger(), fileSystem = realFileSystem) {
402
482
  this.logger = logger;
403
483
  this.fileSystem = fileSystem;
404
484
  this.templateUtility = new TemplateUtility(fileSystem);
405
485
  }
406
- path = path4;
486
+ path = path5;
407
487
  templateUtility;
408
488
  /**
409
489
  * Gets the template path for feature config templates.
@@ -432,7 +512,7 @@ var WaspConfigGenerator = class {
432
512
  this.logger.error(`Template not found: ${templatePath}`);
433
513
  return;
434
514
  }
435
- const configFilePath = path4.join(featureDir, `feature.wasp.ts`);
515
+ const configFilePath = path5.join(featureDir, `feature.wasp.ts`);
436
516
  if (this.fileSystem.existsSync(configFilePath)) {
437
517
  this.logger.warn(`Feature config already exists: ${configFilePath}`);
438
518
  return;
@@ -448,7 +528,7 @@ var WaspConfigGenerator = class {
448
528
  */
449
529
  update(featurePath, declaration) {
450
530
  const configDir = getFeatureDir(this.fileSystem, featurePath);
451
- const configFilePath = path4.join(configDir, `feature.wasp.ts`);
531
+ const configFilePath = path5.join(configDir, `feature.wasp.ts`);
452
532
  if (!this.fileSystem.existsSync(configFilePath)) {
453
533
  const templatePath = this.getTemplatePath("feature.wasp.eta");
454
534
  if (!this.fileSystem.existsSync(templatePath)) {
@@ -844,6 +924,13 @@ var WaspGeneratorBase = class extends GeneratorBase {
844
924
  this.templateUtility = new TemplateUtility(this.fileSystem);
845
925
  this.templateResolver = new TemplateResolver(this.fileSystem);
846
926
  }
927
+ /**
928
+ * Ensures that the installed Wasp version is compatible with this package.
929
+ * Should be called at the start of generator execution.
930
+ */
931
+ ensureWaspCompatible() {
932
+ assertWaspCompatible(this.logger);
933
+ }
847
934
  async loadConfig() {
848
935
  if (this.configLoaded) return;
849
936
  const configManager = getConfigManager();
@@ -960,21 +1047,22 @@ var FeatureGenerator = class extends WaspGeneratorBase {
960
1047
  * @param target - The target path of the generated directory
961
1048
  */
962
1049
  async generate(args) {
1050
+ this.ensureWaspCompatible();
963
1051
  const { target } = args;
964
1052
  const segments = validateFeaturePath(target);
965
1053
  const normalisedPath = normaliseFeaturePath(target);
966
- const sourceRoot = path5.join(findWaspRoot(this.fileSystem), "src");
1054
+ const sourceRoot = path6.join(findWaspRoot(this.fileSystem), "src");
967
1055
  if (segments.length > 1) {
968
1056
  const parentPath = segments.slice(0, -1).join("/");
969
1057
  const parentNormalisedPath = normaliseFeaturePath(parentPath);
970
- const parentFeatureDir = path5.join(sourceRoot, parentNormalisedPath);
1058
+ const parentFeatureDir = path6.join(sourceRoot, parentNormalisedPath);
971
1059
  if (!this.fileSystem.existsSync(parentFeatureDir)) {
972
1060
  handleFatalError2(
973
1061
  `Parent feature '${parentPath}' does not exist. Please create it first.`
974
1062
  );
975
1063
  }
976
1064
  }
977
- const featureDir = path5.join(sourceRoot, normalisedPath);
1065
+ const featureDir = path6.join(sourceRoot, normalisedPath);
978
1066
  this.fileSystem.mkdirSync(featureDir, { recursive: true });
979
1067
  this.configGenerator.generate(normalisedPath);
980
1068
  this.logger.success(`Generated feature: ${normalisedPath}`);
@@ -1009,7 +1097,7 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
1009
1097
  const currentPath = pathSegments.join("/");
1010
1098
  const featureName = pathSegments[pathSegments.length - 1];
1011
1099
  const featureDir = getFeatureDir(this.fileSystem, currentPath);
1012
- const configPath = path6.join(featureDir, `feature.wasp.ts`);
1100
+ const configPath = path7.join(featureDir, `feature.wasp.ts`);
1013
1101
  if (this.fileSystem.existsSync(configPath)) {
1014
1102
  return configPath;
1015
1103
  }
@@ -1081,7 +1169,7 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
1081
1169
  const featureDir = getFeatureDir(this.fileSystem, normalisedPath);
1082
1170
  const typeKey = type.toLowerCase();
1083
1171
  const typeDirectory = TYPE_DIRECTORIES[typeKey];
1084
- const targetDirectory = path6.join(featureDir, typeDirectory);
1172
+ const targetDirectory = path7.join(featureDir, typeDirectory);
1085
1173
  const importDirectory = `@src/${normalisedPath}/${typeDirectory}`;
1086
1174
  return { targetDirectory, importDirectory };
1087
1175
  }
@@ -1447,6 +1535,7 @@ var ActionGenerator = class extends OperationGeneratorBase {
1447
1535
  this.componentType,
1448
1536
  operationName,
1449
1537
  async () => {
1538
+ this.ensureWaspCompatible();
1450
1539
  const configPath = this.validateFeatureConfig(feature);
1451
1540
  const { targetDirectory: operationsDir, importDirectory } = this.ensureTargetDirectory(feature, operationType);
1452
1541
  const importPath = `${importDirectory}/${operationName}`;
@@ -111,6 +111,13 @@ var commonFieldMetadata = {
111
111
  import { toKebabCase } from "@ingenyus/swarm";
112
112
  import { Eta } from "eta";
113
113
 
114
+ // src/common/wasp-compatibility.ts
115
+ import { findPackageJson, getVersion } from "@ingenyus/swarm";
116
+ import { execSync } from "child_process";
117
+ import path2 from "path";
118
+ import { fileURLToPath } from "url";
119
+ import * as semver from "semver";
120
+
114
121
  // src/generators/action/schema.ts
115
122
  var validActions = Object.values(ACTION_OPERATIONS);
116
123
  var actionSchema = z2.string().min(1, "Action type is required").transform((val) => SchemaManager.findEnumValue(ACTION_OPERATIONS, val)).pipe(
@@ -1 +1 @@
1
- {"version":3,"file":"api-generator.d.ts","sourceRoot":"","sources":["../../../src/generators/api/api-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,GAAG,EAGJ,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,YAAY,EAGb,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,qBAAa,YAAa,SAAQ,sBAAsB,CACtD,OAAO,MAAM,EACb,OAAO,YAAY,CAAC,GAAG,CACxB;IACC,SAAS,KAAK,aAAa,UAE1B;IAED,WAAW,SAAmC;IAC9C,MAAM;;;;;;;;;;;;;;;qCAAU;gBAEJ,QAAQ,EAAE,iBAAiB;IAIjC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;YAyCzC,eAAe;YAgBf,gBAAgB;YAuChB,mBAAmB;IA2BjC,OAAO,CAAC,iBAAiB;CA+B1B"}
1
+ {"version":3,"file":"api-generator.d.ts","sourceRoot":"","sources":["../../../src/generators/api/api-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,GAAG,EAGJ,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,YAAY,EAGb,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,qBAAa,YAAa,SAAQ,sBAAsB,CACtD,OAAO,MAAM,EACb,OAAO,YAAY,CAAC,GAAG,CACxB;IACC,SAAS,KAAK,aAAa,UAE1B;IAED,WAAW,SAAmC;IAC9C,MAAM;;;;;;;;;;;;;;;qCAAU;gBAEJ,QAAQ,EAAE,iBAAiB;IAIjC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;YA2CzC,eAAe;YAgBf,gBAAgB;YAuChB,mBAAmB;IA2BjC,OAAO,CAAC,iBAAiB;CA+B1B"}