@solid-stack/mason 1.0.15 → 1.0.16
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/dist/bin.cjs +375 -309
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +374 -308
- package/dist/bin.js.map +1 -1
- package/dist/commands/import.d.ts.map +1 -1
- package/dist/index.cjs +374 -308
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +374 -308
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var fs4 = require('fs');
|
|
4
4
|
var path2 = require('path');
|
|
5
|
-
var
|
|
5
|
+
var p14 = require('@clack/prompts');
|
|
6
6
|
var pc14 = require('picocolors');
|
|
7
7
|
var url = require('url');
|
|
8
8
|
var child_process = require('child_process');
|
|
@@ -33,7 +33,7 @@ function _interopNamespace(e) {
|
|
|
33
33
|
|
|
34
34
|
var fs4__default = /*#__PURE__*/_interopDefault(fs4);
|
|
35
35
|
var path2__default = /*#__PURE__*/_interopDefault(path2);
|
|
36
|
-
var
|
|
36
|
+
var p14__namespace = /*#__PURE__*/_interopNamespace(p14);
|
|
37
37
|
var pc14__default = /*#__PURE__*/_interopDefault(pc14);
|
|
38
38
|
var Handlebars__default = /*#__PURE__*/_interopDefault(Handlebars);
|
|
39
39
|
|
|
@@ -141,17 +141,17 @@ function writeFileSafely(absolutePath, content, options = {}) {
|
|
|
141
141
|
function printGeneratedFiles(files, isDryRun = false) {
|
|
142
142
|
console.log("");
|
|
143
143
|
if (isDryRun) {
|
|
144
|
-
|
|
144
|
+
p14__namespace.log.warn(pc14__default.default.yellow(pc14__default.default.bold("[DRY RUN PREVIEW] No files were written to disk.")));
|
|
145
145
|
}
|
|
146
146
|
for (const f of files) {
|
|
147
147
|
if (f.action === "created") {
|
|
148
|
-
|
|
148
|
+
p14__namespace.log.success(`${pc14__default.default.bold(f.relativePath)} ${pc14__default.default.dim("(created)")}`);
|
|
149
149
|
} else if (f.action === "overwritten") {
|
|
150
|
-
|
|
150
|
+
p14__namespace.log.warn(`${pc14__default.default.bold(f.relativePath)} ${pc14__default.default.dim("(overwritten)")}`);
|
|
151
151
|
} else if (f.action === "skipped") {
|
|
152
|
-
|
|
152
|
+
p14__namespace.log.info(`${pc14__default.default.dim(f.relativePath)} ${pc14__default.default.dim("(skipped - already exists, pass -o to overwrite)")}`);
|
|
153
153
|
} else {
|
|
154
|
-
|
|
154
|
+
p14__namespace.log.info(`${pc14__default.default.bold(f.relativePath)} ${pc14__default.default.dim("(preview)")}`);
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
}
|
|
@@ -347,23 +347,23 @@ var PromptCancelledError = class extends Error {
|
|
|
347
347
|
}
|
|
348
348
|
};
|
|
349
349
|
function handleCancel(result) {
|
|
350
|
-
if (
|
|
351
|
-
|
|
350
|
+
if (p14__namespace.isCancel(result)) {
|
|
351
|
+
p14__namespace.cancel("Operation cancelled.");
|
|
352
352
|
throw new PromptCancelledError();
|
|
353
353
|
}
|
|
354
354
|
return result;
|
|
355
355
|
}
|
|
356
356
|
function printBanner() {
|
|
357
357
|
console.log("");
|
|
358
|
-
|
|
358
|
+
p14__namespace.intro(pc14__default.default.bgCyan(pc14__default.default.black(" @solid-stack/mason ")));
|
|
359
359
|
}
|
|
360
360
|
async function promptProperties(options = {}) {
|
|
361
361
|
const properties = options.defaults ? [...options.defaults] : [];
|
|
362
362
|
if (properties.length > 0) {
|
|
363
363
|
const summary = properties.map((p16) => `${p16.name}: ${p16.type}${p16.optional ? "?" : ""}`).join(", ");
|
|
364
|
-
|
|
364
|
+
p14__namespace.log.info(pc14__default.default.dim(`Pre-configured fields: ${summary}`));
|
|
365
365
|
const addMore = handleCancel(
|
|
366
|
-
await
|
|
366
|
+
await p14__namespace.confirm({
|
|
367
367
|
message: "Would you like to add custom fields/properties?",
|
|
368
368
|
initialValue: false
|
|
369
369
|
})
|
|
@@ -372,10 +372,10 @@ async function promptProperties(options = {}) {
|
|
|
372
372
|
return properties;
|
|
373
373
|
}
|
|
374
374
|
}
|
|
375
|
-
|
|
375
|
+
p14__namespace.log.info(pc14__default.default.cyan("Enter properties (leave name blank when finished):"));
|
|
376
376
|
while (true) {
|
|
377
377
|
const name = handleCancel(
|
|
378
|
-
await
|
|
378
|
+
await p14__namespace.text({
|
|
379
379
|
message: "Property name (or press Enter to finish):",
|
|
380
380
|
placeholder: "e.g. title, email, status"
|
|
381
381
|
})
|
|
@@ -384,7 +384,7 @@ async function promptProperties(options = {}) {
|
|
|
384
384
|
break;
|
|
385
385
|
}
|
|
386
386
|
const type = handleCancel(
|
|
387
|
-
await
|
|
387
|
+
await p14__namespace.select({
|
|
388
388
|
message: `Type for property "${name.trim()}":`,
|
|
389
389
|
options: [
|
|
390
390
|
{ value: "string", label: "string" },
|
|
@@ -401,7 +401,7 @@ async function promptProperties(options = {}) {
|
|
|
401
401
|
let finalType = type;
|
|
402
402
|
if (type === "custom") {
|
|
403
403
|
finalType = handleCancel(
|
|
404
|
-
await
|
|
404
|
+
await p14__namespace.text({
|
|
405
405
|
message: `Enter custom type for "${name.trim()}":`,
|
|
406
406
|
placeholder: "e.g. UserRole, string | null",
|
|
407
407
|
validate: (val) => val && val.trim() ? void 0 : "Type cannot be empty"
|
|
@@ -409,7 +409,7 @@ async function promptProperties(options = {}) {
|
|
|
409
409
|
);
|
|
410
410
|
}
|
|
411
411
|
const optional = handleCancel(
|
|
412
|
-
await
|
|
412
|
+
await p14__namespace.confirm({
|
|
413
413
|
message: `Is "${name.trim()}" optional?`,
|
|
414
414
|
initialValue: false
|
|
415
415
|
})
|
|
@@ -419,7 +419,7 @@ async function promptProperties(options = {}) {
|
|
|
419
419
|
type: finalType.trim(),
|
|
420
420
|
optional
|
|
421
421
|
});
|
|
422
|
-
|
|
422
|
+
p14__namespace.log.success(
|
|
423
423
|
pc14__default.default.green(`Added: ${name.trim()}${optional ? "?" : ""}: ${finalType.trim()}`)
|
|
424
424
|
);
|
|
425
425
|
}
|
|
@@ -642,7 +642,7 @@ function installNpmPackages(projectRoot, packages, pm) {
|
|
|
642
642
|
installCmd = `npm install ${packages.join(" ")}`;
|
|
643
643
|
break;
|
|
644
644
|
}
|
|
645
|
-
|
|
645
|
+
p14__namespace.log.info(`Installing missing dependencies with ${manager}: ${pc14__default.default.cyan(packages.join(", "))}`);
|
|
646
646
|
child_process.execSync(installCmd, {
|
|
647
647
|
cwd: projectRoot,
|
|
648
648
|
stdio: "inherit"
|
|
@@ -2115,7 +2115,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2115
2115
|
}
|
|
2116
2116
|
if (!name) {
|
|
2117
2117
|
name = handleCancel(
|
|
2118
|
-
await
|
|
2118
|
+
await p14__namespace.text({
|
|
2119
2119
|
message: "What is the feature name?",
|
|
2120
2120
|
placeholder: "e.g. users, auth, orders, billing",
|
|
2121
2121
|
validate: (val) => {
|
|
@@ -2131,7 +2131,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2131
2131
|
let targetDirRel = defaultDir;
|
|
2132
2132
|
if (!flags.yes && !flags.target && !flags.dest) {
|
|
2133
2133
|
targetDirRel = handleCancel(
|
|
2134
|
-
await
|
|
2134
|
+
await p14__namespace.text({
|
|
2135
2135
|
message: "Target directory for the feature:",
|
|
2136
2136
|
initialValue: defaultDir,
|
|
2137
2137
|
defaultValue: defaultDir
|
|
@@ -2153,14 +2153,14 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2153
2153
|
const customUseCases = [];
|
|
2154
2154
|
if (!flags.yes) {
|
|
2155
2155
|
includeExpress = handleCancel(
|
|
2156
|
-
await
|
|
2156
|
+
await p14__namespace.confirm({
|
|
2157
2157
|
message: "Include Express Presentation layer (pxExpress routes & handlers)?",
|
|
2158
2158
|
initialValue: true
|
|
2159
2159
|
})
|
|
2160
2160
|
);
|
|
2161
2161
|
if (includeExpress) {
|
|
2162
2162
|
routePath = handleCancel(
|
|
2163
|
-
await
|
|
2163
|
+
await p14__namespace.text({
|
|
2164
2164
|
message: "Express route prefix:",
|
|
2165
2165
|
initialValue: `/${normalizedName}`,
|
|
2166
2166
|
defaultValue: `/${normalizedName}`
|
|
@@ -2168,14 +2168,14 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2168
2168
|
).trim();
|
|
2169
2169
|
}
|
|
2170
2170
|
includeDomain = handleCancel(
|
|
2171
|
-
await
|
|
2171
|
+
await p14__namespace.confirm({
|
|
2172
2172
|
message: "Include Domain Entity/Entities?",
|
|
2173
2173
|
initialValue: true
|
|
2174
2174
|
})
|
|
2175
2175
|
);
|
|
2176
2176
|
if (includeDomain) {
|
|
2177
2177
|
const domainInput = handleCancel(
|
|
2178
|
-
await
|
|
2178
|
+
await p14__namespace.text({
|
|
2179
2179
|
message: "Domain entity name(s) (comma-separated):",
|
|
2180
2180
|
initialValue: defaultEntity,
|
|
2181
2181
|
defaultValue: defaultEntity,
|
|
@@ -2194,21 +2194,21 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2194
2194
|
entityNames = [defaultEntity];
|
|
2195
2195
|
}
|
|
2196
2196
|
includeInterface = handleCancel(
|
|
2197
|
-
await
|
|
2197
|
+
await p14__namespace.confirm({
|
|
2198
2198
|
message: `Include Domain Repository interface(s) for ${entityNames.join(", ")}?`,
|
|
2199
2199
|
initialValue: true
|
|
2200
2200
|
})
|
|
2201
2201
|
);
|
|
2202
2202
|
if (includeInterface) {
|
|
2203
2203
|
includeInfra = handleCancel(
|
|
2204
|
-
await
|
|
2204
|
+
await p14__namespace.confirm({
|
|
2205
2205
|
message: `Include Infrastructure Stub implementation(s) for ${entityNames.join(", ")}?`,
|
|
2206
2206
|
initialValue: true
|
|
2207
2207
|
})
|
|
2208
2208
|
);
|
|
2209
2209
|
}
|
|
2210
2210
|
includeUseCase = handleCancel(
|
|
2211
|
-
await
|
|
2211
|
+
await p14__namespace.confirm({
|
|
2212
2212
|
message: "Include Domain Use Cases?",
|
|
2213
2213
|
initialValue: true
|
|
2214
2214
|
})
|
|
@@ -2222,7 +2222,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2222
2222
|
{ value: "delete", label: "Delete (Delete<Entity>)", hint: "DELETE /:id" }
|
|
2223
2223
|
];
|
|
2224
2224
|
crudOperations = handleCancel(
|
|
2225
|
-
await
|
|
2225
|
+
await p14__namespace.multiselect({
|
|
2226
2226
|
message: "Select standard CRUD use cases to generate:",
|
|
2227
2227
|
options: crudChoices,
|
|
2228
2228
|
initialValues: ["create", "read", "list", "update", "delete"],
|
|
@@ -2230,13 +2230,13 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2230
2230
|
})
|
|
2231
2231
|
);
|
|
2232
2232
|
includeTests = handleCancel(
|
|
2233
|
-
await
|
|
2233
|
+
await p14__namespace.confirm({
|
|
2234
2234
|
message: "Generate Vitest unit tests for use cases?",
|
|
2235
2235
|
initialValue: true
|
|
2236
2236
|
})
|
|
2237
2237
|
);
|
|
2238
2238
|
const wantCustom = handleCancel(
|
|
2239
|
-
await
|
|
2239
|
+
await p14__namespace.confirm({
|
|
2240
2240
|
message: "Do you want to add any custom use cases to this feature?",
|
|
2241
2241
|
initialValue: false
|
|
2242
2242
|
})
|
|
@@ -2246,7 +2246,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2246
2246
|
const availableIfaces = entityNames.map((e) => `I${e}Repository`);
|
|
2247
2247
|
while (addMore) {
|
|
2248
2248
|
const customName = handleCancel(
|
|
2249
|
-
await
|
|
2249
|
+
await p14__namespace.text({
|
|
2250
2250
|
message: "Custom Use Case name:",
|
|
2251
2251
|
placeholder: "e.g. ResetPassword, VerifyEmail, AssignRole",
|
|
2252
2252
|
validate: (v) => v && v.trim() ? void 0 : "Use Case name cannot be empty"
|
|
@@ -2256,7 +2256,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2256
2256
|
let selectedDeps = [];
|
|
2257
2257
|
if (availableIfaces.length > 0) {
|
|
2258
2258
|
selectedDeps = handleCancel(
|
|
2259
|
-
await
|
|
2259
|
+
await p14__namespace.multiselect({
|
|
2260
2260
|
message: `Select domain interfaces to inject into ${customUcName}:`,
|
|
2261
2261
|
options: availableIfaces.map((i) => ({ value: i, label: i })),
|
|
2262
2262
|
required: false
|
|
@@ -2265,7 +2265,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2265
2265
|
}
|
|
2266
2266
|
let customInputProps = [];
|
|
2267
2267
|
const hasInput = handleCancel(
|
|
2268
|
-
await
|
|
2268
|
+
await p14__namespace.confirm({
|
|
2269
2269
|
message: `Does ${customUcName} accept input arguments?`,
|
|
2270
2270
|
initialValue: true
|
|
2271
2271
|
})
|
|
@@ -2276,7 +2276,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2276
2276
|
}
|
|
2277
2277
|
let customOutputProps = [];
|
|
2278
2278
|
const hasCustomOutput = handleCancel(
|
|
2279
|
-
await
|
|
2279
|
+
await p14__namespace.confirm({
|
|
2280
2280
|
message: `Does ${customUcName} return custom output data?`,
|
|
2281
2281
|
initialValue: false
|
|
2282
2282
|
})
|
|
@@ -2286,7 +2286,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2286
2286
|
});
|
|
2287
2287
|
}
|
|
2288
2288
|
const customIncludeTest = handleCancel(
|
|
2289
|
-
await
|
|
2289
|
+
await p14__namespace.confirm({
|
|
2290
2290
|
message: `Generate Vitest unit test for ${customUcName}?`,
|
|
2291
2291
|
initialValue: true
|
|
2292
2292
|
})
|
|
@@ -2296,14 +2296,14 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2296
2296
|
let customHttpPath = `/${toKebabCase(customUcName)}`;
|
|
2297
2297
|
if (includeExpress) {
|
|
2298
2298
|
customCreateHttp = handleCancel(
|
|
2299
|
-
await
|
|
2299
|
+
await p14__namespace.confirm({
|
|
2300
2300
|
message: `Generate a matching ExpressRoute HTTP handler for ${customUcName}?`,
|
|
2301
2301
|
initialValue: true
|
|
2302
2302
|
})
|
|
2303
2303
|
);
|
|
2304
2304
|
if (customCreateHttp) {
|
|
2305
2305
|
customHttpMethod = handleCancel(
|
|
2306
|
-
await
|
|
2306
|
+
await p14__namespace.select({
|
|
2307
2307
|
message: "HTTP method for route:",
|
|
2308
2308
|
options: [
|
|
2309
2309
|
{ value: "post", label: "POST" },
|
|
@@ -2316,7 +2316,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2316
2316
|
})
|
|
2317
2317
|
);
|
|
2318
2318
|
customHttpPath = handleCancel(
|
|
2319
|
-
await
|
|
2319
|
+
await p14__namespace.text({
|
|
2320
2320
|
message: "Route subpath (relative to feature prefix):",
|
|
2321
2321
|
initialValue: `/${toKebabCase(customUcName)}`,
|
|
2322
2322
|
defaultValue: `/${toKebabCase(customUcName)}`
|
|
@@ -2337,7 +2337,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2337
2337
|
validationFields: customInputProps
|
|
2338
2338
|
});
|
|
2339
2339
|
addMore = handleCancel(
|
|
2340
|
-
await
|
|
2340
|
+
await p14__namespace.confirm({
|
|
2341
2341
|
message: "Add another custom use case?",
|
|
2342
2342
|
initialValue: false
|
|
2343
2343
|
})
|
|
@@ -2346,7 +2346,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2346
2346
|
}
|
|
2347
2347
|
}
|
|
2348
2348
|
includeDiProvider = handleCancel(
|
|
2349
|
-
await
|
|
2349
|
+
await p14__namespace.confirm({
|
|
2350
2350
|
message: "Generate / update feature DI provider (diProvider.ts)?",
|
|
2351
2351
|
initialValue: true
|
|
2352
2352
|
})
|
|
@@ -2358,7 +2358,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2358
2358
|
entityNames = [defaultEntity];
|
|
2359
2359
|
}
|
|
2360
2360
|
}
|
|
2361
|
-
const s =
|
|
2361
|
+
const s = p14__namespace.spinner();
|
|
2362
2362
|
s.start(`Generating feature '${pc14__default.default.cyan(normalizedName)}'...`);
|
|
2363
2363
|
const options = {
|
|
2364
2364
|
name: normalizedName,
|
|
@@ -2405,7 +2405,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2405
2405
|
}
|
|
2406
2406
|
s.stop("Feature scaffolded successfully!");
|
|
2407
2407
|
printGeneratedFiles(files, options.dryRun);
|
|
2408
|
-
|
|
2408
|
+
p14__namespace.outro(
|
|
2409
2409
|
pc14__default.default.green(
|
|
2410
2410
|
`\u2713 Feature '${normalizedName}' initialized in ${path2__default.default.relative(projectRoot, targetDir)} (uncommitted, unregistered)`
|
|
2411
2411
|
)
|
|
@@ -2520,7 +2520,7 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
|
|
|
2520
2520
|
}
|
|
2521
2521
|
if (!name) {
|
|
2522
2522
|
name = handleCancel(
|
|
2523
|
-
await
|
|
2523
|
+
await p14__namespace.text({
|
|
2524
2524
|
message: "What is the shared module name?",
|
|
2525
2525
|
placeholder: "e.g. hasher, time, uuid, cache, logger",
|
|
2526
2526
|
validate: (val) => {
|
|
@@ -2536,7 +2536,7 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
|
|
|
2536
2536
|
let targetDirRel = defaultDir;
|
|
2537
2537
|
if (!flags.yes && !flags.target && !flags.dest) {
|
|
2538
2538
|
targetDirRel = handleCancel(
|
|
2539
|
-
await
|
|
2539
|
+
await p14__namespace.text({
|
|
2540
2540
|
message: "Target directory for the shared module:",
|
|
2541
2541
|
initialValue: defaultDir,
|
|
2542
2542
|
defaultValue: defaultDir
|
|
@@ -2548,20 +2548,20 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
|
|
|
2548
2548
|
let includeStub = true;
|
|
2549
2549
|
if (!flags.yes) {
|
|
2550
2550
|
description = handleCancel(
|
|
2551
|
-
await
|
|
2551
|
+
await p14__namespace.text({
|
|
2552
2552
|
message: "Module description (optional):",
|
|
2553
2553
|
placeholder: "e.g. In-memory caching and Redis port abstraction",
|
|
2554
2554
|
initialValue: ""
|
|
2555
2555
|
})
|
|
2556
2556
|
).trim();
|
|
2557
2557
|
includeStub = handleCancel(
|
|
2558
|
-
await
|
|
2558
|
+
await p14__namespace.confirm({
|
|
2559
2559
|
message: "Include stub implementation in infrastructure/?",
|
|
2560
2560
|
initialValue: true
|
|
2561
2561
|
})
|
|
2562
2562
|
);
|
|
2563
2563
|
}
|
|
2564
|
-
const s =
|
|
2564
|
+
const s = p14__namespace.spinner();
|
|
2565
2565
|
s.start(`Generating shared module '${pc14__default.default.cyan(normalizedName)}'...`);
|
|
2566
2566
|
const files = generateShared({
|
|
2567
2567
|
name: normalizedName,
|
|
@@ -2575,7 +2575,7 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
|
|
|
2575
2575
|
});
|
|
2576
2576
|
s.stop("Shared module generated successfully!");
|
|
2577
2577
|
printGeneratedFiles(files, Boolean(flags.dryRun));
|
|
2578
|
-
|
|
2578
|
+
p14__namespace.outro(
|
|
2579
2579
|
pc14__default.default.green(
|
|
2580
2580
|
`\u2713 Shared module '${normalizedName}' initialized in ${path2__default.default.relative(projectRoot, targetDir)} (uncommitted, unregistered)`
|
|
2581
2581
|
)
|
|
@@ -2590,14 +2590,14 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
|
|
|
2590
2590
|
const featureOptions = existingFeatures.map((f) => ({ value: f, label: f }));
|
|
2591
2591
|
featureOptions.push({ value: "__custom__", label: "\u270F\uFE0F Enter custom feature name..." });
|
|
2592
2592
|
const selected = handleCancel(
|
|
2593
|
-
await
|
|
2593
|
+
await p14__namespace.select({
|
|
2594
2594
|
message: "Select target feature:",
|
|
2595
2595
|
options: featureOptions
|
|
2596
2596
|
})
|
|
2597
2597
|
);
|
|
2598
2598
|
if (selected === "__custom__") {
|
|
2599
2599
|
feature = handleCancel(
|
|
2600
|
-
await
|
|
2600
|
+
await p14__namespace.text({
|
|
2601
2601
|
message: "Enter feature name:",
|
|
2602
2602
|
validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
|
|
2603
2603
|
})
|
|
@@ -2607,7 +2607,7 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
|
|
|
2607
2607
|
}
|
|
2608
2608
|
} else {
|
|
2609
2609
|
feature = handleCancel(
|
|
2610
|
-
await
|
|
2610
|
+
await p14__namespace.text({
|
|
2611
2611
|
message: "Enter target feature name:",
|
|
2612
2612
|
validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
|
|
2613
2613
|
})
|
|
@@ -2618,7 +2618,7 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
|
|
|
2618
2618
|
let name = useCaseNameArg?.trim();
|
|
2619
2619
|
if (!name) {
|
|
2620
2620
|
name = handleCancel(
|
|
2621
|
-
await
|
|
2621
|
+
await p14__namespace.text({
|
|
2622
2622
|
message: "Use Case name:",
|
|
2623
2623
|
placeholder: "e.g. CreateUser, GetUser, CancelOrder",
|
|
2624
2624
|
validate: (v) => v && v.trim() ? void 0 : "Use Case name cannot be empty"
|
|
@@ -2634,7 +2634,7 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
|
|
|
2634
2634
|
label: i.name
|
|
2635
2635
|
}));
|
|
2636
2636
|
selectedDeps = handleCancel(
|
|
2637
|
-
await
|
|
2637
|
+
await p14__namespace.multiselect({
|
|
2638
2638
|
message: "Select domain interfaces to inject into use case:",
|
|
2639
2639
|
options: multiOptions,
|
|
2640
2640
|
required: false
|
|
@@ -2649,7 +2649,7 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
|
|
|
2649
2649
|
let httpPath = "/";
|
|
2650
2650
|
if (!flags.yes) {
|
|
2651
2651
|
const hasInput = handleCancel(
|
|
2652
|
-
await
|
|
2652
|
+
await p14__namespace.confirm({
|
|
2653
2653
|
message: "Does this use case accept input arguments?",
|
|
2654
2654
|
initialValue: true
|
|
2655
2655
|
})
|
|
@@ -2659,7 +2659,7 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
|
|
|
2659
2659
|
});
|
|
2660
2660
|
}
|
|
2661
2661
|
const hasCustomOutput = handleCancel(
|
|
2662
|
-
await
|
|
2662
|
+
await p14__namespace.confirm({
|
|
2663
2663
|
message: "Does this use case return custom output data?",
|
|
2664
2664
|
initialValue: false
|
|
2665
2665
|
})
|
|
@@ -2669,20 +2669,20 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
|
|
|
2669
2669
|
});
|
|
2670
2670
|
}
|
|
2671
2671
|
includeTest = handleCancel(
|
|
2672
|
-
await
|
|
2672
|
+
await p14__namespace.confirm({
|
|
2673
2673
|
message: "Generate Vitest unit test skeleton (.test.ts)?",
|
|
2674
2674
|
initialValue: true
|
|
2675
2675
|
})
|
|
2676
2676
|
);
|
|
2677
2677
|
createHttp = handleCancel(
|
|
2678
|
-
await
|
|
2678
|
+
await p14__namespace.confirm({
|
|
2679
2679
|
message: "Generate a matching ExpressRoute HTTP handler?",
|
|
2680
2680
|
initialValue: false
|
|
2681
2681
|
})
|
|
2682
2682
|
);
|
|
2683
2683
|
if (createHttp) {
|
|
2684
2684
|
httpMethod = handleCancel(
|
|
2685
|
-
await
|
|
2685
|
+
await p14__namespace.select({
|
|
2686
2686
|
message: "HTTP method for route:",
|
|
2687
2687
|
options: [
|
|
2688
2688
|
{ value: "post", label: "POST" },
|
|
@@ -2695,7 +2695,7 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
|
|
|
2695
2695
|
})
|
|
2696
2696
|
);
|
|
2697
2697
|
httpPath = handleCancel(
|
|
2698
|
-
await
|
|
2698
|
+
await p14__namespace.text({
|
|
2699
2699
|
message: "Route subpath (relative to feature prefix):",
|
|
2700
2700
|
initialValue: "/",
|
|
2701
2701
|
defaultValue: "/"
|
|
@@ -2703,7 +2703,7 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
|
|
|
2703
2703
|
).trim();
|
|
2704
2704
|
}
|
|
2705
2705
|
}
|
|
2706
|
-
const s =
|
|
2706
|
+
const s = p14__namespace.spinner();
|
|
2707
2707
|
s.start(`Generating use case '${pc14__default.default.cyan(ucName)}'...`);
|
|
2708
2708
|
const options = {
|
|
2709
2709
|
name: ucName,
|
|
@@ -2736,7 +2736,7 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
|
|
|
2736
2736
|
}
|
|
2737
2737
|
s.stop("Use case generated successfully!");
|
|
2738
2738
|
printGeneratedFiles(files, options.dryRun);
|
|
2739
|
-
|
|
2739
|
+
p14__namespace.outro(pc14__default.default.green(`Use case '${ucName}' created in feature '${feature}'!`));
|
|
2740
2740
|
}
|
|
2741
2741
|
async function runDomainCommand(domainNameArg, flags = {}) {
|
|
2742
2742
|
const projectRoot = findProjectRoot();
|
|
@@ -2747,14 +2747,14 @@ async function runDomainCommand(domainNameArg, flags = {}) {
|
|
|
2747
2747
|
const featureOptions = existingFeatures.map((f) => ({ value: f, label: f }));
|
|
2748
2748
|
featureOptions.push({ value: "__custom__", label: "\u270F\uFE0F Enter custom feature name..." });
|
|
2749
2749
|
const selected = handleCancel(
|
|
2750
|
-
await
|
|
2750
|
+
await p14__namespace.select({
|
|
2751
2751
|
message: "Select target feature:",
|
|
2752
2752
|
options: featureOptions
|
|
2753
2753
|
})
|
|
2754
2754
|
);
|
|
2755
2755
|
if (selected === "__custom__") {
|
|
2756
2756
|
feature = handleCancel(
|
|
2757
|
-
await
|
|
2757
|
+
await p14__namespace.text({
|
|
2758
2758
|
message: "Enter feature name:",
|
|
2759
2759
|
validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
|
|
2760
2760
|
})
|
|
@@ -2764,7 +2764,7 @@ async function runDomainCommand(domainNameArg, flags = {}) {
|
|
|
2764
2764
|
}
|
|
2765
2765
|
} else {
|
|
2766
2766
|
feature = handleCancel(
|
|
2767
|
-
await
|
|
2767
|
+
await p14__namespace.text({
|
|
2768
2768
|
message: "Enter target feature name:",
|
|
2769
2769
|
validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
|
|
2770
2770
|
})
|
|
@@ -2775,7 +2775,7 @@ async function runDomainCommand(domainNameArg, flags = {}) {
|
|
|
2775
2775
|
let name = domainNameArg?.trim();
|
|
2776
2776
|
if (!name) {
|
|
2777
2777
|
name = handleCancel(
|
|
2778
|
-
await
|
|
2778
|
+
await p14__namespace.text({
|
|
2779
2779
|
message: "Domain model / entity name:",
|
|
2780
2780
|
placeholder: "e.g. User, Order, Product, Address",
|
|
2781
2781
|
validate: (v) => v && v.trim() ? void 0 : "Domain name cannot be empty"
|
|
@@ -2787,7 +2787,7 @@ async function runDomainCommand(domainNameArg, flags = {}) {
|
|
|
2787
2787
|
let properties = [];
|
|
2788
2788
|
if (!flags.yes) {
|
|
2789
2789
|
kind = handleCancel(
|
|
2790
|
-
await
|
|
2790
|
+
await p14__namespace.select({
|
|
2791
2791
|
message: "Select domain model type:",
|
|
2792
2792
|
options: [
|
|
2793
2793
|
{ value: "interface", label: "TypeScript Interface (pure data structure)" },
|
|
@@ -2806,7 +2806,7 @@ async function runDomainCommand(domainNameArg, flags = {}) {
|
|
|
2806
2806
|
defaults: kind === "valueObject" ? [{ name: "value", type: "string" }] : defaultProps
|
|
2807
2807
|
});
|
|
2808
2808
|
}
|
|
2809
|
-
const s =
|
|
2809
|
+
const s = p14__namespace.spinner();
|
|
2810
2810
|
s.start(`Generating domain model '${pc14__default.default.cyan(entityName)}'...`);
|
|
2811
2811
|
const options = {
|
|
2812
2812
|
name: entityName,
|
|
@@ -2820,7 +2820,7 @@ async function runDomainCommand(domainNameArg, flags = {}) {
|
|
|
2820
2820
|
const file = generateDomain(options);
|
|
2821
2821
|
s.stop("Domain model generated successfully!");
|
|
2822
2822
|
printGeneratedFiles([file], options.dryRun);
|
|
2823
|
-
|
|
2823
|
+
p14__namespace.outro(pc14__default.default.green(`Domain model '${entityName}' created in feature '${feature}'!`));
|
|
2824
2824
|
}
|
|
2825
2825
|
async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
2826
2826
|
const projectRoot = findProjectRoot();
|
|
@@ -2829,7 +2829,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2829
2829
|
let feature = flags.feature?.trim();
|
|
2830
2830
|
if (!flags.yes && !flags.global && !flags.feature) {
|
|
2831
2831
|
scope = handleCancel(
|
|
2832
|
-
await
|
|
2832
|
+
await p14__namespace.select({
|
|
2833
2833
|
message: "Where should this infrastructure implementation be placed?",
|
|
2834
2834
|
options: [
|
|
2835
2835
|
{ value: "feature", label: "Feature-level (features/<feature>/infrastructure)" },
|
|
@@ -2844,14 +2844,14 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2844
2844
|
const featureOptions = existingFeatures.map((f) => ({ value: f, label: f }));
|
|
2845
2845
|
featureOptions.push({ value: "__custom__", label: "\u270F\uFE0F Enter custom feature name..." });
|
|
2846
2846
|
const selected = handleCancel(
|
|
2847
|
-
await
|
|
2847
|
+
await p14__namespace.select({
|
|
2848
2848
|
message: "Select target feature:",
|
|
2849
2849
|
options: featureOptions
|
|
2850
2850
|
})
|
|
2851
2851
|
);
|
|
2852
2852
|
if (selected === "__custom__") {
|
|
2853
2853
|
feature = handleCancel(
|
|
2854
|
-
await
|
|
2854
|
+
await p14__namespace.text({
|
|
2855
2855
|
message: "Enter feature name:",
|
|
2856
2856
|
validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
|
|
2857
2857
|
})
|
|
@@ -2861,7 +2861,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2861
2861
|
}
|
|
2862
2862
|
} else {
|
|
2863
2863
|
feature = handleCancel(
|
|
2864
|
-
await
|
|
2864
|
+
await p14__namespace.text({
|
|
2865
2865
|
message: "Enter target feature name:",
|
|
2866
2866
|
validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
|
|
2867
2867
|
})
|
|
@@ -2874,7 +2874,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2874
2874
|
let name = classNameArg?.trim();
|
|
2875
2875
|
if (!name) {
|
|
2876
2876
|
name = handleCancel(
|
|
2877
|
-
await
|
|
2877
|
+
await p14__namespace.text({
|
|
2878
2878
|
message: "Infrastructure class name:",
|
|
2879
2879
|
placeholder: "e.g. StubUserRepository, PostgresUserRepository, S3FileStorage",
|
|
2880
2880
|
validate: (v) => v && v.trim() ? void 0 : "Class name cannot be empty"
|
|
@@ -2893,7 +2893,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2893
2893
|
(i) => className.toLowerCase().includes(removeInterfacePrefix(i.name).toLowerCase())
|
|
2894
2894
|
);
|
|
2895
2895
|
const ifaceChoice = handleCancel(
|
|
2896
|
-
await
|
|
2896
|
+
await p14__namespace.select({
|
|
2897
2897
|
message: "Does this class implement a domain interface or abstract class?",
|
|
2898
2898
|
options: [
|
|
2899
2899
|
...interfaces.map((i) => ({ value: i.name, label: i.name })),
|
|
@@ -2905,7 +2905,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2905
2905
|
);
|
|
2906
2906
|
if (ifaceChoice === "__custom__") {
|
|
2907
2907
|
implementsInterface = handleCancel(
|
|
2908
|
-
await
|
|
2908
|
+
await p14__namespace.text({
|
|
2909
2909
|
message: "Enter interface or abstract class name:",
|
|
2910
2910
|
placeholder: "e.g. IUserRepository, BaseStorageAdapter",
|
|
2911
2911
|
validate: (v) => v && v.trim() ? void 0 : "Name cannot be empty"
|
|
@@ -2916,14 +2916,14 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2916
2916
|
}
|
|
2917
2917
|
} else {
|
|
2918
2918
|
const wantImpl = handleCancel(
|
|
2919
|
-
await
|
|
2919
|
+
await p14__namespace.confirm({
|
|
2920
2920
|
message: "Does this class implement a domain interface or abstract class?",
|
|
2921
2921
|
initialValue: false
|
|
2922
2922
|
})
|
|
2923
2923
|
);
|
|
2924
2924
|
if (wantImpl) {
|
|
2925
2925
|
implementsInterface = handleCancel(
|
|
2926
|
-
await
|
|
2926
|
+
await p14__namespace.text({
|
|
2927
2927
|
message: "Enter interface or abstract class name:",
|
|
2928
2928
|
placeholder: "e.g. IUserRepository, BaseStorageAdapter",
|
|
2929
2929
|
validate: (v) => v && v.trim() ? void 0 : "Name cannot be empty"
|
|
@@ -2943,7 +2943,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2943
2943
|
const allInterfaces = listDomainInterfaces(projectRoot);
|
|
2944
2944
|
if (allInterfaces.length > 0) {
|
|
2945
2945
|
const ifaceChoice = handleCancel(
|
|
2946
|
-
await
|
|
2946
|
+
await p14__namespace.select({
|
|
2947
2947
|
message: "Does this class implement an interface or abstract class?",
|
|
2948
2948
|
options: [
|
|
2949
2949
|
...allInterfaces.map((i) => ({ value: i.name, label: `${i.name} (${i.feature})` })),
|
|
@@ -2955,7 +2955,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2955
2955
|
);
|
|
2956
2956
|
if (ifaceChoice === "__custom__") {
|
|
2957
2957
|
implementsInterface = handleCancel(
|
|
2958
|
-
await
|
|
2958
|
+
await p14__namespace.text({
|
|
2959
2959
|
message: "Enter interface or abstract class name:",
|
|
2960
2960
|
placeholder: "e.g. IAuthRepository",
|
|
2961
2961
|
validate: (v) => v && v.trim() ? void 0 : "Name cannot be empty"
|
|
@@ -2968,7 +2968,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2968
2968
|
}
|
|
2969
2969
|
if (!flags.yes && !flags.kind) {
|
|
2970
2970
|
kind = handleCancel(
|
|
2971
|
-
await
|
|
2971
|
+
await p14__namespace.select({
|
|
2972
2972
|
message: "Select implementation kind:",
|
|
2973
2973
|
options: [
|
|
2974
2974
|
{ value: "stub", label: "In-Memory Stub (with in-memory store and test helper methods)" },
|
|
@@ -2979,7 +2979,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2979
2979
|
);
|
|
2980
2980
|
if (scope === "feature" && feature && implementsInterface) {
|
|
2981
2981
|
registerInProvider = handleCancel(
|
|
2982
|
-
await
|
|
2982
|
+
await p14__namespace.confirm({
|
|
2983
2983
|
message: "Register this implementation in feature diProvider.ts?",
|
|
2984
2984
|
initialValue: true
|
|
2985
2985
|
})
|
|
@@ -2988,7 +2988,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2988
2988
|
} else if (flags.yes && scope === "feature" && feature && implementsInterface) {
|
|
2989
2989
|
registerInProvider = !flags.noProvider;
|
|
2990
2990
|
}
|
|
2991
|
-
const s =
|
|
2991
|
+
const s = p14__namespace.spinner();
|
|
2992
2992
|
s.start(`Generating infrastructure class '${pc14__default.default.cyan(className)}'...`);
|
|
2993
2993
|
const files = [];
|
|
2994
2994
|
const options = {
|
|
@@ -3024,7 +3024,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
3024
3024
|
}
|
|
3025
3025
|
s.stop("Infrastructure class generated successfully!");
|
|
3026
3026
|
printGeneratedFiles(files, options.dryRun);
|
|
3027
|
-
|
|
3027
|
+
p14__namespace.outro(pc14__default.default.green(`Infrastructure class '${className}' created!`));
|
|
3028
3028
|
}
|
|
3029
3029
|
async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
3030
3030
|
const projectRoot = findProjectRoot();
|
|
@@ -3035,14 +3035,14 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
|
3035
3035
|
const featureOptions = existingFeatures.map((f) => ({ value: f, label: f }));
|
|
3036
3036
|
featureOptions.push({ value: "__custom__", label: "\u270F\uFE0F Enter custom feature name..." });
|
|
3037
3037
|
const selected = handleCancel(
|
|
3038
|
-
await
|
|
3038
|
+
await p14__namespace.select({
|
|
3039
3039
|
message: "Select target feature:",
|
|
3040
3040
|
options: featureOptions
|
|
3041
3041
|
})
|
|
3042
3042
|
);
|
|
3043
3043
|
if (selected === "__custom__") {
|
|
3044
3044
|
feature = handleCancel(
|
|
3045
|
-
await
|
|
3045
|
+
await p14__namespace.text({
|
|
3046
3046
|
message: "Enter feature name:",
|
|
3047
3047
|
validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
|
|
3048
3048
|
})
|
|
@@ -3052,7 +3052,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
|
3052
3052
|
}
|
|
3053
3053
|
} else {
|
|
3054
3054
|
feature = handleCancel(
|
|
3055
|
-
await
|
|
3055
|
+
await p14__namespace.text({
|
|
3056
3056
|
message: "Enter target feature name:",
|
|
3057
3057
|
validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
|
|
3058
3058
|
})
|
|
@@ -3063,7 +3063,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
|
3063
3063
|
let name = interfaceNameArg?.trim();
|
|
3064
3064
|
if (!name) {
|
|
3065
3065
|
name = handleCancel(
|
|
3066
|
-
await
|
|
3066
|
+
await p14__namespace.text({
|
|
3067
3067
|
message: "Domain interface name:",
|
|
3068
3068
|
placeholder: "e.g. IUserRepository, IPaymentService",
|
|
3069
3069
|
validate: (v) => v && v.trim() ? void 0 : "Interface name cannot be empty"
|
|
@@ -3081,7 +3081,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
|
3081
3081
|
if (!flags.yes) {
|
|
3082
3082
|
if (existingEntities.length > 0) {
|
|
3083
3083
|
const selectedEntity = handleCancel(
|
|
3084
|
-
await
|
|
3084
|
+
await p14__namespace.select({
|
|
3085
3085
|
message: "Select domain entity associated with this interface:",
|
|
3086
3086
|
options: [
|
|
3087
3087
|
...existingEntities.map((e) => ({ value: e.name, label: e.name })),
|
|
@@ -3092,7 +3092,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
|
3092
3092
|
);
|
|
3093
3093
|
if (selectedEntity === "__custom__") {
|
|
3094
3094
|
entityName = handleCancel(
|
|
3095
|
-
await
|
|
3095
|
+
await p14__namespace.text({
|
|
3096
3096
|
message: "Enter entity name:",
|
|
3097
3097
|
defaultValue: removeInterfacePrefix(ifaceName).replace(/Repository$|Service$/, "")
|
|
3098
3098
|
})
|
|
@@ -3102,7 +3102,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
|
3102
3102
|
}
|
|
3103
3103
|
}
|
|
3104
3104
|
kind = handleCancel(
|
|
3105
|
-
await
|
|
3105
|
+
await p14__namespace.select({
|
|
3106
3106
|
message: "Interface definition style:",
|
|
3107
3107
|
options: [
|
|
3108
3108
|
{ value: "abstractClass", label: "Abstract Class (Recommended - acts as DI token & type)" },
|
|
@@ -3112,7 +3112,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
|
3112
3112
|
})
|
|
3113
3113
|
);
|
|
3114
3114
|
methodsPreset = handleCancel(
|
|
3115
|
-
await
|
|
3115
|
+
await p14__namespace.select({
|
|
3116
3116
|
message: "Method signature preset:",
|
|
3117
3117
|
options: [
|
|
3118
3118
|
{ value: "crud", label: "Standard CRUD (GetById, List, Create, Update, Delete)" },
|
|
@@ -3122,21 +3122,21 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
|
3122
3122
|
})
|
|
3123
3123
|
);
|
|
3124
3124
|
generateStub = handleCancel(
|
|
3125
|
-
await
|
|
3125
|
+
await p14__namespace.confirm({
|
|
3126
3126
|
message: "Auto-generate Infrastructure Stub implementation?",
|
|
3127
3127
|
initialValue: true
|
|
3128
3128
|
})
|
|
3129
3129
|
);
|
|
3130
3130
|
if (generateStub) {
|
|
3131
3131
|
registerInProvider = handleCancel(
|
|
3132
|
-
await
|
|
3132
|
+
await p14__namespace.confirm({
|
|
3133
3133
|
message: "Auto-register interface & stub in feature diProvider.ts?",
|
|
3134
3134
|
initialValue: true
|
|
3135
3135
|
})
|
|
3136
3136
|
);
|
|
3137
3137
|
}
|
|
3138
3138
|
}
|
|
3139
|
-
const s =
|
|
3139
|
+
const s = p14__namespace.spinner();
|
|
3140
3140
|
s.start(`Generating interface '${pc14__default.default.cyan(ifaceName)}'...`);
|
|
3141
3141
|
const files = [];
|
|
3142
3142
|
const options = {
|
|
@@ -3186,7 +3186,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
|
3186
3186
|
}
|
|
3187
3187
|
s.stop("Interface generated successfully!");
|
|
3188
3188
|
printGeneratedFiles(files, options.dryRun);
|
|
3189
|
-
|
|
3189
|
+
p14__namespace.outro(pc14__default.default.green(`Interface '${ifaceName}' created in feature '${feature}'!`));
|
|
3190
3190
|
}
|
|
3191
3191
|
async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
|
|
3192
3192
|
const projectRoot = findProjectRoot();
|
|
@@ -3197,14 +3197,14 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
|
|
|
3197
3197
|
const featureOptions = existingFeatures.map((f) => ({ value: f, label: f }));
|
|
3198
3198
|
featureOptions.push({ value: "__custom__", label: "\u270F\uFE0F Enter custom feature name..." });
|
|
3199
3199
|
const selected = handleCancel(
|
|
3200
|
-
await
|
|
3200
|
+
await p14__namespace.select({
|
|
3201
3201
|
message: "Select target feature:",
|
|
3202
3202
|
options: featureOptions
|
|
3203
3203
|
})
|
|
3204
3204
|
);
|
|
3205
3205
|
if (selected === "__custom__") {
|
|
3206
3206
|
feature = handleCancel(
|
|
3207
|
-
await
|
|
3207
|
+
await p14__namespace.text({
|
|
3208
3208
|
message: "Enter feature name:",
|
|
3209
3209
|
validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
|
|
3210
3210
|
})
|
|
@@ -3214,7 +3214,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
|
|
|
3214
3214
|
}
|
|
3215
3215
|
} else {
|
|
3216
3216
|
feature = handleCancel(
|
|
3217
|
-
await
|
|
3217
|
+
await p14__namespace.text({
|
|
3218
3218
|
message: "Enter target feature name:",
|
|
3219
3219
|
validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
|
|
3220
3220
|
})
|
|
@@ -3225,7 +3225,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
|
|
|
3225
3225
|
let name = handlerNameArg?.trim();
|
|
3226
3226
|
if (!name) {
|
|
3227
3227
|
name = handleCancel(
|
|
3228
|
-
await
|
|
3228
|
+
await p14__namespace.text({
|
|
3229
3229
|
message: "HTTP Route Handler class name:",
|
|
3230
3230
|
placeholder: "e.g. CreateUserHttp, GetUserHttp, HealthHttp",
|
|
3231
3231
|
validate: (v) => v && v.trim() ? void 0 : "Handler name cannot be empty"
|
|
@@ -3244,7 +3244,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
|
|
|
3244
3244
|
let validationFields = [];
|
|
3245
3245
|
if (!flags.yes) {
|
|
3246
3246
|
method = handleCancel(
|
|
3247
|
-
await
|
|
3247
|
+
await p14__namespace.select({
|
|
3248
3248
|
message: "HTTP Method:",
|
|
3249
3249
|
options: [
|
|
3250
3250
|
{ value: "get", label: "GET" },
|
|
@@ -3258,7 +3258,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
|
|
|
3258
3258
|
);
|
|
3259
3259
|
const defaultPath = method === "get" ? "/" : "/";
|
|
3260
3260
|
subPath = handleCancel(
|
|
3261
|
-
await
|
|
3261
|
+
await p14__namespace.text({
|
|
3262
3262
|
message: "Route subpath (relative to feature prefix):",
|
|
3263
3263
|
initialValue: defaultPath,
|
|
3264
3264
|
defaultValue: defaultPath
|
|
@@ -3269,7 +3269,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
|
|
|
3269
3269
|
const ucOptions = useCases.map((u) => ({ value: u.name, label: u.name }));
|
|
3270
3270
|
ucOptions.push({ value: "__none__", label: "None / Standalone Handler" });
|
|
3271
3271
|
const chosenUc = handleCancel(
|
|
3272
|
-
await
|
|
3272
|
+
await p14__namespace.select({
|
|
3273
3273
|
message: "Connect this handler to a domain Use Case?",
|
|
3274
3274
|
options: ucOptions,
|
|
3275
3275
|
initialValue: ucOptions[0]?.value
|
|
@@ -3280,7 +3280,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
|
|
|
3280
3280
|
}
|
|
3281
3281
|
}
|
|
3282
3282
|
includeValidation = handleCancel(
|
|
3283
|
-
await
|
|
3283
|
+
await p14__namespace.confirm({
|
|
3284
3284
|
message: "Include Zod inbound request validation?",
|
|
3285
3285
|
initialValue: method !== "delete"
|
|
3286
3286
|
})
|
|
@@ -3288,7 +3288,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
|
|
|
3288
3288
|
if (includeValidation) {
|
|
3289
3289
|
const defaultSource = method === "get" ? "query" : "body";
|
|
3290
3290
|
validationSource = handleCancel(
|
|
3291
|
-
await
|
|
3291
|
+
await p14__namespace.select({
|
|
3292
3292
|
message: "Validation data source:",
|
|
3293
3293
|
options: [
|
|
3294
3294
|
{ value: "body", label: "req.body (for POST / PUT / PATCH payloads)" },
|
|
@@ -3302,7 +3302,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
|
|
|
3302
3302
|
});
|
|
3303
3303
|
}
|
|
3304
3304
|
}
|
|
3305
|
-
const s =
|
|
3305
|
+
const s = p14__namespace.spinner();
|
|
3306
3306
|
s.start(`Generating HTTP handler '${pc14__default.default.cyan(className)}'...`);
|
|
3307
3307
|
const options = {
|
|
3308
3308
|
name: className,
|
|
@@ -3321,7 +3321,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
|
|
|
3321
3321
|
const files = generateHttpHandler(options);
|
|
3322
3322
|
s.stop("HTTP handler generated successfully!");
|
|
3323
3323
|
printGeneratedFiles(files, options.dryRun);
|
|
3324
|
-
|
|
3324
|
+
p14__namespace.outro(pc14__default.default.green(`HTTP handler '${className}' created in feature '${feature}'!`));
|
|
3325
3325
|
}
|
|
3326
3326
|
function generateInjectableCode(className, dependencies = [], methods = [], implementsInterface) {
|
|
3327
3327
|
const formattedDeps = dependencies.map((dep) => ({
|
|
@@ -3401,7 +3401,7 @@ async function runInjectableCommand(classNameArg, flags = {}) {
|
|
|
3401
3401
|
let name = classNameArg?.trim();
|
|
3402
3402
|
if (!name) {
|
|
3403
3403
|
name = handleCancel(
|
|
3404
|
-
await
|
|
3404
|
+
await p14__namespace.text({
|
|
3405
3405
|
message: "Injectable class name:",
|
|
3406
3406
|
placeholder: "e.g. PasswordHasher, TokenService, UserTransformer",
|
|
3407
3407
|
validate: (v) => v && v.trim() ? void 0 : "Class name cannot be empty"
|
|
@@ -3414,7 +3414,7 @@ async function runInjectableCommand(classNameArg, flags = {}) {
|
|
|
3414
3414
|
let customPath;
|
|
3415
3415
|
if (!flags.yes) {
|
|
3416
3416
|
location = handleCancel(
|
|
3417
|
-
await
|
|
3417
|
+
await p14__namespace.select({
|
|
3418
3418
|
message: "Select target architectural location:",
|
|
3419
3419
|
options: [
|
|
3420
3420
|
{ value: "feature-service", label: "Feature Service (features/<feature>/services/)" },
|
|
@@ -3432,14 +3432,14 @@ async function runInjectableCommand(classNameArg, flags = {}) {
|
|
|
3432
3432
|
const featureOptions = existingFeatures.map((f) => ({ value: f, label: f }));
|
|
3433
3433
|
featureOptions.push({ value: "__custom__", label: "\u270F\uFE0F Enter custom feature name..." });
|
|
3434
3434
|
const selected = handleCancel(
|
|
3435
|
-
await
|
|
3435
|
+
await p14__namespace.select({
|
|
3436
3436
|
message: "Select target feature:",
|
|
3437
3437
|
options: featureOptions
|
|
3438
3438
|
})
|
|
3439
3439
|
);
|
|
3440
3440
|
if (selected === "__custom__") {
|
|
3441
3441
|
feature = handleCancel(
|
|
3442
|
-
await
|
|
3442
|
+
await p14__namespace.text({
|
|
3443
3443
|
message: "Enter feature name:",
|
|
3444
3444
|
validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
|
|
3445
3445
|
})
|
|
@@ -3449,7 +3449,7 @@ async function runInjectableCommand(classNameArg, flags = {}) {
|
|
|
3449
3449
|
}
|
|
3450
3450
|
} else {
|
|
3451
3451
|
feature = handleCancel(
|
|
3452
|
-
await
|
|
3452
|
+
await p14__namespace.text({
|
|
3453
3453
|
message: "Enter target feature name:",
|
|
3454
3454
|
validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
|
|
3455
3455
|
})
|
|
@@ -3459,7 +3459,7 @@ async function runInjectableCommand(classNameArg, flags = {}) {
|
|
|
3459
3459
|
feature = toCamelCase(feature);
|
|
3460
3460
|
} else if (location === "custom") {
|
|
3461
3461
|
customPath = handleCancel(
|
|
3462
|
-
await
|
|
3462
|
+
await p14__namespace.text({
|
|
3463
3463
|
message: "Enter destination directory path:",
|
|
3464
3464
|
placeholder: "e.g. src/services or lib/utils",
|
|
3465
3465
|
validate: (v) => v && v.trim() ? void 0 : "Path cannot be empty"
|
|
@@ -3470,13 +3470,13 @@ async function runInjectableCommand(classNameArg, flags = {}) {
|
|
|
3470
3470
|
let generateInterface2 = false;
|
|
3471
3471
|
if (!flags.yes) {
|
|
3472
3472
|
generateInterface2 = handleCancel(
|
|
3473
|
-
await
|
|
3473
|
+
await p14__namespace.confirm({
|
|
3474
3474
|
message: `Generate abstract class interface (I${className}) as runtime DI token?`,
|
|
3475
3475
|
initialValue: false
|
|
3476
3476
|
})
|
|
3477
3477
|
);
|
|
3478
3478
|
}
|
|
3479
|
-
const s =
|
|
3479
|
+
const s = p14__namespace.spinner();
|
|
3480
3480
|
s.start(`Generating injectable '${pc14__default.default.cyan(className)}'...`);
|
|
3481
3481
|
const options = {
|
|
3482
3482
|
name: className,
|
|
@@ -3491,12 +3491,12 @@ async function runInjectableCommand(classNameArg, flags = {}) {
|
|
|
3491
3491
|
const files = generateInjectable(options);
|
|
3492
3492
|
s.stop("Injectable class generated successfully!");
|
|
3493
3493
|
printGeneratedFiles(files, options.dryRun);
|
|
3494
|
-
|
|
3494
|
+
p14__namespace.outro(pc14__default.default.green(`Injectable '${className}' created successfully!`));
|
|
3495
3495
|
}
|
|
3496
3496
|
async function runInteractiveMenu(flags = {}) {
|
|
3497
3497
|
printBanner();
|
|
3498
3498
|
const choice = handleCancel(
|
|
3499
|
-
await
|
|
3499
|
+
await p14__namespace.select({
|
|
3500
3500
|
message: "What would you like to create in your architecture?",
|
|
3501
3501
|
options: [
|
|
3502
3502
|
{
|
|
@@ -3604,7 +3604,7 @@ async function handleCreate(type, name, flags = {}) {
|
|
|
3604
3604
|
await runInjectableCommand(name, flags);
|
|
3605
3605
|
break;
|
|
3606
3606
|
default:
|
|
3607
|
-
|
|
3607
|
+
p14__namespace.log.error(
|
|
3608
3608
|
pc14__default.default.red(
|
|
3609
3609
|
`Unknown component type: "${type}". Allowed types: feature, shared, usecase, domain, infrastructure, interface, httpHandler, injectable.`
|
|
3610
3610
|
)
|
|
@@ -3613,8 +3613,8 @@ async function handleCreate(type, name, flags = {}) {
|
|
|
3613
3613
|
}
|
|
3614
3614
|
}
|
|
3615
3615
|
var importPrompts = {
|
|
3616
|
-
select:
|
|
3617
|
-
text:
|
|
3616
|
+
select: p14__namespace.select,
|
|
3617
|
+
text: p14__namespace.text
|
|
3618
3618
|
};
|
|
3619
3619
|
function rewriteImports(content, aliasMap) {
|
|
3620
3620
|
if (aliasMap.size === 0) return content;
|
|
@@ -3643,126 +3643,6 @@ function getExistingModuleDir(projectRoot, modType, modName) {
|
|
|
3643
3643
|
function checkModuleExists(projectRoot, modType, modName) {
|
|
3644
3644
|
return getExistingModuleDir(projectRoot, modType, modName) !== null;
|
|
3645
3645
|
}
|
|
3646
|
-
async function resolveDependency(depType, depName, aliasMap, projectRoot, flags, importModuleRecursive, importedModules, registryBase, index) {
|
|
3647
|
-
const folder = depType === "shared" ? "shared" : "features";
|
|
3648
|
-
const isAlreadyImportedThisRun = importedModules.has(`${depType}:${depName}`);
|
|
3649
|
-
if (isAlreadyImportedThisRun) return;
|
|
3650
|
-
const programmaticAlias = flags.alias?.[depName] || flags.alias?.[`${depType}/${depName}`];
|
|
3651
|
-
if (programmaticAlias) {
|
|
3652
|
-
aliasMap.set(`@/${folder}/${depName}/`, `@/${folder}/${programmaticAlias}/`);
|
|
3653
|
-
const baseDir = getModuleBaseDir(projectRoot, depType);
|
|
3654
|
-
const displayDest = path2__default.default.relative(
|
|
3655
|
-
projectRoot,
|
|
3656
|
-
path2__default.default.join(baseDir, programmaticAlias)
|
|
3657
|
-
);
|
|
3658
|
-
p4__namespace.log.step(`Importing '${depName}' into '${displayDest}'...`);
|
|
3659
|
-
await importModuleRecursive(depType, depName, programmaticAlias);
|
|
3660
|
-
return;
|
|
3661
|
-
}
|
|
3662
|
-
const existingDir = getExistingModuleDir(projectRoot, depType, depName);
|
|
3663
|
-
if (!existingDir) {
|
|
3664
|
-
p4__namespace.log.info(` \u21B3 Resolving required ${depType} dependency: ${pc14__default.default.cyan(depName)}`);
|
|
3665
|
-
await importModuleRecursive(depType, depName, depName);
|
|
3666
|
-
return;
|
|
3667
|
-
}
|
|
3668
|
-
const entry = (depType === "shared" ? index?.shared : index?.features)?.find(
|
|
3669
|
-
(item) => item.name === depName
|
|
3670
|
-
);
|
|
3671
|
-
let remoteIntegrity = entry?.integrity;
|
|
3672
|
-
if (!remoteIntegrity) {
|
|
3673
|
-
try {
|
|
3674
|
-
const depManifest = await fetchModuleManifest(registryBase, depType, depName);
|
|
3675
|
-
remoteIntegrity = depManifest.integrity;
|
|
3676
|
-
} catch {
|
|
3677
|
-
}
|
|
3678
|
-
}
|
|
3679
|
-
const localHash = computeDirectoryHash(existingDir);
|
|
3680
|
-
if (remoteIntegrity && localHash === remoteIntegrity) {
|
|
3681
|
-
p4__namespace.log.step(`\u2713 ${depType}/${depName} is up to date (reusing existing)`);
|
|
3682
|
-
importedModules.add(`${depType}:${depName}`);
|
|
3683
|
-
return;
|
|
3684
|
-
}
|
|
3685
|
-
if (flags.overwrite) {
|
|
3686
|
-
p4__namespace.log.step(`Overwriting '${depType}/${depName}' with registry version (--overwrite)...`);
|
|
3687
|
-
const baseDir = getModuleBaseDir(projectRoot, depType);
|
|
3688
|
-
const targetDir = path2__default.default.join(baseDir, depName);
|
|
3689
|
-
if (!flags.dryRun) {
|
|
3690
|
-
if (existingDir !== targetDir) {
|
|
3691
|
-
fs4__default.default.rmSync(existingDir, { recursive: true, force: true });
|
|
3692
|
-
}
|
|
3693
|
-
fs4__default.default.rmSync(targetDir, { recursive: true, force: true });
|
|
3694
|
-
}
|
|
3695
|
-
await importModuleRecursive(depType, depName, depName, { overwrite: true });
|
|
3696
|
-
return;
|
|
3697
|
-
}
|
|
3698
|
-
if (flags.yes) {
|
|
3699
|
-
p4__namespace.log.info(`Using existing '${depType}/${depName}'`);
|
|
3700
|
-
importedModules.add(`${depType}:${depName}`);
|
|
3701
|
-
return;
|
|
3702
|
-
}
|
|
3703
|
-
const choice = handleCancel(
|
|
3704
|
-
await importPrompts.select({
|
|
3705
|
-
message: `Local '${depType}/${depName}' differs from the registry version.`,
|
|
3706
|
-
options: [
|
|
3707
|
-
{
|
|
3708
|
-
value: "keep_existing",
|
|
3709
|
-
label: `Keep existing local version (Recommended)`
|
|
3710
|
-
},
|
|
3711
|
-
{
|
|
3712
|
-
value: "rename",
|
|
3713
|
-
label: "Import fresh copy under a new name (alias)"
|
|
3714
|
-
},
|
|
3715
|
-
{
|
|
3716
|
-
value: "overwrite",
|
|
3717
|
-
label: "Overwrite local version with registry version"
|
|
3718
|
-
}
|
|
3719
|
-
]
|
|
3720
|
-
})
|
|
3721
|
-
);
|
|
3722
|
-
if (choice === "keep_existing" || choice === "use_existing") {
|
|
3723
|
-
p4__namespace.log.step(`Skipping '${depType}/${depName}' (keeping existing)`);
|
|
3724
|
-
importedModules.add(`${depType}:${depName}`);
|
|
3725
|
-
return;
|
|
3726
|
-
}
|
|
3727
|
-
if (choice === "rename") {
|
|
3728
|
-
const newName = handleCancel(
|
|
3729
|
-
await importPrompts.text({
|
|
3730
|
-
message: "What should we name the new copy?",
|
|
3731
|
-
placeholder: `${depName}-copy`,
|
|
3732
|
-
validate(val) {
|
|
3733
|
-
const v = val?.trim();
|
|
3734
|
-
if (!v) return "Name cannot be empty";
|
|
3735
|
-
if (v === depName) return `Name must be different from '${depName}'`;
|
|
3736
|
-
if (!/^[a-zA-Z0-9_-]+$/.test(v)) {
|
|
3737
|
-
return "Name can only contain alphanumeric characters, dashes, and underscores";
|
|
3738
|
-
}
|
|
3739
|
-
if (checkModuleExists(projectRoot, depType, v)) {
|
|
3740
|
-
return `'${v}' already exists in ${folder}, please choose another name`;
|
|
3741
|
-
}
|
|
3742
|
-
}
|
|
3743
|
-
})
|
|
3744
|
-
).trim();
|
|
3745
|
-
aliasMap.set(`@/${folder}/${depName}/`, `@/${folder}/${newName}/`);
|
|
3746
|
-
const baseDir = getModuleBaseDir(projectRoot, depType);
|
|
3747
|
-
const displayDest = path2__default.default.relative(projectRoot, path2__default.default.join(baseDir, newName));
|
|
3748
|
-
p4__namespace.log.step(`Importing '${depName}' into '${displayDest}'...`);
|
|
3749
|
-
await importModuleRecursive(depType, depName, newName);
|
|
3750
|
-
return;
|
|
3751
|
-
}
|
|
3752
|
-
if (choice === "overwrite") {
|
|
3753
|
-
p4__namespace.log.step(`Overwriting '${depType}/${depName}' with registry version...`);
|
|
3754
|
-
const baseDir = getModuleBaseDir(projectRoot, depType);
|
|
3755
|
-
const targetDir = path2__default.default.join(baseDir, depName);
|
|
3756
|
-
if (!flags.dryRun) {
|
|
3757
|
-
if (existingDir !== targetDir) {
|
|
3758
|
-
fs4__default.default.rmSync(existingDir, { recursive: true, force: true });
|
|
3759
|
-
}
|
|
3760
|
-
fs4__default.default.rmSync(targetDir, { recursive: true, force: true });
|
|
3761
|
-
}
|
|
3762
|
-
await importModuleRecursive(depType, depName, depName, { overwrite: true });
|
|
3763
|
-
return;
|
|
3764
|
-
}
|
|
3765
|
-
}
|
|
3766
3646
|
async function handleImport(typeArg, nameArg, flags = {}) {
|
|
3767
3647
|
const projectRoot = findProjectRoot();
|
|
3768
3648
|
let type = typeArg?.trim().toLowerCase();
|
|
@@ -3787,11 +3667,11 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3787
3667
|
);
|
|
3788
3668
|
}
|
|
3789
3669
|
if (type !== "shared" && type !== "feature") {
|
|
3790
|
-
|
|
3670
|
+
p14__namespace.log.error(pc14__default.default.red(`Invalid module type: "${typeArg}". Must be "shared" or "feature".`));
|
|
3791
3671
|
process.exit(1);
|
|
3792
3672
|
}
|
|
3793
3673
|
const registryBase = getRegistryBase(projectRoot, flags.registry);
|
|
3794
|
-
const s =
|
|
3674
|
+
const s = p14__namespace.spinner();
|
|
3795
3675
|
s.start(`Connecting to registry at ${pc14__default.default.dim(registryBase)}...`);
|
|
3796
3676
|
let index;
|
|
3797
3677
|
try {
|
|
@@ -3799,7 +3679,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3799
3679
|
s.stop("Registry index loaded.");
|
|
3800
3680
|
} catch (err) {
|
|
3801
3681
|
s.stop(pc14__default.default.red("Failed to load registry index."));
|
|
3802
|
-
|
|
3682
|
+
p14__namespace.log.error(pc14__default.default.red(err.message || String(err)));
|
|
3803
3683
|
process.exit(1);
|
|
3804
3684
|
}
|
|
3805
3685
|
const availableList = type === "shared" ? index.shared : index.features;
|
|
@@ -3807,7 +3687,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3807
3687
|
let name = nameArg?.trim();
|
|
3808
3688
|
if (!name) {
|
|
3809
3689
|
if (availableList.length === 0) {
|
|
3810
|
-
|
|
3690
|
+
p14__namespace.log.warn(`No ${type} modules available in the registry.`);
|
|
3811
3691
|
return;
|
|
3812
3692
|
}
|
|
3813
3693
|
name = handleCancel(
|
|
@@ -3823,108 +3703,294 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3823
3703
|
}
|
|
3824
3704
|
if (!candidateNames.includes(name)) {
|
|
3825
3705
|
const closest = findClosestMatch(name, candidateNames);
|
|
3826
|
-
|
|
3706
|
+
p14__namespace.log.error(pc14__default.default.red(`\u274C Module '${name}' not found in the ${type} registry.`));
|
|
3827
3707
|
if (closest) {
|
|
3828
|
-
|
|
3708
|
+
p14__namespace.log.info(pc14__default.default.yellow(`Did you mean '${pc14__default.default.cyan(closest)}'?`));
|
|
3829
3709
|
}
|
|
3830
3710
|
process.exit(1);
|
|
3831
3711
|
}
|
|
3832
|
-
const
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
const modKey = `${modType}:${targetName}`;
|
|
3837
|
-
if (importedModules.has(modKey)) return;
|
|
3838
|
-
p4__namespace.log.step(
|
|
3839
|
-
`Importing ${modType}: ${pc14__default.default.cyan(targetName)}${targetName !== registryName ? pc14__default.default.dim(` (from ${registryName})`) : ""}...`
|
|
3840
|
-
);
|
|
3712
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
3713
|
+
async function discoverGraph(modType, modName) {
|
|
3714
|
+
const key = `${modType}:${modName}`;
|
|
3715
|
+
if (nodes.has(key)) return;
|
|
3841
3716
|
let manifest;
|
|
3842
3717
|
try {
|
|
3843
|
-
manifest = await fetchModuleManifest(registryBase, modType,
|
|
3718
|
+
manifest = await fetchModuleManifest(registryBase, modType, modName);
|
|
3844
3719
|
} catch (err) {
|
|
3845
|
-
|
|
3720
|
+
p14__namespace.log.error(pc14__default.default.red(`Failed to fetch manifest for ${modType} '${modName}': ${err.message}`));
|
|
3846
3721
|
process.exit(1);
|
|
3847
3722
|
}
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3723
|
+
nodes.set(key, {
|
|
3724
|
+
type: modType,
|
|
3725
|
+
name: modName,
|
|
3726
|
+
manifest
|
|
3727
|
+
});
|
|
3728
|
+
for (const dep of manifest.dependencies?.shared || []) {
|
|
3729
|
+
await discoverGraph("shared", dep);
|
|
3852
3730
|
}
|
|
3853
|
-
const
|
|
3854
|
-
|
|
3855
|
-
await resolveDependency(
|
|
3856
|
-
"shared",
|
|
3857
|
-
dep,
|
|
3858
|
-
aliasMap,
|
|
3859
|
-
projectRoot,
|
|
3860
|
-
flags,
|
|
3861
|
-
importModuleRecursive,
|
|
3862
|
-
importedModules,
|
|
3863
|
-
registryBase,
|
|
3864
|
-
index
|
|
3865
|
-
);
|
|
3731
|
+
for (const dep of manifest.dependencies?.features || []) {
|
|
3732
|
+
await discoverGraph("feature", dep);
|
|
3866
3733
|
}
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3734
|
+
}
|
|
3735
|
+
await discoverGraph(type, name);
|
|
3736
|
+
const orderedKeys = [];
|
|
3737
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
3738
|
+
const visited = /* @__PURE__ */ new Set();
|
|
3739
|
+
function buildTopologicalOrder(key) {
|
|
3740
|
+
if (visited.has(key)) return;
|
|
3741
|
+
if (visiting.has(key)) return;
|
|
3742
|
+
visiting.add(key);
|
|
3743
|
+
const node = nodes.get(key);
|
|
3744
|
+
if (node) {
|
|
3745
|
+
for (const dep of node.manifest.dependencies?.shared || []) {
|
|
3746
|
+
buildTopologicalOrder(`shared:${dep}`);
|
|
3747
|
+
}
|
|
3748
|
+
for (const dep of node.manifest.dependencies?.features || []) {
|
|
3749
|
+
buildTopologicalOrder(`feature:${dep}`);
|
|
3750
|
+
}
|
|
3751
|
+
}
|
|
3752
|
+
visiting.delete(key);
|
|
3753
|
+
visited.add(key);
|
|
3754
|
+
orderedKeys.push(key);
|
|
3755
|
+
}
|
|
3756
|
+
const rootKey = `${type}:${name}`;
|
|
3757
|
+
buildTopologicalOrder(rootKey);
|
|
3758
|
+
const resolutions = /* @__PURE__ */ new Map();
|
|
3759
|
+
const globalAliasMap = /* @__PURE__ */ new Map();
|
|
3760
|
+
p14__namespace.log.step(`Importing ${type}: ${pc14__default.default.cyan(name)}...`);
|
|
3761
|
+
for (const key of orderedKeys) {
|
|
3762
|
+
const node = nodes.get(key);
|
|
3763
|
+
const { type: modType, name: registryName, manifest } = node;
|
|
3764
|
+
const folder = modType === "shared" ? "shared" : "features";
|
|
3765
|
+
if (key === rootKey) {
|
|
3766
|
+
const programmaticAlias2 = flags.alias?.[registryName] || flags.alias?.[`${modType}/${registryName}`];
|
|
3767
|
+
const targetName = programmaticAlias2 || registryName;
|
|
3768
|
+
if (targetName !== registryName) {
|
|
3769
|
+
globalAliasMap.set(`@/${folder}/${registryName}/`, `@/${folder}/${targetName}/`);
|
|
3770
|
+
globalAliasMap.set(`@/${folder}/${registryName}`, `@/${folder}/${targetName}`);
|
|
3771
|
+
}
|
|
3772
|
+
resolutions.set(key, {
|
|
3773
|
+
type: modType,
|
|
3774
|
+
registryName,
|
|
3775
|
+
targetName,
|
|
3776
|
+
action: flags.overwrite ? "overwrite" : "download",
|
|
3777
|
+
manifest
|
|
3778
|
+
});
|
|
3779
|
+
continue;
|
|
3780
|
+
}
|
|
3781
|
+
const programmaticAlias = flags.alias?.[registryName] || flags.alias?.[`${modType}/${registryName}`];
|
|
3782
|
+
if (programmaticAlias) {
|
|
3783
|
+
globalAliasMap.set(`@/${folder}/${registryName}/`, `@/${folder}/${programmaticAlias}/`);
|
|
3784
|
+
globalAliasMap.set(`@/${folder}/${registryName}`, `@/${folder}/${programmaticAlias}`);
|
|
3785
|
+
const baseDir = getModuleBaseDir(projectRoot, modType);
|
|
3786
|
+
const displayDest = path2__default.default.relative(projectRoot, path2__default.default.join(baseDir, programmaticAlias));
|
|
3787
|
+
p14__namespace.log.step(`Importing '${registryName}' into '${displayDest}'...`);
|
|
3788
|
+
resolutions.set(key, {
|
|
3789
|
+
type: modType,
|
|
3790
|
+
registryName,
|
|
3791
|
+
targetName: programmaticAlias,
|
|
3792
|
+
action: "alias",
|
|
3793
|
+
manifest
|
|
3794
|
+
});
|
|
3795
|
+
continue;
|
|
3796
|
+
}
|
|
3797
|
+
const existingDir = getExistingModuleDir(projectRoot, modType, registryName);
|
|
3798
|
+
if (!existingDir) {
|
|
3799
|
+
p14__namespace.log.info(` \u21B3 Resolving required ${modType} dependency: ${pc14__default.default.cyan(registryName)}`);
|
|
3800
|
+
resolutions.set(key, {
|
|
3801
|
+
type: modType,
|
|
3802
|
+
registryName,
|
|
3803
|
+
targetName: registryName,
|
|
3804
|
+
action: "download",
|
|
3805
|
+
manifest
|
|
3806
|
+
});
|
|
3807
|
+
continue;
|
|
3808
|
+
}
|
|
3809
|
+
const entry = (modType === "shared" ? index.shared : index.features)?.find(
|
|
3810
|
+
(item) => item.name === registryName
|
|
3811
|
+
);
|
|
3812
|
+
const remoteIntegrity = manifest.integrity || entry?.integrity;
|
|
3813
|
+
const localHash = computeDirectoryHash(existingDir);
|
|
3814
|
+
if (remoteIntegrity && localHash === remoteIntegrity) {
|
|
3815
|
+
p14__namespace.log.step(`\u2713 ${modType}/${registryName} is up to date (reusing existing)`);
|
|
3816
|
+
resolutions.set(key, {
|
|
3817
|
+
type: modType,
|
|
3818
|
+
registryName,
|
|
3819
|
+
targetName: registryName,
|
|
3820
|
+
action: "reuse",
|
|
3821
|
+
manifest
|
|
3822
|
+
});
|
|
3823
|
+
continue;
|
|
3824
|
+
}
|
|
3825
|
+
if (flags.overwrite) {
|
|
3826
|
+
p14__namespace.log.step(`Overwriting '${modType}/${registryName}' with registry version (--overwrite)...`);
|
|
3827
|
+
resolutions.set(key, {
|
|
3828
|
+
type: modType,
|
|
3829
|
+
registryName,
|
|
3830
|
+
targetName: registryName,
|
|
3831
|
+
action: "overwrite",
|
|
3832
|
+
manifest
|
|
3833
|
+
});
|
|
3834
|
+
continue;
|
|
3835
|
+
}
|
|
3836
|
+
if (flags.yes) {
|
|
3837
|
+
p14__namespace.log.info(`Using existing '${modType}/${registryName}'`);
|
|
3838
|
+
resolutions.set(key, {
|
|
3839
|
+
type: modType,
|
|
3840
|
+
registryName,
|
|
3841
|
+
targetName: registryName,
|
|
3842
|
+
action: "reuse",
|
|
3843
|
+
manifest
|
|
3844
|
+
});
|
|
3845
|
+
continue;
|
|
3880
3846
|
}
|
|
3881
|
-
|
|
3847
|
+
const choice = handleCancel(
|
|
3848
|
+
await importPrompts.select({
|
|
3849
|
+
message: `Local '${modType}/${registryName}' differs from the registry version.`,
|
|
3850
|
+
options: [
|
|
3851
|
+
{
|
|
3852
|
+
value: "keep_existing",
|
|
3853
|
+
label: `Keep existing local version (Recommended)`
|
|
3854
|
+
},
|
|
3855
|
+
{
|
|
3856
|
+
value: "rename",
|
|
3857
|
+
label: "Import fresh copy under a new name (alias)"
|
|
3858
|
+
},
|
|
3859
|
+
{
|
|
3860
|
+
value: "overwrite",
|
|
3861
|
+
label: "Overwrite local version with registry version"
|
|
3862
|
+
}
|
|
3863
|
+
]
|
|
3864
|
+
})
|
|
3865
|
+
);
|
|
3866
|
+
if (choice === "keep_existing" || choice === "use_existing") {
|
|
3867
|
+
p14__namespace.log.step(`Skipping '${modType}/${registryName}' (keeping existing)`);
|
|
3868
|
+
resolutions.set(key, {
|
|
3869
|
+
type: modType,
|
|
3870
|
+
registryName,
|
|
3871
|
+
targetName: registryName,
|
|
3872
|
+
action: "reuse",
|
|
3873
|
+
manifest
|
|
3874
|
+
});
|
|
3875
|
+
continue;
|
|
3876
|
+
}
|
|
3877
|
+
if (choice === "rename") {
|
|
3878
|
+
const newName = handleCancel(
|
|
3879
|
+
await importPrompts.text({
|
|
3880
|
+
message: "What should we name the new copy?",
|
|
3881
|
+
placeholder: `${registryName}-copy`,
|
|
3882
|
+
validate(val) {
|
|
3883
|
+
const v = val?.trim();
|
|
3884
|
+
if (!v) return "Name cannot be empty";
|
|
3885
|
+
if (v === registryName) return `Name must be different from '${registryName}'`;
|
|
3886
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(v)) {
|
|
3887
|
+
return "Name can only contain alphanumeric characters, dashes, and underscores";
|
|
3888
|
+
}
|
|
3889
|
+
if (checkModuleExists(projectRoot, modType, v)) {
|
|
3890
|
+
return `'${v}' already exists in ${folder}, please choose another name`;
|
|
3891
|
+
}
|
|
3892
|
+
}
|
|
3893
|
+
})
|
|
3894
|
+
).trim();
|
|
3895
|
+
globalAliasMap.set(`@/${folder}/${registryName}/`, `@/${folder}/${newName}/`);
|
|
3896
|
+
globalAliasMap.set(`@/${folder}/${registryName}`, `@/${folder}/${newName}`);
|
|
3897
|
+
const baseDir = getModuleBaseDir(projectRoot, modType);
|
|
3898
|
+
const displayDest = path2__default.default.relative(projectRoot, path2__default.default.join(baseDir, newName));
|
|
3899
|
+
p14__namespace.log.step(`Importing '${registryName}' into '${displayDest}'...`);
|
|
3900
|
+
resolutions.set(key, {
|
|
3901
|
+
type: modType,
|
|
3902
|
+
registryName,
|
|
3903
|
+
targetName: newName,
|
|
3904
|
+
action: "alias",
|
|
3905
|
+
manifest
|
|
3906
|
+
});
|
|
3907
|
+
continue;
|
|
3908
|
+
}
|
|
3909
|
+
if (choice === "overwrite") {
|
|
3910
|
+
p14__namespace.log.step(`Overwriting '${modType}/${registryName}' with registry version...`);
|
|
3911
|
+
resolutions.set(key, {
|
|
3912
|
+
type: modType,
|
|
3913
|
+
registryName,
|
|
3914
|
+
targetName: registryName,
|
|
3915
|
+
action: "overwrite",
|
|
3916
|
+
manifest
|
|
3917
|
+
});
|
|
3918
|
+
continue;
|
|
3919
|
+
}
|
|
3920
|
+
}
|
|
3921
|
+
const totalWrittenFiles = [];
|
|
3922
|
+
const requiredNpmPackages = /* @__PURE__ */ new Set();
|
|
3923
|
+
for (const node of nodes.values()) {
|
|
3924
|
+
for (const pkg of node.manifest.dependencies?.npm || []) {
|
|
3882
3925
|
requiredNpmPackages.add(pkg);
|
|
3883
3926
|
}
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
const
|
|
3887
|
-
|
|
3927
|
+
}
|
|
3928
|
+
for (const key of orderedKeys) {
|
|
3929
|
+
const res = resolutions.get(key);
|
|
3930
|
+
if (res.action === "reuse") {
|
|
3931
|
+
continue;
|
|
3932
|
+
}
|
|
3933
|
+
const folder = res.type === "shared" ? "shared" : "features";
|
|
3934
|
+
const targetDir = path2__default.default.join(getModuleBaseDir(projectRoot, res.type), res.targetName);
|
|
3935
|
+
const isOverwrite = Boolean(flags.overwrite || res.action === "overwrite");
|
|
3936
|
+
if (key !== rootKey) {
|
|
3937
|
+
p14__namespace.log.step(
|
|
3938
|
+
`Importing ${res.type}: ${pc14__default.default.cyan(res.targetName)}${res.targetName !== res.registryName ? pc14__default.default.dim(` (from ${res.registryName})`) : ""}...`
|
|
3939
|
+
);
|
|
3940
|
+
}
|
|
3941
|
+
if (res.action === "overwrite" && !flags.dryRun) {
|
|
3942
|
+
const existingDir = getExistingModuleDir(projectRoot, res.type, res.targetName);
|
|
3943
|
+
if (existingDir && existingDir !== targetDir) {
|
|
3944
|
+
fs4__default.default.rmSync(existingDir, { recursive: true, force: true });
|
|
3945
|
+
}
|
|
3946
|
+
if (fs4__default.default.existsSync(targetDir)) {
|
|
3947
|
+
fs4__default.default.rmSync(targetDir, { recursive: true, force: true });
|
|
3948
|
+
}
|
|
3949
|
+
}
|
|
3950
|
+
for (const file of res.manifest.files || []) {
|
|
3888
3951
|
if (file === "registry.json") continue;
|
|
3889
|
-
const remoteFilePath = `${folder}/${registryName}/${file}`;
|
|
3952
|
+
const remoteFilePath = `${folder}/${res.registryName}/${file}`;
|
|
3890
3953
|
const localFilePath = path2__default.default.join(targetDir, file);
|
|
3891
3954
|
if (fs4__default.default.existsSync(localFilePath) && !isOverwrite) {
|
|
3892
|
-
|
|
3955
|
+
p14__namespace.log.warn(
|
|
3893
3956
|
` \u21B3 Skipping existing file: ${pc14__default.default.dim(path2__default.default.relative(projectRoot, localFilePath))} (use --overwrite to replace)`
|
|
3894
3957
|
);
|
|
3895
3958
|
continue;
|
|
3896
3959
|
}
|
|
3897
3960
|
let content = await fetchRegistryFile(registryBase, remoteFilePath);
|
|
3898
|
-
content = rewriteImports(content,
|
|
3961
|
+
content = rewriteImports(content, globalAliasMap);
|
|
3899
3962
|
if (!flags.dryRun) {
|
|
3900
3963
|
fs4__default.default.mkdirSync(path2__default.default.dirname(localFilePath), { recursive: true });
|
|
3901
3964
|
fs4__default.default.writeFileSync(localFilePath, content, "utf-8");
|
|
3902
3965
|
}
|
|
3903
3966
|
const displayPath = path2__default.default.relative(projectRoot, localFilePath);
|
|
3904
3967
|
totalWrittenFiles.push(displayPath);
|
|
3905
|
-
|
|
3968
|
+
p14__namespace.log.message(` ${pc14__default.default.green("+")} ${displayPath}`);
|
|
3906
3969
|
}
|
|
3907
|
-
importedModules.add(modKey);
|
|
3908
3970
|
}
|
|
3909
|
-
await importModuleRecursive(type, name, name);
|
|
3910
3971
|
const missingNpm = getMissingNpmPackages(projectRoot, Array.from(requiredNpmPackages));
|
|
3911
3972
|
if (missingNpm.length > 0) {
|
|
3912
3973
|
if (flags.skipInstall || flags.dryRun) {
|
|
3913
|
-
|
|
3974
|
+
p14__namespace.log.info(`Required npm dependencies to install: ${pc14__default.default.cyan(missingNpm.join(", "))}`);
|
|
3914
3975
|
} else {
|
|
3915
3976
|
try {
|
|
3916
3977
|
installNpmPackages(projectRoot, missingNpm);
|
|
3917
3978
|
} catch (err) {
|
|
3918
|
-
|
|
3979
|
+
p14__namespace.log.warn(
|
|
3980
|
+
`Could not automatically install packages (${err.message}). Please run: npm install ${missingNpm.join(
|
|
3981
|
+
" "
|
|
3982
|
+
)}`
|
|
3983
|
+
);
|
|
3919
3984
|
}
|
|
3920
3985
|
}
|
|
3921
3986
|
}
|
|
3922
3987
|
if (flags.dryRun) {
|
|
3923
|
-
|
|
3988
|
+
p14__namespace.log.info(pc14__default.default.yellow("Dry run complete: No files were written to disk."));
|
|
3924
3989
|
} else {
|
|
3990
|
+
const rootRes = resolutions.get(rootKey);
|
|
3925
3991
|
const baseDir = getModuleBaseDir(projectRoot, type);
|
|
3926
|
-
const displayTarget = path2__default.default.relative(projectRoot, path2__default.default.join(baseDir,
|
|
3927
|
-
|
|
3992
|
+
const displayTarget = path2__default.default.relative(projectRoot, path2__default.default.join(baseDir, rootRes.targetName));
|
|
3993
|
+
p14__namespace.log.success(
|
|
3928
3994
|
pc14__default.default.green(
|
|
3929
3995
|
`Successfully imported ${type} '${name}' (${totalWrittenFiles.length} file${totalWrittenFiles.length === 1 ? "" : "s"} placed in ${displayTarget})`
|
|
3930
3996
|
)
|
|
@@ -3937,7 +4003,7 @@ function createCli() {
|
|
|
3937
4003
|
const cli = cac.cac("mason");
|
|
3938
4004
|
cli.command("[...args]", "Interactive scaffolding and import wizard").option("-d, --dry-run", "Preview changes without writing to disk").option("-o, --overwrite", "Overwrite existing files").option("-y, --yes", "Accept defaults and skip interactive prompts").option("--registry", "Run in registry mode").action(async (args, flags) => {
|
|
3939
4005
|
if (args && args.length > 0) {
|
|
3940
|
-
|
|
4006
|
+
p14__namespace.log.error(
|
|
3941
4007
|
pc14__default.default.red(
|
|
3942
4008
|
`Unknown command: "${args.join(" ")}". Use --help to list available commands.`
|
|
3943
4009
|
)
|
|
@@ -3949,7 +4015,7 @@ function createCli() {
|
|
|
3949
4015
|
const mode = getEffectiveMode(projectRoot, flags);
|
|
3950
4016
|
if (mode === "registry") {
|
|
3951
4017
|
const choice2 = handleCancel(
|
|
3952
|
-
await
|
|
4018
|
+
await p14__namespace.select({
|
|
3953
4019
|
message: "\u{1F3DB}\uFE0F Mason (Registry Mode): What would you like to scaffold?",
|
|
3954
4020
|
options: [
|
|
3955
4021
|
{
|
|
@@ -3992,7 +4058,7 @@ function createCli() {
|
|
|
3992
4058
|
return;
|
|
3993
4059
|
}
|
|
3994
4060
|
const choice = handleCancel(
|
|
3995
|
-
await
|
|
4061
|
+
await p14__namespace.select({
|
|
3996
4062
|
message: "\u{1F9F1} Mason: What would you like to do?",
|
|
3997
4063
|
options: [
|
|
3998
4064
|
{
|
|
@@ -4060,7 +4126,7 @@ function createCli() {
|
|
|
4060
4126
|
});
|
|
4061
4127
|
}
|
|
4062
4128
|
cli.help();
|
|
4063
|
-
cli.version("1.0.
|
|
4129
|
+
cli.version("1.0.16");
|
|
4064
4130
|
return cli;
|
|
4065
4131
|
}
|
|
4066
4132
|
function handleCliError(err) {
|
|
@@ -4068,7 +4134,7 @@ function handleCliError(err) {
|
|
|
4068
4134
|
process.exit(0);
|
|
4069
4135
|
}
|
|
4070
4136
|
const message = err instanceof Error ? err.message : String(err);
|
|
4071
|
-
|
|
4137
|
+
p14__namespace.log.error(pc14__default.default.red(`Error: ${message}`));
|
|
4072
4138
|
process.exit(1);
|
|
4073
4139
|
}
|
|
4074
4140
|
async function runCli(argv = process.argv) {
|