@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
@@ -1,6 +1,6 @@
1
1
  // src/generators/api-namespace/api-namespace-generator.ts
2
2
  import { toCamelCase } from "@ingenyus/swarm";
3
- import path7 from "path";
3
+ import path8 from "path";
4
4
 
5
5
  // src/common/constants.ts
6
6
  var PLUGIN_NAME = "wasp";
@@ -222,22 +222,102 @@ var TemplateUtility = class {
222
222
  }
223
223
  };
224
224
 
225
+ // src/common/wasp-compatibility.ts
226
+ import { findPackageJson, getVersion } from "@ingenyus/swarm";
227
+ import { execSync } from "child_process";
228
+ import path4 from "path";
229
+ import { fileURLToPath } from "url";
230
+ import * as semver from "semver";
231
+ var cachedSupportedRange = null;
232
+ function getWaspSupportedRange() {
233
+ if (cachedSupportedRange) {
234
+ return cachedSupportedRange;
235
+ }
236
+ const currentFile = fileURLToPath(import.meta.url);
237
+ const currentDir = path4.dirname(currentFile);
238
+ const result = findPackageJson(currentDir, {
239
+ packageName: "@ingenyus/swarm-wasp"
240
+ });
241
+ if (!result) {
242
+ throw new Error(
243
+ "Unable to find package.json for @ingenyus/swarm-wasp. Wasp supported version range must be specified in swarm.wasp field."
244
+ );
245
+ }
246
+ const swarm = result.packageJson.swarm;
247
+ const waspRange = swarm?.wasp;
248
+ if (!waspRange) {
249
+ throw new Error(
250
+ `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" }).`
251
+ );
252
+ }
253
+ cachedSupportedRange = waspRange;
254
+ return cachedSupportedRange;
255
+ }
256
+ function getInstalledWaspVersion(logger) {
257
+ try {
258
+ const output = execSync("wasp version", {
259
+ encoding: "utf8",
260
+ stdio: "pipe"
261
+ });
262
+ const firstLine = output.split("\n")[0]?.trim();
263
+ if (!firstLine) {
264
+ logger.error(
265
+ "Unable to parse Wasp version from command output. Expected version number on first line."
266
+ );
267
+ throw new Error("Unable to parse Wasp version from command output");
268
+ }
269
+ if (!semver.valid(firstLine)) {
270
+ logger.error(
271
+ `Invalid Wasp version format: "${firstLine}". Expected a valid semver version (e.g., "0.18.2").`
272
+ );
273
+ throw new Error("Invalid Wasp version format");
274
+ }
275
+ return firstLine;
276
+ } catch (error) {
277
+ if (error.code === "ENOENT" || error.message?.includes("wasp")) {
278
+ logger.error(
279
+ "Wasp CLI not found. Install using: curl -sSL https://get.wasp.sh/installer.sh | sh -s"
280
+ );
281
+ throw new Error("Wasp CLI not found");
282
+ }
283
+ throw new Error("Unable to determine installed Wasp version");
284
+ }
285
+ }
286
+ function isTestEnvironment() {
287
+ return process.env.NODE_ENV === "test" || process.env.VITEST === "true" || typeof process.env.VITEST !== "undefined";
288
+ }
289
+ function assertWaspCompatible(logger) {
290
+ if (isTestEnvironment()) {
291
+ return;
292
+ }
293
+ const version = getInstalledWaspVersion(logger);
294
+ const supportedRange = getWaspSupportedRange();
295
+ if (!semver.satisfies(version, supportedRange)) {
296
+ const startDir = path4.dirname(fileURLToPath(import.meta.url));
297
+ const packageVersion = getVersion("@ingenyus/swarm-wasp", startDir);
298
+ logger.error(
299
+ `Incompatible Wasp version detected: ${version}. @ingenyus/swarm-wasp@${packageVersion} supports Wasp ${supportedRange}.`
300
+ );
301
+ throw new Error("Incompatible Wasp version");
302
+ }
303
+ }
304
+
225
305
  // src/generators/base/component-generator.base.ts
226
306
  import {
227
307
  hasHelperMethodCall,
228
308
  toKebabCase as toKebabCase2
229
309
  } from "@ingenyus/swarm";
230
- import path6 from "path";
310
+ import path7 from "path";
231
311
 
232
312
  // src/generators/feature/feature-generator.ts
233
313
  import { handleFatalError as handleFatalError2 } from "@ingenyus/swarm";
234
- import path5 from "path";
314
+ import path6 from "path";
235
315
 
236
316
  // src/generators/base/wasp-generator.base.ts
237
317
  import {
238
318
  GeneratorBase,
239
- getConfigManager,
240
- TemplateResolver
319
+ TemplateResolver,
320
+ getConfigManager
241
321
  } from "@ingenyus/swarm";
242
322
 
243
323
  // src/generators/config/wasp-config-generator.ts
@@ -246,14 +326,14 @@ import {
246
326
  handleFatalError,
247
327
  parseHelperMethodDefinition
248
328
  } from "@ingenyus/swarm";
249
- import path4 from "path";
329
+ import path5 from "path";
250
330
  var WaspConfigGenerator = class {
251
331
  constructor(logger = getCLILogger(), fileSystem = realFileSystem) {
252
332
  this.logger = logger;
253
333
  this.fileSystem = fileSystem;
254
334
  this.templateUtility = new TemplateUtility(fileSystem);
255
335
  }
256
- path = path4;
336
+ path = path5;
257
337
  templateUtility;
258
338
  /**
259
339
  * Gets the template path for feature config templates.
@@ -282,7 +362,7 @@ var WaspConfigGenerator = class {
282
362
  this.logger.error(`Template not found: ${templatePath}`);
283
363
  return;
284
364
  }
285
- const configFilePath = path4.join(featureDir, `feature.wasp.ts`);
365
+ const configFilePath = path5.join(featureDir, `feature.wasp.ts`);
286
366
  if (this.fileSystem.existsSync(configFilePath)) {
287
367
  this.logger.warn(`Feature config already exists: ${configFilePath}`);
288
368
  return;
@@ -298,7 +378,7 @@ var WaspConfigGenerator = class {
298
378
  */
299
379
  update(featurePath, declaration) {
300
380
  const configDir = getFeatureDir(this.fileSystem, featurePath);
301
- const configFilePath = path4.join(configDir, `feature.wasp.ts`);
381
+ const configFilePath = path5.join(configDir, `feature.wasp.ts`);
302
382
  if (!this.fileSystem.existsSync(configFilePath)) {
303
383
  const templatePath = this.getTemplatePath("feature.wasp.eta");
304
384
  if (!this.fileSystem.existsSync(templatePath)) {
@@ -694,6 +774,13 @@ var WaspGeneratorBase = class extends GeneratorBase {
694
774
  this.templateUtility = new TemplateUtility(this.fileSystem);
695
775
  this.templateResolver = new TemplateResolver(this.fileSystem);
696
776
  }
777
+ /**
778
+ * Ensures that the installed Wasp version is compatible with this package.
779
+ * Should be called at the start of generator execution.
780
+ */
781
+ ensureWaspCompatible() {
782
+ assertWaspCompatible(this.logger);
783
+ }
697
784
  async loadConfig() {
698
785
  if (this.configLoaded) return;
699
786
  const configManager = getConfigManager();
@@ -810,21 +897,22 @@ var FeatureGenerator = class extends WaspGeneratorBase {
810
897
  * @param target - The target path of the generated directory
811
898
  */
812
899
  async generate(args) {
900
+ this.ensureWaspCompatible();
813
901
  const { target } = args;
814
902
  const segments = validateFeaturePath(target);
815
903
  const normalisedPath = normaliseFeaturePath(target);
816
- const sourceRoot = path5.join(findWaspRoot(this.fileSystem), "src");
904
+ const sourceRoot = path6.join(findWaspRoot(this.fileSystem), "src");
817
905
  if (segments.length > 1) {
818
906
  const parentPath = segments.slice(0, -1).join("/");
819
907
  const parentNormalisedPath = normaliseFeaturePath(parentPath);
820
- const parentFeatureDir = path5.join(sourceRoot, parentNormalisedPath);
908
+ const parentFeatureDir = path6.join(sourceRoot, parentNormalisedPath);
821
909
  if (!this.fileSystem.existsSync(parentFeatureDir)) {
822
910
  handleFatalError2(
823
911
  `Parent feature '${parentPath}' does not exist. Please create it first.`
824
912
  );
825
913
  }
826
914
  }
827
- const featureDir = path5.join(sourceRoot, normalisedPath);
915
+ const featureDir = path6.join(sourceRoot, normalisedPath);
828
916
  this.fileSystem.mkdirSync(featureDir, { recursive: true });
829
917
  this.configGenerator.generate(normalisedPath);
830
918
  this.logger.success(`Generated feature: ${normalisedPath}`);
@@ -859,7 +947,7 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
859
947
  const currentPath = pathSegments.join("/");
860
948
  const featureName = pathSegments[pathSegments.length - 1];
861
949
  const featureDir = getFeatureDir(this.fileSystem, currentPath);
862
- const configPath = path6.join(featureDir, `feature.wasp.ts`);
950
+ const configPath = path7.join(featureDir, `feature.wasp.ts`);
863
951
  if (this.fileSystem.existsSync(configPath)) {
864
952
  return configPath;
865
953
  }
@@ -931,7 +1019,7 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
931
1019
  const featureDir = getFeatureDir(this.fileSystem, normalisedPath);
932
1020
  const typeKey = type.toLowerCase();
933
1021
  const typeDirectory = TYPE_DIRECTORIES[typeKey];
934
- const targetDirectory = path6.join(featureDir, typeDirectory);
1022
+ const targetDirectory = path7.join(featureDir, typeDirectory);
935
1023
  const importDirectory = `@src/${normalisedPath}/${typeDirectory}`;
936
1024
  return { targetDirectory, importDirectory };
937
1025
  }
@@ -1010,12 +1098,13 @@ var ApiNamespaceGenerator = class extends ComponentGeneratorBase {
1010
1098
  this.componentType,
1011
1099
  namespaceName,
1012
1100
  async () => {
1101
+ this.ensureWaspCompatible();
1013
1102
  const configPath = this.validateFeatureConfig(feature);
1014
1103
  const {
1015
1104
  targetDirectory: apiTargetDirectory,
1016
1105
  importDirectory: apiImportDirectory
1017
1106
  } = this.ensureTargetDirectory(feature, "api");
1018
- const middlewareTargetDirectory = path7.join(
1107
+ const middlewareTargetDirectory = path8.join(
1019
1108
  apiTargetDirectory,
1020
1109
  "middleware"
1021
1110
  );
@@ -104,6 +104,13 @@ var commonFieldMetadata = {
104
104
  import { toKebabCase } from "@ingenyus/swarm";
105
105
  import { Eta } from "eta";
106
106
 
107
+ // src/common/wasp-compatibility.ts
108
+ import { findPackageJson, getVersion } from "@ingenyus/swarm";
109
+ import { execSync } from "child_process";
110
+ import path2 from "path";
111
+ import { fileURLToPath } from "url";
112
+ import * as semver from "semver";
113
+
107
114
  // src/generators/api-namespace/schema.ts
108
115
  var baseSchema = z2.object({
109
116
  feature: commonSchemas.feature,
@@ -3,7 +3,7 @@ import {
3
3
  hasHelperMethodCall,
4
4
  toKebabCase as toKebabCase2
5
5
  } from "@ingenyus/swarm";
6
- import path6 from "path";
6
+ import path7 from "path";
7
7
 
8
8
  // src/common/constants.ts
9
9
  var PLUGIN_NAME = "wasp";
@@ -216,15 +216,95 @@ var TemplateUtility = class {
216
216
  }
217
217
  };
218
218
 
219
+ // src/common/wasp-compatibility.ts
220
+ import { findPackageJson, getVersion } from "@ingenyus/swarm";
221
+ import { execSync } from "child_process";
222
+ import path4 from "path";
223
+ import { fileURLToPath } from "url";
224
+ import * as semver from "semver";
225
+ var cachedSupportedRange = null;
226
+ function getWaspSupportedRange() {
227
+ if (cachedSupportedRange) {
228
+ return cachedSupportedRange;
229
+ }
230
+ const currentFile = fileURLToPath(import.meta.url);
231
+ const currentDir = path4.dirname(currentFile);
232
+ const result = findPackageJson(currentDir, {
233
+ packageName: "@ingenyus/swarm-wasp"
234
+ });
235
+ if (!result) {
236
+ throw new Error(
237
+ "Unable to find package.json for @ingenyus/swarm-wasp. Wasp supported version range must be specified in swarm.wasp field."
238
+ );
239
+ }
240
+ const swarm = result.packageJson.swarm;
241
+ const waspRange = swarm?.wasp;
242
+ if (!waspRange) {
243
+ throw new Error(
244
+ `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" }).`
245
+ );
246
+ }
247
+ cachedSupportedRange = waspRange;
248
+ return cachedSupportedRange;
249
+ }
250
+ function getInstalledWaspVersion(logger) {
251
+ try {
252
+ const output = execSync("wasp version", {
253
+ encoding: "utf8",
254
+ stdio: "pipe"
255
+ });
256
+ const firstLine = output.split("\n")[0]?.trim();
257
+ if (!firstLine) {
258
+ logger.error(
259
+ "Unable to parse Wasp version from command output. Expected version number on first line."
260
+ );
261
+ throw new Error("Unable to parse Wasp version from command output");
262
+ }
263
+ if (!semver.valid(firstLine)) {
264
+ logger.error(
265
+ `Invalid Wasp version format: "${firstLine}". Expected a valid semver version (e.g., "0.18.2").`
266
+ );
267
+ throw new Error("Invalid Wasp version format");
268
+ }
269
+ return firstLine;
270
+ } catch (error) {
271
+ if (error.code === "ENOENT" || error.message?.includes("wasp")) {
272
+ logger.error(
273
+ "Wasp CLI not found. Install using: curl -sSL https://get.wasp.sh/installer.sh | sh -s"
274
+ );
275
+ throw new Error("Wasp CLI not found");
276
+ }
277
+ throw new Error("Unable to determine installed Wasp version");
278
+ }
279
+ }
280
+ function isTestEnvironment() {
281
+ return process.env.NODE_ENV === "test" || process.env.VITEST === "true" || typeof process.env.VITEST !== "undefined";
282
+ }
283
+ function assertWaspCompatible(logger) {
284
+ if (isTestEnvironment()) {
285
+ return;
286
+ }
287
+ const version = getInstalledWaspVersion(logger);
288
+ const supportedRange = getWaspSupportedRange();
289
+ if (!semver.satisfies(version, supportedRange)) {
290
+ const startDir = path4.dirname(fileURLToPath(import.meta.url));
291
+ const packageVersion = getVersion("@ingenyus/swarm-wasp", startDir);
292
+ logger.error(
293
+ `Incompatible Wasp version detected: ${version}. @ingenyus/swarm-wasp@${packageVersion} supports Wasp ${supportedRange}.`
294
+ );
295
+ throw new Error("Incompatible Wasp version");
296
+ }
297
+ }
298
+
219
299
  // src/generators/feature/feature-generator.ts
220
300
  import { handleFatalError as handleFatalError2 } from "@ingenyus/swarm";
221
- import path5 from "path";
301
+ import path6 from "path";
222
302
 
223
303
  // src/generators/base/wasp-generator.base.ts
224
304
  import {
225
305
  GeneratorBase,
226
- getConfigManager,
227
- TemplateResolver
306
+ TemplateResolver,
307
+ getConfigManager
228
308
  } from "@ingenyus/swarm";
229
309
 
230
310
  // src/generators/config/wasp-config-generator.ts
@@ -233,14 +313,14 @@ import {
233
313
  handleFatalError,
234
314
  parseHelperMethodDefinition
235
315
  } from "@ingenyus/swarm";
236
- import path4 from "path";
316
+ import path5 from "path";
237
317
  var WaspConfigGenerator = class {
238
318
  constructor(logger = getCLILogger(), fileSystem = realFileSystem) {
239
319
  this.logger = logger;
240
320
  this.fileSystem = fileSystem;
241
321
  this.templateUtility = new TemplateUtility(fileSystem);
242
322
  }
243
- path = path4;
323
+ path = path5;
244
324
  templateUtility;
245
325
  /**
246
326
  * Gets the template path for feature config templates.
@@ -269,7 +349,7 @@ var WaspConfigGenerator = class {
269
349
  this.logger.error(`Template not found: ${templatePath}`);
270
350
  return;
271
351
  }
272
- const configFilePath = path4.join(featureDir, `feature.wasp.ts`);
352
+ const configFilePath = path5.join(featureDir, `feature.wasp.ts`);
273
353
  if (this.fileSystem.existsSync(configFilePath)) {
274
354
  this.logger.warn(`Feature config already exists: ${configFilePath}`);
275
355
  return;
@@ -285,7 +365,7 @@ var WaspConfigGenerator = class {
285
365
  */
286
366
  update(featurePath, declaration) {
287
367
  const configDir = getFeatureDir(this.fileSystem, featurePath);
288
- const configFilePath = path4.join(configDir, `feature.wasp.ts`);
368
+ const configFilePath = path5.join(configDir, `feature.wasp.ts`);
289
369
  if (!this.fileSystem.existsSync(configFilePath)) {
290
370
  const templatePath = this.getTemplatePath("feature.wasp.eta");
291
371
  if (!this.fileSystem.existsSync(templatePath)) {
@@ -681,6 +761,13 @@ var WaspGeneratorBase = class extends GeneratorBase {
681
761
  this.templateUtility = new TemplateUtility(this.fileSystem);
682
762
  this.templateResolver = new TemplateResolver(this.fileSystem);
683
763
  }
764
+ /**
765
+ * Ensures that the installed Wasp version is compatible with this package.
766
+ * Should be called at the start of generator execution.
767
+ */
768
+ ensureWaspCompatible() {
769
+ assertWaspCompatible(this.logger);
770
+ }
684
771
  async loadConfig() {
685
772
  if (this.configLoaded) return;
686
773
  const configManager = getConfigManager();
@@ -797,21 +884,22 @@ var FeatureGenerator = class extends WaspGeneratorBase {
797
884
  * @param target - The target path of the generated directory
798
885
  */
799
886
  async generate(args) {
887
+ this.ensureWaspCompatible();
800
888
  const { target } = args;
801
889
  const segments = validateFeaturePath(target);
802
890
  const normalisedPath = normaliseFeaturePath(target);
803
- const sourceRoot = path5.join(findWaspRoot(this.fileSystem), "src");
891
+ const sourceRoot = path6.join(findWaspRoot(this.fileSystem), "src");
804
892
  if (segments.length > 1) {
805
893
  const parentPath = segments.slice(0, -1).join("/");
806
894
  const parentNormalisedPath = normaliseFeaturePath(parentPath);
807
- const parentFeatureDir = path5.join(sourceRoot, parentNormalisedPath);
895
+ const parentFeatureDir = path6.join(sourceRoot, parentNormalisedPath);
808
896
  if (!this.fileSystem.existsSync(parentFeatureDir)) {
809
897
  handleFatalError2(
810
898
  `Parent feature '${parentPath}' does not exist. Please create it first.`
811
899
  );
812
900
  }
813
901
  }
814
- const featureDir = path5.join(sourceRoot, normalisedPath);
902
+ const featureDir = path6.join(sourceRoot, normalisedPath);
815
903
  this.fileSystem.mkdirSync(featureDir, { recursive: true });
816
904
  this.configGenerator.generate(normalisedPath);
817
905
  this.logger.success(`Generated feature: ${normalisedPath}`);
@@ -846,7 +934,7 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
846
934
  const currentPath = pathSegments.join("/");
847
935
  const featureName = pathSegments[pathSegments.length - 1];
848
936
  const featureDir = getFeatureDir(this.fileSystem, currentPath);
849
- const configPath = path6.join(featureDir, `feature.wasp.ts`);
937
+ const configPath = path7.join(featureDir, `feature.wasp.ts`);
850
938
  if (this.fileSystem.existsSync(configPath)) {
851
939
  return configPath;
852
940
  }
@@ -918,7 +1006,7 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
918
1006
  const featureDir = getFeatureDir(this.fileSystem, normalisedPath);
919
1007
  const typeKey = type.toLowerCase();
920
1008
  const typeDirectory = TYPE_DIRECTORIES[typeKey];
921
- const targetDirectory = path6.join(featureDir, typeDirectory);
1009
+ const targetDirectory = path7.join(featureDir, typeDirectory);
922
1010
  const importDirectory = `@src/${normalisedPath}/${typeDirectory}`;
923
1011
  return { targetDirectory, importDirectory };
924
1012
  }
@@ -3,7 +3,7 @@ import {
3
3
  hasHelperMethodCall,
4
4
  toKebabCase as toKebabCase2
5
5
  } from "@ingenyus/swarm";
6
- import path6 from "path";
6
+ import path7 from "path";
7
7
 
8
8
  // src/common/constants.ts
9
9
  var PLUGIN_NAME = "wasp";
@@ -365,15 +365,95 @@ var TemplateUtility = class {
365
365
  }
366
366
  };
367
367
 
368
+ // src/common/wasp-compatibility.ts
369
+ import { findPackageJson, getVersion } from "@ingenyus/swarm";
370
+ import { execSync } from "child_process";
371
+ import path4 from "path";
372
+ import { fileURLToPath } from "url";
373
+ import * as semver from "semver";
374
+ var cachedSupportedRange = null;
375
+ function getWaspSupportedRange() {
376
+ if (cachedSupportedRange) {
377
+ return cachedSupportedRange;
378
+ }
379
+ const currentFile = fileURLToPath(import.meta.url);
380
+ const currentDir = path4.dirname(currentFile);
381
+ const result = findPackageJson(currentDir, {
382
+ packageName: "@ingenyus/swarm-wasp"
383
+ });
384
+ if (!result) {
385
+ throw new Error(
386
+ "Unable to find package.json for @ingenyus/swarm-wasp. Wasp supported version range must be specified in swarm.wasp field."
387
+ );
388
+ }
389
+ const swarm = result.packageJson.swarm;
390
+ const waspRange = swarm?.wasp;
391
+ if (!waspRange) {
392
+ throw new Error(
393
+ `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" }).`
394
+ );
395
+ }
396
+ cachedSupportedRange = waspRange;
397
+ return cachedSupportedRange;
398
+ }
399
+ function getInstalledWaspVersion(logger) {
400
+ try {
401
+ const output = execSync("wasp version", {
402
+ encoding: "utf8",
403
+ stdio: "pipe"
404
+ });
405
+ const firstLine = output.split("\n")[0]?.trim();
406
+ if (!firstLine) {
407
+ logger.error(
408
+ "Unable to parse Wasp version from command output. Expected version number on first line."
409
+ );
410
+ throw new Error("Unable to parse Wasp version from command output");
411
+ }
412
+ if (!semver.valid(firstLine)) {
413
+ logger.error(
414
+ `Invalid Wasp version format: "${firstLine}". Expected a valid semver version (e.g., "0.18.2").`
415
+ );
416
+ throw new Error("Invalid Wasp version format");
417
+ }
418
+ return firstLine;
419
+ } catch (error) {
420
+ if (error.code === "ENOENT" || error.message?.includes("wasp")) {
421
+ logger.error(
422
+ "Wasp CLI not found. Install using: curl -sSL https://get.wasp.sh/installer.sh | sh -s"
423
+ );
424
+ throw new Error("Wasp CLI not found");
425
+ }
426
+ throw new Error("Unable to determine installed Wasp version");
427
+ }
428
+ }
429
+ function isTestEnvironment() {
430
+ return process.env.NODE_ENV === "test" || process.env.VITEST === "true" || typeof process.env.VITEST !== "undefined";
431
+ }
432
+ function assertWaspCompatible(logger) {
433
+ if (isTestEnvironment()) {
434
+ return;
435
+ }
436
+ const version = getInstalledWaspVersion(logger);
437
+ const supportedRange = getWaspSupportedRange();
438
+ if (!semver.satisfies(version, supportedRange)) {
439
+ const startDir = path4.dirname(fileURLToPath(import.meta.url));
440
+ const packageVersion = getVersion("@ingenyus/swarm-wasp", startDir);
441
+ logger.error(
442
+ `Incompatible Wasp version detected: ${version}. @ingenyus/swarm-wasp@${packageVersion} supports Wasp ${supportedRange}.`
443
+ );
444
+ throw new Error("Incompatible Wasp version");
445
+ }
446
+ }
447
+
368
448
  // src/generators/feature/feature-generator.ts
369
449
  import { handleFatalError as handleFatalError2 } from "@ingenyus/swarm";
370
- import path5 from "path";
450
+ import path6 from "path";
371
451
 
372
452
  // src/generators/base/wasp-generator.base.ts
373
453
  import {
374
454
  GeneratorBase,
375
- getConfigManager,
376
- TemplateResolver
455
+ TemplateResolver,
456
+ getConfigManager
377
457
  } from "@ingenyus/swarm";
378
458
 
379
459
  // src/generators/config/wasp-config-generator.ts
@@ -382,14 +462,14 @@ import {
382
462
  handleFatalError,
383
463
  parseHelperMethodDefinition
384
464
  } from "@ingenyus/swarm";
385
- import path4 from "path";
465
+ import path5 from "path";
386
466
  var WaspConfigGenerator = class {
387
467
  constructor(logger = getCLILogger(), fileSystem = realFileSystem) {
388
468
  this.logger = logger;
389
469
  this.fileSystem = fileSystem;
390
470
  this.templateUtility = new TemplateUtility(fileSystem);
391
471
  }
392
- path = path4;
472
+ path = path5;
393
473
  templateUtility;
394
474
  /**
395
475
  * Gets the template path for feature config templates.
@@ -418,7 +498,7 @@ var WaspConfigGenerator = class {
418
498
  this.logger.error(`Template not found: ${templatePath}`);
419
499
  return;
420
500
  }
421
- const configFilePath = path4.join(featureDir, `feature.wasp.ts`);
501
+ const configFilePath = path5.join(featureDir, `feature.wasp.ts`);
422
502
  if (this.fileSystem.existsSync(configFilePath)) {
423
503
  this.logger.warn(`Feature config already exists: ${configFilePath}`);
424
504
  return;
@@ -434,7 +514,7 @@ var WaspConfigGenerator = class {
434
514
  */
435
515
  update(featurePath, declaration) {
436
516
  const configDir = getFeatureDir(this.fileSystem, featurePath);
437
- const configFilePath = path4.join(configDir, `feature.wasp.ts`);
517
+ const configFilePath = path5.join(configDir, `feature.wasp.ts`);
438
518
  if (!this.fileSystem.existsSync(configFilePath)) {
439
519
  const templatePath = this.getTemplatePath("feature.wasp.eta");
440
520
  if (!this.fileSystem.existsSync(templatePath)) {
@@ -830,6 +910,13 @@ var WaspGeneratorBase = class extends GeneratorBase {
830
910
  this.templateUtility = new TemplateUtility(this.fileSystem);
831
911
  this.templateResolver = new TemplateResolver(this.fileSystem);
832
912
  }
913
+ /**
914
+ * Ensures that the installed Wasp version is compatible with this package.
915
+ * Should be called at the start of generator execution.
916
+ */
917
+ ensureWaspCompatible() {
918
+ assertWaspCompatible(this.logger);
919
+ }
833
920
  async loadConfig() {
834
921
  if (this.configLoaded) return;
835
922
  const configManager = getConfigManager();
@@ -946,21 +1033,22 @@ var FeatureGenerator = class extends WaspGeneratorBase {
946
1033
  * @param target - The target path of the generated directory
947
1034
  */
948
1035
  async generate(args) {
1036
+ this.ensureWaspCompatible();
949
1037
  const { target } = args;
950
1038
  const segments = validateFeaturePath(target);
951
1039
  const normalisedPath = normaliseFeaturePath(target);
952
- const sourceRoot = path5.join(findWaspRoot(this.fileSystem), "src");
1040
+ const sourceRoot = path6.join(findWaspRoot(this.fileSystem), "src");
953
1041
  if (segments.length > 1) {
954
1042
  const parentPath = segments.slice(0, -1).join("/");
955
1043
  const parentNormalisedPath = normaliseFeaturePath(parentPath);
956
- const parentFeatureDir = path5.join(sourceRoot, parentNormalisedPath);
1044
+ const parentFeatureDir = path6.join(sourceRoot, parentNormalisedPath);
957
1045
  if (!this.fileSystem.existsSync(parentFeatureDir)) {
958
1046
  handleFatalError2(
959
1047
  `Parent feature '${parentPath}' does not exist. Please create it first.`
960
1048
  );
961
1049
  }
962
1050
  }
963
- const featureDir = path5.join(sourceRoot, normalisedPath);
1051
+ const featureDir = path6.join(sourceRoot, normalisedPath);
964
1052
  this.fileSystem.mkdirSync(featureDir, { recursive: true });
965
1053
  this.configGenerator.generate(normalisedPath);
966
1054
  this.logger.success(`Generated feature: ${normalisedPath}`);
@@ -995,7 +1083,7 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
995
1083
  const currentPath = pathSegments.join("/");
996
1084
  const featureName = pathSegments[pathSegments.length - 1];
997
1085
  const featureDir = getFeatureDir(this.fileSystem, currentPath);
998
- const configPath = path6.join(featureDir, `feature.wasp.ts`);
1086
+ const configPath = path7.join(featureDir, `feature.wasp.ts`);
999
1087
  if (this.fileSystem.existsSync(configPath)) {
1000
1088
  return configPath;
1001
1089
  }
@@ -1067,7 +1155,7 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
1067
1155
  const featureDir = getFeatureDir(this.fileSystem, normalisedPath);
1068
1156
  const typeKey = type.toLowerCase();
1069
1157
  const typeDirectory = TYPE_DIRECTORIES[typeKey];
1070
- const targetDirectory = path6.join(featureDir, typeDirectory);
1158
+ const targetDirectory = path7.join(featureDir, typeDirectory);
1071
1159
  const importDirectory = `@src/${normalisedPath}/${typeDirectory}`;
1072
1160
  return { targetDirectory, importDirectory };
1073
1161
  }