@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.
- package/README.md +14 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/common/index.d.ts +1 -0
- package/dist/common/index.d.ts.map +1 -1
- package/dist/common/index.js +81 -0
- package/dist/common/wasp-compatibility.d.ts +10 -0
- package/dist/common/wasp-compatibility.d.ts.map +1 -0
- package/dist/common/wasp-compatibility.js +82 -0
- package/dist/generators/action/action-generator.d.ts.map +1 -1
- package/dist/generators/action/action-generator.js +102 -13
- package/dist/generators/action/index.js +102 -13
- package/dist/generators/action/schema.js +7 -0
- package/dist/generators/api/api-generator.d.ts.map +1 -1
- package/dist/generators/api/api-generator.js +104 -15
- package/dist/generators/api/index.js +104 -15
- package/dist/generators/api/schema.js +7 -0
- package/dist/generators/api-namespace/api-namespace-generator.d.ts.map +1 -1
- package/dist/generators/api-namespace/api-namespace-generator.js +104 -15
- package/dist/generators/api-namespace/index.js +104 -15
- package/dist/generators/api-namespace/schema.js +7 -0
- package/dist/generators/base/component-generator.base.js +101 -13
- package/dist/generators/base/index.js +101 -13
- package/dist/generators/base/operation-generator.base.js +101 -13
- package/dist/generators/base/wasp-generator.base.d.ts +5 -0
- package/dist/generators/base/wasp-generator.base.d.ts.map +1 -1
- package/dist/generators/base/wasp-generator.base.js +93 -6
- package/dist/generators/config/index.js +11 -4
- package/dist/generators/config/wasp-config-generator.js +11 -4
- package/dist/generators/crud/crud-generator.d.ts.map +1 -1
- package/dist/generators/crud/crud-generator.js +102 -13
- package/dist/generators/crud/index.js +102 -13
- package/dist/generators/crud/schema.js +7 -0
- package/dist/generators/feature/feature-generator.d.ts.map +1 -1
- package/dist/generators/feature/feature-generator.js +98 -10
- package/dist/generators/feature/index.js +98 -10
- package/dist/generators/feature/schema.js +7 -0
- package/dist/generators/index.js +112 -17
- package/dist/generators/job/index.js +102 -13
- package/dist/generators/job/job-generator.d.ts.map +1 -1
- package/dist/generators/job/job-generator.js +102 -13
- package/dist/generators/job/schema.js +7 -0
- package/dist/generators/query/index.js +102 -13
- package/dist/generators/query/query-generator.d.ts.map +1 -1
- package/dist/generators/query/query-generator.js +102 -13
- package/dist/generators/query/schema.js +7 -0
- package/dist/generators/route/index.js +102 -13
- package/dist/generators/route/route-generator.d.ts.map +1 -1
- package/dist/generators/route/route-generator.js +102 -13
- package/dist/generators/route/schema.js +7 -0
- package/dist/index.js +120 -25
- 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
|
|
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
|
|
327
|
+
import path6 from "path";
|
|
248
328
|
|
|
249
329
|
// src/generators/base/wasp-generator.base.ts
|
|
250
330
|
import {
|
|
251
331
|
GeneratorBase,
|
|
252
|
-
|
|
253
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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:
|
|
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
|
-
|
|
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
|
|
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
|
|
327
|
+
import path6 from "path";
|
|
248
328
|
|
|
249
329
|
// src/generators/base/wasp-generator.base.ts
|
|
250
330
|
import {
|
|
251
331
|
GeneratorBase,
|
|
252
|
-
|
|
253
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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:
|
|
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
|
-
|
|
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;
|
|
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
|
|
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
|
|
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
|
|
314
|
+
import path6 from "path";
|
|
235
315
|
|
|
236
316
|
// src/generators/base/wasp-generator.base.ts
|
|
237
317
|
import {
|
|
238
318
|
GeneratorBase,
|
|
239
|
-
|
|
240
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
1107
|
+
const middlewareTargetDirectory = path8.join(
|
|
1019
1108
|
apiTargetDirectory,
|
|
1020
1109
|
"middleware"
|
|
1021
1110
|
);
|