@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
@@ -235,22 +235,102 @@ var TemplateUtility = class {
235
235
  }
236
236
  };
237
237
 
238
+ // src/common/wasp-compatibility.ts
239
+ import { findPackageJson, getVersion } from "@ingenyus/swarm";
240
+ import { execSync } from "child_process";
241
+ import path4 from "path";
242
+ import { fileURLToPath } from "url";
243
+ import * as semver from "semver";
244
+ var cachedSupportedRange = null;
245
+ function getWaspSupportedRange() {
246
+ if (cachedSupportedRange) {
247
+ return cachedSupportedRange;
248
+ }
249
+ const currentFile = fileURLToPath(import.meta.url);
250
+ const currentDir = path4.dirname(currentFile);
251
+ const result = findPackageJson(currentDir, {
252
+ packageName: "@ingenyus/swarm-wasp"
253
+ });
254
+ if (!result) {
255
+ throw new Error(
256
+ "Unable to find package.json for @ingenyus/swarm-wasp. Wasp supported version range must be specified in swarm.wasp field."
257
+ );
258
+ }
259
+ const swarm = result.packageJson.swarm;
260
+ const waspRange = swarm?.wasp;
261
+ if (!waspRange) {
262
+ throw new Error(
263
+ `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" }).`
264
+ );
265
+ }
266
+ cachedSupportedRange = waspRange;
267
+ return cachedSupportedRange;
268
+ }
269
+ function getInstalledWaspVersion(logger) {
270
+ try {
271
+ const output = execSync("wasp version", {
272
+ encoding: "utf8",
273
+ stdio: "pipe"
274
+ });
275
+ const firstLine = output.split("\n")[0]?.trim();
276
+ if (!firstLine) {
277
+ logger.error(
278
+ "Unable to parse Wasp version from command output. Expected version number on first line."
279
+ );
280
+ throw new Error("Unable to parse Wasp version from command output");
281
+ }
282
+ if (!semver.valid(firstLine)) {
283
+ logger.error(
284
+ `Invalid Wasp version format: "${firstLine}". Expected a valid semver version (e.g., "0.18.2").`
285
+ );
286
+ throw new Error("Invalid Wasp version format");
287
+ }
288
+ return firstLine;
289
+ } catch (error) {
290
+ if (error.code === "ENOENT" || error.message?.includes("wasp")) {
291
+ logger.error(
292
+ "Wasp CLI not found. Install using: curl -sSL https://get.wasp.sh/installer.sh | sh -s"
293
+ );
294
+ throw new Error("Wasp CLI not found");
295
+ }
296
+ throw new Error("Unable to determine installed Wasp version");
297
+ }
298
+ }
299
+ function isTestEnvironment() {
300
+ return process.env.NODE_ENV === "test" || process.env.VITEST === "true" || typeof process.env.VITEST !== "undefined";
301
+ }
302
+ function assertWaspCompatible(logger) {
303
+ if (isTestEnvironment()) {
304
+ return;
305
+ }
306
+ const version = getInstalledWaspVersion(logger);
307
+ const supportedRange = getWaspSupportedRange();
308
+ if (!semver.satisfies(version, supportedRange)) {
309
+ const startDir = path4.dirname(fileURLToPath(import.meta.url));
310
+ const packageVersion = getVersion("@ingenyus/swarm-wasp", startDir);
311
+ logger.error(
312
+ `Incompatible Wasp version detected: ${version}. @ingenyus/swarm-wasp@${packageVersion} supports Wasp ${supportedRange}.`
313
+ );
314
+ throw new Error("Incompatible Wasp version");
315
+ }
316
+ }
317
+
238
318
  // src/generators/base/component-generator.base.ts
239
319
  import {
240
320
  hasHelperMethodCall,
241
321
  toKebabCase as toKebabCase2
242
322
  } from "@ingenyus/swarm";
243
- import path6 from "path";
323
+ import path7 from "path";
244
324
 
245
325
  // src/generators/feature/feature-generator.ts
246
326
  import { handleFatalError as handleFatalError2 } from "@ingenyus/swarm";
247
- import path5 from "path";
327
+ import path6 from "path";
248
328
 
249
329
  // src/generators/base/wasp-generator.base.ts
250
330
  import {
251
331
  GeneratorBase,
252
- getConfigManager,
253
- TemplateResolver
332
+ TemplateResolver,
333
+ getConfigManager
254
334
  } from "@ingenyus/swarm";
255
335
 
256
336
  // src/generators/config/wasp-config-generator.ts
@@ -259,14 +339,14 @@ import {
259
339
  handleFatalError,
260
340
  parseHelperMethodDefinition
261
341
  } from "@ingenyus/swarm";
262
- import path4 from "path";
342
+ import path5 from "path";
263
343
  var WaspConfigGenerator = class {
264
344
  constructor(logger = getCLILogger(), fileSystem = realFileSystem) {
265
345
  this.logger = logger;
266
346
  this.fileSystem = fileSystem;
267
347
  this.templateUtility = new TemplateUtility(fileSystem);
268
348
  }
269
- path = path4;
349
+ path = path5;
270
350
  templateUtility;
271
351
  /**
272
352
  * Gets the template path for feature config templates.
@@ -295,7 +375,7 @@ var WaspConfigGenerator = class {
295
375
  this.logger.error(`Template not found: ${templatePath}`);
296
376
  return;
297
377
  }
298
- const configFilePath = path4.join(featureDir, `feature.wasp.ts`);
378
+ const configFilePath = path5.join(featureDir, `feature.wasp.ts`);
299
379
  if (this.fileSystem.existsSync(configFilePath)) {
300
380
  this.logger.warn(`Feature config already exists: ${configFilePath}`);
301
381
  return;
@@ -311,7 +391,7 @@ var WaspConfigGenerator = class {
311
391
  */
312
392
  update(featurePath, declaration) {
313
393
  const configDir = getFeatureDir(this.fileSystem, featurePath);
314
- const configFilePath = path4.join(configDir, `feature.wasp.ts`);
394
+ const configFilePath = path5.join(configDir, `feature.wasp.ts`);
315
395
  if (!this.fileSystem.existsSync(configFilePath)) {
316
396
  const templatePath = this.getTemplatePath("feature.wasp.eta");
317
397
  if (!this.fileSystem.existsSync(templatePath)) {
@@ -707,6 +787,13 @@ var WaspGeneratorBase = class extends GeneratorBase {
707
787
  this.templateUtility = new TemplateUtility(this.fileSystem);
708
788
  this.templateResolver = new TemplateResolver(this.fileSystem);
709
789
  }
790
+ /**
791
+ * Ensures that the installed Wasp version is compatible with this package.
792
+ * Should be called at the start of generator execution.
793
+ */
794
+ ensureWaspCompatible() {
795
+ assertWaspCompatible(this.logger);
796
+ }
710
797
  async loadConfig() {
711
798
  if (this.configLoaded) return;
712
799
  const configManager = getConfigManager();
@@ -823,21 +910,22 @@ var FeatureGenerator = class extends WaspGeneratorBase {
823
910
  * @param target - The target path of the generated directory
824
911
  */
825
912
  async generate(args) {
913
+ this.ensureWaspCompatible();
826
914
  const { target } = args;
827
915
  const segments = validateFeaturePath(target);
828
916
  const normalisedPath = normaliseFeaturePath(target);
829
- const sourceRoot = path5.join(findWaspRoot(this.fileSystem), "src");
917
+ const sourceRoot = path6.join(findWaspRoot(this.fileSystem), "src");
830
918
  if (segments.length > 1) {
831
919
  const parentPath = segments.slice(0, -1).join("/");
832
920
  const parentNormalisedPath = normaliseFeaturePath(parentPath);
833
- const parentFeatureDir = path5.join(sourceRoot, parentNormalisedPath);
921
+ const parentFeatureDir = path6.join(sourceRoot, parentNormalisedPath);
834
922
  if (!this.fileSystem.existsSync(parentFeatureDir)) {
835
923
  handleFatalError2(
836
924
  `Parent feature '${parentPath}' does not exist. Please create it first.`
837
925
  );
838
926
  }
839
927
  }
840
- const featureDir = path5.join(sourceRoot, normalisedPath);
928
+ const featureDir = path6.join(sourceRoot, normalisedPath);
841
929
  this.fileSystem.mkdirSync(featureDir, { recursive: true });
842
930
  this.configGenerator.generate(normalisedPath);
843
931
  this.logger.success(`Generated feature: ${normalisedPath}`);
@@ -872,7 +960,7 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
872
960
  const currentPath = pathSegments.join("/");
873
961
  const featureName = pathSegments[pathSegments.length - 1];
874
962
  const featureDir = getFeatureDir(this.fileSystem, currentPath);
875
- const configPath = path6.join(featureDir, `feature.wasp.ts`);
963
+ const configPath = path7.join(featureDir, `feature.wasp.ts`);
876
964
  if (this.fileSystem.existsSync(configPath)) {
877
965
  return configPath;
878
966
  }
@@ -944,7 +1032,7 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
944
1032
  const featureDir = getFeatureDir(this.fileSystem, normalisedPath);
945
1033
  const typeKey = type.toLowerCase();
946
1034
  const typeDirectory = TYPE_DIRECTORIES[typeKey];
947
- const targetDirectory = path6.join(featureDir, typeDirectory);
1035
+ const targetDirectory = path7.join(featureDir, typeDirectory);
948
1036
  const importDirectory = `@src/${normalisedPath}/${typeDirectory}`;
949
1037
  return { targetDirectory, importDirectory };
950
1038
  }
@@ -1046,6 +1134,7 @@ var ApiGenerator = class extends ComponentGeneratorBase {
1046
1134
  async generate(args) {
1047
1135
  const apiName = toCamelCase(args.name);
1048
1136
  return this.handleGeneratorError(this.componentType, apiName, async () => {
1137
+ this.ensureWaspCompatible();
1049
1138
  const configPath = this.validateFeatureConfig(args.feature);
1050
1139
  const {
1051
1140
  targetDirectory: apiTargetDirectory,
@@ -1092,7 +1181,7 @@ var ApiGenerator = class extends ComponentGeneratorBase {
1092
1181
  force = false,
1093
1182
  entities,
1094
1183
  method,
1095
- path: path7,
1184
+ path: path8,
1096
1185
  auth,
1097
1186
  customMiddleware
1098
1187
  } = args;
@@ -1102,7 +1191,7 @@ var ApiGenerator = class extends ComponentGeneratorBase {
1102
1191
  feature,
1103
1192
  Array.isArray(entities) ? entities : entities ? [entities] : [],
1104
1193
  method,
1105
- path7,
1194
+ path8,
1106
1195
  apiFile,
1107
1196
  auth,
1108
1197
  importPath,
@@ -235,22 +235,102 @@ var TemplateUtility = class {
235
235
  }
236
236
  };
237
237
 
238
+ // src/common/wasp-compatibility.ts
239
+ import { findPackageJson, getVersion } from "@ingenyus/swarm";
240
+ import { execSync } from "child_process";
241
+ import path4 from "path";
242
+ import { fileURLToPath } from "url";
243
+ import * as semver from "semver";
244
+ var cachedSupportedRange = null;
245
+ function getWaspSupportedRange() {
246
+ if (cachedSupportedRange) {
247
+ return cachedSupportedRange;
248
+ }
249
+ const currentFile = fileURLToPath(import.meta.url);
250
+ const currentDir = path4.dirname(currentFile);
251
+ const result = findPackageJson(currentDir, {
252
+ packageName: "@ingenyus/swarm-wasp"
253
+ });
254
+ if (!result) {
255
+ throw new Error(
256
+ "Unable to find package.json for @ingenyus/swarm-wasp. Wasp supported version range must be specified in swarm.wasp field."
257
+ );
258
+ }
259
+ const swarm = result.packageJson.swarm;
260
+ const waspRange = swarm?.wasp;
261
+ if (!waspRange) {
262
+ throw new Error(
263
+ `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" }).`
264
+ );
265
+ }
266
+ cachedSupportedRange = waspRange;
267
+ return cachedSupportedRange;
268
+ }
269
+ function getInstalledWaspVersion(logger) {
270
+ try {
271
+ const output = execSync("wasp version", {
272
+ encoding: "utf8",
273
+ stdio: "pipe"
274
+ });
275
+ const firstLine = output.split("\n")[0]?.trim();
276
+ if (!firstLine) {
277
+ logger.error(
278
+ "Unable to parse Wasp version from command output. Expected version number on first line."
279
+ );
280
+ throw new Error("Unable to parse Wasp version from command output");
281
+ }
282
+ if (!semver.valid(firstLine)) {
283
+ logger.error(
284
+ `Invalid Wasp version format: "${firstLine}". Expected a valid semver version (e.g., "0.18.2").`
285
+ );
286
+ throw new Error("Invalid Wasp version format");
287
+ }
288
+ return firstLine;
289
+ } catch (error) {
290
+ if (error.code === "ENOENT" || error.message?.includes("wasp")) {
291
+ logger.error(
292
+ "Wasp CLI not found. Install using: curl -sSL https://get.wasp.sh/installer.sh | sh -s"
293
+ );
294
+ throw new Error("Wasp CLI not found");
295
+ }
296
+ throw new Error("Unable to determine installed Wasp version");
297
+ }
298
+ }
299
+ function isTestEnvironment() {
300
+ return process.env.NODE_ENV === "test" || process.env.VITEST === "true" || typeof process.env.VITEST !== "undefined";
301
+ }
302
+ function assertWaspCompatible(logger) {
303
+ if (isTestEnvironment()) {
304
+ return;
305
+ }
306
+ const version = getInstalledWaspVersion(logger);
307
+ const supportedRange = getWaspSupportedRange();
308
+ if (!semver.satisfies(version, supportedRange)) {
309
+ const startDir = path4.dirname(fileURLToPath(import.meta.url));
310
+ const packageVersion = getVersion("@ingenyus/swarm-wasp", startDir);
311
+ logger.error(
312
+ `Incompatible Wasp version detected: ${version}. @ingenyus/swarm-wasp@${packageVersion} supports Wasp ${supportedRange}.`
313
+ );
314
+ throw new Error("Incompatible Wasp version");
315
+ }
316
+ }
317
+
238
318
  // src/generators/base/component-generator.base.ts
239
319
  import {
240
320
  hasHelperMethodCall,
241
321
  toKebabCase as toKebabCase2
242
322
  } from "@ingenyus/swarm";
243
- import path6 from "path";
323
+ import path7 from "path";
244
324
 
245
325
  // src/generators/feature/feature-generator.ts
246
326
  import { handleFatalError as handleFatalError2 } from "@ingenyus/swarm";
247
- import path5 from "path";
327
+ import path6 from "path";
248
328
 
249
329
  // src/generators/base/wasp-generator.base.ts
250
330
  import {
251
331
  GeneratorBase,
252
- getConfigManager,
253
- TemplateResolver
332
+ TemplateResolver,
333
+ getConfigManager
254
334
  } from "@ingenyus/swarm";
255
335
 
256
336
  // src/generators/config/wasp-config-generator.ts
@@ -259,14 +339,14 @@ import {
259
339
  handleFatalError,
260
340
  parseHelperMethodDefinition
261
341
  } from "@ingenyus/swarm";
262
- import path4 from "path";
342
+ import path5 from "path";
263
343
  var WaspConfigGenerator = class {
264
344
  constructor(logger = getCLILogger(), fileSystem = realFileSystem) {
265
345
  this.logger = logger;
266
346
  this.fileSystem = fileSystem;
267
347
  this.templateUtility = new TemplateUtility(fileSystem);
268
348
  }
269
- path = path4;
349
+ path = path5;
270
350
  templateUtility;
271
351
  /**
272
352
  * Gets the template path for feature config templates.
@@ -295,7 +375,7 @@ var WaspConfigGenerator = class {
295
375
  this.logger.error(`Template not found: ${templatePath}`);
296
376
  return;
297
377
  }
298
- const configFilePath = path4.join(featureDir, `feature.wasp.ts`);
378
+ const configFilePath = path5.join(featureDir, `feature.wasp.ts`);
299
379
  if (this.fileSystem.existsSync(configFilePath)) {
300
380
  this.logger.warn(`Feature config already exists: ${configFilePath}`);
301
381
  return;
@@ -311,7 +391,7 @@ var WaspConfigGenerator = class {
311
391
  */
312
392
  update(featurePath, declaration) {
313
393
  const configDir = getFeatureDir(this.fileSystem, featurePath);
314
- const configFilePath = path4.join(configDir, `feature.wasp.ts`);
394
+ const configFilePath = path5.join(configDir, `feature.wasp.ts`);
315
395
  if (!this.fileSystem.existsSync(configFilePath)) {
316
396
  const templatePath = this.getTemplatePath("feature.wasp.eta");
317
397
  if (!this.fileSystem.existsSync(templatePath)) {
@@ -707,6 +787,13 @@ var WaspGeneratorBase = class extends GeneratorBase {
707
787
  this.templateUtility = new TemplateUtility(this.fileSystem);
708
788
  this.templateResolver = new TemplateResolver(this.fileSystem);
709
789
  }
790
+ /**
791
+ * Ensures that the installed Wasp version is compatible with this package.
792
+ * Should be called at the start of generator execution.
793
+ */
794
+ ensureWaspCompatible() {
795
+ assertWaspCompatible(this.logger);
796
+ }
710
797
  async loadConfig() {
711
798
  if (this.configLoaded) return;
712
799
  const configManager = getConfigManager();
@@ -823,21 +910,22 @@ var FeatureGenerator = class extends WaspGeneratorBase {
823
910
  * @param target - The target path of the generated directory
824
911
  */
825
912
  async generate(args) {
913
+ this.ensureWaspCompatible();
826
914
  const { target } = args;
827
915
  const segments = validateFeaturePath(target);
828
916
  const normalisedPath = normaliseFeaturePath(target);
829
- const sourceRoot = path5.join(findWaspRoot(this.fileSystem), "src");
917
+ const sourceRoot = path6.join(findWaspRoot(this.fileSystem), "src");
830
918
  if (segments.length > 1) {
831
919
  const parentPath = segments.slice(0, -1).join("/");
832
920
  const parentNormalisedPath = normaliseFeaturePath(parentPath);
833
- const parentFeatureDir = path5.join(sourceRoot, parentNormalisedPath);
921
+ const parentFeatureDir = path6.join(sourceRoot, parentNormalisedPath);
834
922
  if (!this.fileSystem.existsSync(parentFeatureDir)) {
835
923
  handleFatalError2(
836
924
  `Parent feature '${parentPath}' does not exist. Please create it first.`
837
925
  );
838
926
  }
839
927
  }
840
- const featureDir = path5.join(sourceRoot, normalisedPath);
928
+ const featureDir = path6.join(sourceRoot, normalisedPath);
841
929
  this.fileSystem.mkdirSync(featureDir, { recursive: true });
842
930
  this.configGenerator.generate(normalisedPath);
843
931
  this.logger.success(`Generated feature: ${normalisedPath}`);
@@ -872,7 +960,7 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
872
960
  const currentPath = pathSegments.join("/");
873
961
  const featureName = pathSegments[pathSegments.length - 1];
874
962
  const featureDir = getFeatureDir(this.fileSystem, currentPath);
875
- const configPath = path6.join(featureDir, `feature.wasp.ts`);
963
+ const configPath = path7.join(featureDir, `feature.wasp.ts`);
876
964
  if (this.fileSystem.existsSync(configPath)) {
877
965
  return configPath;
878
966
  }
@@ -944,7 +1032,7 @@ var ComponentGeneratorBase = class extends WaspGeneratorBase {
944
1032
  const featureDir = getFeatureDir(this.fileSystem, normalisedPath);
945
1033
  const typeKey = type.toLowerCase();
946
1034
  const typeDirectory = TYPE_DIRECTORIES[typeKey];
947
- const targetDirectory = path6.join(featureDir, typeDirectory);
1035
+ const targetDirectory = path7.join(featureDir, typeDirectory);
948
1036
  const importDirectory = `@src/${normalisedPath}/${typeDirectory}`;
949
1037
  return { targetDirectory, importDirectory };
950
1038
  }
@@ -1046,6 +1134,7 @@ var ApiGenerator = class extends ComponentGeneratorBase {
1046
1134
  async generate(args) {
1047
1135
  const apiName = toCamelCase(args.name);
1048
1136
  return this.handleGeneratorError(this.componentType, apiName, async () => {
1137
+ this.ensureWaspCompatible();
1049
1138
  const configPath = this.validateFeatureConfig(args.feature);
1050
1139
  const {
1051
1140
  targetDirectory: apiTargetDirectory,
@@ -1092,7 +1181,7 @@ var ApiGenerator = class extends ComponentGeneratorBase {
1092
1181
  force = false,
1093
1182
  entities,
1094
1183
  method,
1095
- path: path7,
1184
+ path: path8,
1096
1185
  auth,
1097
1186
  customMiddleware
1098
1187
  } = args;
@@ -1102,7 +1191,7 @@ var ApiGenerator = class extends ComponentGeneratorBase {
1102
1191
  feature,
1103
1192
  Array.isArray(entities) ? entities : entities ? [entities] : [],
1104
1193
  method,
1105
- path7,
1194
+ path8,
1106
1195
  apiFile,
1107
1196
  auth,
1108
1197
  importPath,
@@ -113,6 +113,13 @@ var commonFieldMetadata = {
113
113
  import { toKebabCase } from "@ingenyus/swarm";
114
114
  import { Eta } from "eta";
115
115
 
116
+ // src/common/wasp-compatibility.ts
117
+ import { findPackageJson, getVersion } from "@ingenyus/swarm";
118
+ import { execSync } from "child_process";
119
+ import path2 from "path";
120
+ import { fileURLToPath } from "url";
121
+ import * as semver from "semver";
122
+
116
123
  // src/generators/api/schema.ts
117
124
  var validHttpMethods = API_HTTP_METHODS.map((method) => `${method}`);
118
125
  var baseSchema = z2.object({
@@ -1 +1 @@
1
- {"version":3,"file":"api-namespace-generator.d.ts","sourceRoot":"","sources":["../../../src/generators/api-namespace/api-namespace-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,GAAG,EAAe,MAAM,iBAAiB,CAAC;AAEtE,OAAO,EAAE,YAAY,EAAyB,MAAM,cAAc,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,qBAAa,qBAAsB,SAAQ,sBAAsB,CAC/D,OAAO,MAAM,EACb,OAAO,YAAY,CAAC,aAAa,CAClC;IACC,SAAS,KAAK,aAAa,mBAE1B;IAED,WAAW,SAAoC;IAC/C,MAAM;;;;;qCAAU;gBAEJ,QAAQ,EAAE,iBAAiB;IAIjC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;YAuCzC,gBAAgB;IAyB9B;;OAEG;IACG,aAAa,CACjB,aAAa,EAAE,MAAM,EACrB,oBAAoB,EAAE,MAAM,EAC5B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC;CAanB"}
1
+ {"version":3,"file":"api-namespace-generator.d.ts","sourceRoot":"","sources":["../../../src/generators/api-namespace/api-namespace-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,GAAG,EAAe,MAAM,iBAAiB,CAAC;AAEtE,OAAO,EAAE,YAAY,EAAyB,MAAM,cAAc,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,qBAAa,qBAAsB,SAAQ,sBAAsB,CAC/D,OAAO,MAAM,EACb,OAAO,YAAY,CAAC,aAAa,CAClC;IACC,SAAS,KAAK,aAAa,mBAE1B;IAED,WAAW,SAAoC;IAC/C,MAAM;;;;;qCAAU;gBAEJ,QAAQ,EAAE,iBAAiB;IAIjC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;YAyCzC,gBAAgB;IAyB9B;;OAEG;IACG,aAAa,CACjB,aAAa,EAAE,MAAM,EACrB,oBAAoB,EAAE,MAAM,EAC5B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC;CAanB"}
@@ -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
  );