@solid-stack/mason 1.0.13 → 1.0.15
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 +249 -844
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +246 -841
- package/dist/bin.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/index.cjs +250 -846
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +248 -843
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/commands/registry.d.ts +0 -64
- package/dist/commands/registry.d.ts.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var fs4 = require('fs');
|
|
4
4
|
var path2 = require('path');
|
|
5
|
-
var
|
|
6
|
-
var
|
|
5
|
+
var p4 = require('@clack/prompts');
|
|
6
|
+
var pc14 = require('picocolors');
|
|
7
7
|
var url = require('url');
|
|
8
8
|
var child_process = require('child_process');
|
|
9
9
|
var crypto = require('crypto');
|
|
@@ -31,10 +31,10 @@ function _interopNamespace(e) {
|
|
|
31
31
|
return Object.freeze(n);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
var
|
|
34
|
+
var fs4__default = /*#__PURE__*/_interopDefault(fs4);
|
|
35
35
|
var path2__default = /*#__PURE__*/_interopDefault(path2);
|
|
36
|
-
var
|
|
37
|
-
var
|
|
36
|
+
var p4__namespace = /*#__PURE__*/_interopNamespace(p4);
|
|
37
|
+
var pc14__default = /*#__PURE__*/_interopDefault(pc14);
|
|
38
38
|
var Handlebars__default = /*#__PURE__*/_interopDefault(Handlebars);
|
|
39
39
|
|
|
40
40
|
// src/utils/formatting.ts
|
|
@@ -106,7 +106,7 @@ function isValidIdentifier(str) {
|
|
|
106
106
|
function writeFileSafely(absolutePath, content, options = {}) {
|
|
107
107
|
const projectRoot = options.projectRoot || process.cwd();
|
|
108
108
|
const relPath = path2__default.default.relative(projectRoot, absolutePath).replace(/\\/g, "/");
|
|
109
|
-
const existedBefore =
|
|
109
|
+
const existedBefore = fs4__default.default.existsSync(absolutePath);
|
|
110
110
|
if (options.dryRun) {
|
|
111
111
|
return {
|
|
112
112
|
relativePath: relPath,
|
|
@@ -126,10 +126,10 @@ function writeFileSafely(absolutePath, content, options = {}) {
|
|
|
126
126
|
};
|
|
127
127
|
}
|
|
128
128
|
const dir = path2__default.default.dirname(absolutePath);
|
|
129
|
-
if (!
|
|
130
|
-
|
|
129
|
+
if (!fs4__default.default.existsSync(dir)) {
|
|
130
|
+
fs4__default.default.mkdirSync(dir, { recursive: true });
|
|
131
131
|
}
|
|
132
|
-
|
|
132
|
+
fs4__default.default.writeFileSync(absolutePath, content, "utf-8");
|
|
133
133
|
return {
|
|
134
134
|
relativePath: relPath,
|
|
135
135
|
absolutePath,
|
|
@@ -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
|
+
p4__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
|
+
p4__namespace.log.success(`${pc14__default.default.bold(f.relativePath)} ${pc14__default.default.dim("(created)")}`);
|
|
149
149
|
} else if (f.action === "overwritten") {
|
|
150
|
-
|
|
150
|
+
p4__namespace.log.warn(`${pc14__default.default.bold(f.relativePath)} ${pc14__default.default.dim("(overwritten)")}`);
|
|
151
151
|
} else if (f.action === "skipped") {
|
|
152
|
-
|
|
152
|
+
p4__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
|
+
p4__namespace.log.info(`${pc14__default.default.bold(f.relativePath)} ${pc14__default.default.dim("(preview)")}`);
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
}
|
|
@@ -159,9 +159,9 @@ function loadMasonConfig(startDir = process.cwd()) {
|
|
|
159
159
|
let current = path2__default.default.resolve(startDir);
|
|
160
160
|
while (true) {
|
|
161
161
|
const configPath = path2__default.default.join(current, "mason.config.json");
|
|
162
|
-
if (
|
|
162
|
+
if (fs4__default.default.existsSync(configPath)) {
|
|
163
163
|
try {
|
|
164
|
-
return JSON.parse(
|
|
164
|
+
return JSON.parse(fs4__default.default.readFileSync(configPath, "utf-8"));
|
|
165
165
|
} catch {
|
|
166
166
|
return null;
|
|
167
167
|
}
|
|
@@ -176,7 +176,7 @@ function getEffectiveMode(projectRoot, flags) {
|
|
|
176
176
|
if (flags?.registry) return "registry";
|
|
177
177
|
const config = loadMasonConfig(projectRoot);
|
|
178
178
|
if (config?.mode) return config.mode;
|
|
179
|
-
if (
|
|
179
|
+
if (fs4__default.default.existsSync(path2__default.default.join(projectRoot, "index.json")) && (fs4__default.default.existsSync(path2__default.default.join(projectRoot, "features")) || fs4__default.default.existsSync(path2__default.default.join(projectRoot, "shared"))) && !fs4__default.default.existsSync(path2__default.default.join(projectRoot, "src"))) {
|
|
180
180
|
return "registry";
|
|
181
181
|
}
|
|
182
182
|
return "app";
|
|
@@ -192,7 +192,7 @@ function getConfiguredFeaturesDir(projectRoot, flags) {
|
|
|
192
192
|
if (mode === "registry") {
|
|
193
193
|
return path2__default.default.join(projectRoot, "features");
|
|
194
194
|
}
|
|
195
|
-
if (
|
|
195
|
+
if (fs4__default.default.existsSync(path2__default.default.join(projectRoot, "src/features"))) {
|
|
196
196
|
return path2__default.default.join(projectRoot, "src/features");
|
|
197
197
|
}
|
|
198
198
|
return path2__default.default.join(projectRoot, "features");
|
|
@@ -208,7 +208,7 @@ function getConfiguredSharedDir(projectRoot, flags) {
|
|
|
208
208
|
if (mode === "registry") {
|
|
209
209
|
return path2__default.default.join(projectRoot, "shared");
|
|
210
210
|
}
|
|
211
|
-
if (
|
|
211
|
+
if (fs4__default.default.existsSync(path2__default.default.join(projectRoot, "src/shared"))) {
|
|
212
212
|
return path2__default.default.join(projectRoot, "src/shared");
|
|
213
213
|
}
|
|
214
214
|
return path2__default.default.join(projectRoot, "shared");
|
|
@@ -218,7 +218,7 @@ function getConfiguredSharedDir(projectRoot, flags) {
|
|
|
218
218
|
function findProjectRoot(startDir = process.cwd()) {
|
|
219
219
|
let current = path2__default.default.resolve(startDir);
|
|
220
220
|
while (true) {
|
|
221
|
-
if (
|
|
221
|
+
if (fs4__default.default.existsSync(path2__default.default.join(current, "package.json"))) {
|
|
222
222
|
return current;
|
|
223
223
|
}
|
|
224
224
|
const parent = path2__default.default.dirname(current);
|
|
@@ -236,9 +236,9 @@ function resolveSharedDir(projectRoot, flags) {
|
|
|
236
236
|
}
|
|
237
237
|
function listExistingShared(projectRoot) {
|
|
238
238
|
const sharedDir = resolveSharedDir(projectRoot);
|
|
239
|
-
if (!
|
|
239
|
+
if (!fs4__default.default.existsSync(sharedDir)) return [];
|
|
240
240
|
try {
|
|
241
|
-
const entries =
|
|
241
|
+
const entries = fs4__default.default.readdirSync(sharedDir, { withFileTypes: true });
|
|
242
242
|
return entries.filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => e.name).sort();
|
|
243
243
|
} catch {
|
|
244
244
|
return [];
|
|
@@ -246,9 +246,9 @@ function listExistingShared(projectRoot) {
|
|
|
246
246
|
}
|
|
247
247
|
function listExistingFeatures(projectRoot) {
|
|
248
248
|
const featuresDir = resolveFeaturesDir(projectRoot);
|
|
249
|
-
if (!
|
|
249
|
+
if (!fs4__default.default.existsSync(featuresDir)) return [];
|
|
250
250
|
try {
|
|
251
|
-
const entries =
|
|
251
|
+
const entries = fs4__default.default.readdirSync(featuresDir, { withFileTypes: true });
|
|
252
252
|
return entries.filter((e) => e.isDirectory()).map((e) => e.name).sort();
|
|
253
253
|
} catch {
|
|
254
254
|
return [];
|
|
@@ -259,9 +259,9 @@ function listDomainInterfaces(projectRoot, featureName) {
|
|
|
259
259
|
const features = featureName ? [featureName] : listExistingFeatures(projectRoot);
|
|
260
260
|
for (const feat of features) {
|
|
261
261
|
const domainDir = path2__default.default.join(resolveFeaturesDir(projectRoot), feat, "domain");
|
|
262
|
-
if (!
|
|
262
|
+
if (!fs4__default.default.existsSync(domainDir)) continue;
|
|
263
263
|
try {
|
|
264
|
-
const files =
|
|
264
|
+
const files = fs4__default.default.readdirSync(domainDir);
|
|
265
265
|
for (const file of files) {
|
|
266
266
|
if (file.endsWith(".ts") && !file.endsWith(".test.ts") && !file.endsWith(".d.ts")) {
|
|
267
267
|
const name = file.replace(/\.ts$/, "");
|
|
@@ -274,7 +274,7 @@ function listDomainInterfaces(projectRoot, featureName) {
|
|
|
274
274
|
});
|
|
275
275
|
} else {
|
|
276
276
|
try {
|
|
277
|
-
const content =
|
|
277
|
+
const content = fs4__default.default.readFileSync(fullPath, "utf-8");
|
|
278
278
|
if (/export\s+(?:abstract\s+class|interface)\s+(\w+)/.test(content)) {
|
|
279
279
|
results.push({
|
|
280
280
|
name,
|
|
@@ -297,9 +297,9 @@ function listDomainEntities(projectRoot, featureName) {
|
|
|
297
297
|
const features = featureName ? [featureName] : listExistingFeatures(projectRoot);
|
|
298
298
|
for (const feat of features) {
|
|
299
299
|
const domainDir = path2__default.default.join(resolveFeaturesDir(projectRoot), feat, "domain");
|
|
300
|
-
if (!
|
|
300
|
+
if (!fs4__default.default.existsSync(domainDir)) continue;
|
|
301
301
|
try {
|
|
302
|
-
const files =
|
|
302
|
+
const files = fs4__default.default.readdirSync(domainDir);
|
|
303
303
|
for (const file of files) {
|
|
304
304
|
if (file.endsWith(".ts") && !file.endsWith(".test.ts") && !file.endsWith(".d.ts")) {
|
|
305
305
|
const name = file.replace(/\.ts$/, "");
|
|
@@ -322,9 +322,9 @@ function listUseCases(projectRoot, featureName) {
|
|
|
322
322
|
const features = featureName ? [featureName] : listExistingFeatures(projectRoot);
|
|
323
323
|
for (const feat of features) {
|
|
324
324
|
const useCasesDir = path2__default.default.join(resolveFeaturesDir(projectRoot), feat, "useCases");
|
|
325
|
-
if (!
|
|
325
|
+
if (!fs4__default.default.existsSync(useCasesDir)) continue;
|
|
326
326
|
try {
|
|
327
|
-
const files =
|
|
327
|
+
const files = fs4__default.default.readdirSync(useCasesDir);
|
|
328
328
|
for (const file of files) {
|
|
329
329
|
if (file.endsWith(".ts") && !file.endsWith(".test.ts") && !file.endsWith(".d.ts")) {
|
|
330
330
|
const name = file.replace(/\.ts$/, "");
|
|
@@ -347,23 +347,23 @@ var PromptCancelledError = class extends Error {
|
|
|
347
347
|
}
|
|
348
348
|
};
|
|
349
349
|
function handleCancel(result) {
|
|
350
|
-
if (
|
|
351
|
-
|
|
350
|
+
if (p4__namespace.isCancel(result)) {
|
|
351
|
+
p4__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
|
+
p4__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
|
-
const summary = properties.map((
|
|
364
|
-
|
|
363
|
+
const summary = properties.map((p16) => `${p16.name}: ${p16.type}${p16.optional ? "?" : ""}`).join(", ");
|
|
364
|
+
p4__namespace.log.info(pc14__default.default.dim(`Pre-configured fields: ${summary}`));
|
|
365
365
|
const addMore = handleCancel(
|
|
366
|
-
await
|
|
366
|
+
await p4__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
|
+
p4__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 p4__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 p4__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 p4__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 p4__namespace.confirm({
|
|
413
413
|
message: `Is "${name.trim()}" optional?`,
|
|
414
414
|
initialValue: false
|
|
415
415
|
})
|
|
@@ -419,8 +419,8 @@ async function promptProperties(options = {}) {
|
|
|
419
419
|
type: finalType.trim(),
|
|
420
420
|
optional
|
|
421
421
|
});
|
|
422
|
-
|
|
423
|
-
|
|
422
|
+
p4__namespace.log.success(
|
|
423
|
+
pc14__default.default.green(`Added: ${name.trim()}${optional ? "?" : ""}: ${finalType.trim()}`)
|
|
424
424
|
);
|
|
425
425
|
}
|
|
426
426
|
return properties;
|
|
@@ -450,7 +450,7 @@ function findLocalRegistry(startDir = process.cwd()) {
|
|
|
450
450
|
let current = path2__default.default.resolve(startDir);
|
|
451
451
|
while (true) {
|
|
452
452
|
const candidate = path2__default.default.join(current, "mason-registry");
|
|
453
|
-
if (
|
|
453
|
+
if (fs4__default.default.existsSync(candidate) && fs4__default.default.existsSync(path2__default.default.join(candidate, "index.json"))) {
|
|
454
454
|
return candidate;
|
|
455
455
|
}
|
|
456
456
|
const parent = path2__default.default.dirname(current);
|
|
@@ -472,9 +472,9 @@ function getRegistryBase(projectRoot, override) {
|
|
|
472
472
|
path2__default.default.join(process.cwd(), "mason.config.json")
|
|
473
473
|
];
|
|
474
474
|
for (const configPath of configLocations) {
|
|
475
|
-
if (
|
|
475
|
+
if (fs4__default.default.existsSync(configPath)) {
|
|
476
476
|
try {
|
|
477
|
-
const config = JSON.parse(
|
|
477
|
+
const config = JSON.parse(fs4__default.default.readFileSync(configPath, "utf-8"));
|
|
478
478
|
if (config.registry && typeof config.registry === "string") {
|
|
479
479
|
return normalizeRegistryUrl(config.registry.trim(), path2__default.default.dirname(configPath));
|
|
480
480
|
}
|
|
@@ -487,9 +487,9 @@ function getRegistryBase(projectRoot, override) {
|
|
|
487
487
|
path2__default.default.join(process.cwd(), "package.json")
|
|
488
488
|
];
|
|
489
489
|
for (const pkgPath of pkgLocations) {
|
|
490
|
-
if (
|
|
490
|
+
if (fs4__default.default.existsSync(pkgPath)) {
|
|
491
491
|
try {
|
|
492
|
-
const pkg = JSON.parse(
|
|
492
|
+
const pkg = JSON.parse(fs4__default.default.readFileSync(pkgPath, "utf-8"));
|
|
493
493
|
if (pkg.mason?.registry && typeof pkg.mason.registry === "string") {
|
|
494
494
|
return normalizeRegistryUrl(pkg.mason.registry.trim(), path2__default.default.dirname(pkgPath));
|
|
495
495
|
}
|
|
@@ -533,10 +533,10 @@ async function fetchRegistryFile(registryBase, relPath) {
|
|
|
533
533
|
baseDir = url.fileURLToPath(baseDir);
|
|
534
534
|
}
|
|
535
535
|
const filePath = path2__default.default.resolve(baseDir, cleanRelPath);
|
|
536
|
-
if (!
|
|
536
|
+
if (!fs4__default.default.existsSync(filePath)) {
|
|
537
537
|
throw new Error(`Registry file not found at ${filePath}`);
|
|
538
538
|
}
|
|
539
|
-
return
|
|
539
|
+
return fs4__default.default.promises.readFile(filePath, "utf-8");
|
|
540
540
|
}
|
|
541
541
|
async function fetchRegistryIndex(registryBase) {
|
|
542
542
|
const content = await fetchRegistryFile(registryBase, "index.json");
|
|
@@ -598,26 +598,26 @@ function findClosestMatch(target, candidates) {
|
|
|
598
598
|
return null;
|
|
599
599
|
}
|
|
600
600
|
function detectPackageManager(projectRoot) {
|
|
601
|
-
if (
|
|
602
|
-
if (
|
|
603
|
-
if (
|
|
601
|
+
if (fs4__default.default.existsSync(path2__default.default.join(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
|
|
602
|
+
if (fs4__default.default.existsSync(path2__default.default.join(projectRoot, "yarn.lock"))) return "yarn";
|
|
603
|
+
if (fs4__default.default.existsSync(path2__default.default.join(projectRoot, "bun.lockb")) || fs4__default.default.existsSync(path2__default.default.join(projectRoot, "bun.lock"))) return "bun";
|
|
604
604
|
return "npm";
|
|
605
605
|
}
|
|
606
606
|
function getMissingNpmPackages(projectRoot, requiredPackages) {
|
|
607
607
|
if (!requiredPackages || requiredPackages.length === 0) return [];
|
|
608
608
|
const pkgJsonPath = path2__default.default.join(projectRoot, "package.json");
|
|
609
|
-
if (!
|
|
609
|
+
if (!fs4__default.default.existsSync(pkgJsonPath)) {
|
|
610
610
|
return requiredPackages;
|
|
611
611
|
}
|
|
612
612
|
try {
|
|
613
|
-
const pkg = JSON.parse(
|
|
613
|
+
const pkg = JSON.parse(fs4__default.default.readFileSync(pkgJsonPath, "utf-8"));
|
|
614
614
|
const installed = /* @__PURE__ */ new Set([
|
|
615
615
|
...Object.keys(pkg.dependencies || {}),
|
|
616
616
|
...Object.keys(pkg.devDependencies || {}),
|
|
617
617
|
...Object.keys(pkg.peerDependencies || {})
|
|
618
618
|
]);
|
|
619
|
-
return requiredPackages.filter((
|
|
620
|
-
const nameOnly =
|
|
619
|
+
return requiredPackages.filter((p16) => {
|
|
620
|
+
const nameOnly = p16.startsWith("@") ? `@${p16.slice(1).split("@")[0] || ""}` : p16.split("@")[0] || p16;
|
|
621
621
|
return !installed.has(nameOnly);
|
|
622
622
|
});
|
|
623
623
|
} catch {
|
|
@@ -642,15 +642,15 @@ function installNpmPackages(projectRoot, packages, pm) {
|
|
|
642
642
|
installCmd = `npm install ${packages.join(" ")}`;
|
|
643
643
|
break;
|
|
644
644
|
}
|
|
645
|
-
|
|
645
|
+
p4__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"
|
|
649
649
|
});
|
|
650
650
|
}
|
|
651
651
|
function getAllFiles(dir, baseDir = dir) {
|
|
652
|
-
if (!
|
|
653
|
-
const entries =
|
|
652
|
+
if (!fs4__default.default.existsSync(dir)) return [];
|
|
653
|
+
const entries = fs4__default.default.readdirSync(dir, { withFileTypes: true });
|
|
654
654
|
const files = [];
|
|
655
655
|
for (const entry of entries) {
|
|
656
656
|
const fullPath = path2__default.default.join(dir, entry.name);
|
|
@@ -670,13 +670,13 @@ function getAllFiles(dir, baseDir = dir) {
|
|
|
670
670
|
return files.sort();
|
|
671
671
|
}
|
|
672
672
|
function computeDirectoryHash(dirPath, files) {
|
|
673
|
-
if (!
|
|
673
|
+
if (!fs4__default.default.existsSync(dirPath)) return "";
|
|
674
674
|
const hash = crypto.createHash("sha256");
|
|
675
675
|
const fileList = (files ?? getAllFiles(dirPath)).sort();
|
|
676
676
|
for (const relativePath of fileList) {
|
|
677
677
|
const absolutePath = path2__default.default.join(dirPath, relativePath);
|
|
678
|
-
if (!
|
|
679
|
-
const content =
|
|
678
|
+
if (!fs4__default.default.existsSync(absolutePath)) continue;
|
|
679
|
+
const content = fs4__default.default.readFileSync(absolutePath, "utf8");
|
|
680
680
|
const normalizedContent = content.replace(/\r\n/g, "\n");
|
|
681
681
|
hash.update(relativePath);
|
|
682
682
|
hash.update(normalizedContent);
|
|
@@ -699,29 +699,29 @@ hbs.registerHelper("join", (arr, sep) => {
|
|
|
699
699
|
});
|
|
700
700
|
var cachedTemplatesDir = null;
|
|
701
701
|
function getTemplatesDir() {
|
|
702
|
-
if (cachedTemplatesDir &&
|
|
702
|
+
if (cachedTemplatesDir && fs4__default.default.existsSync(cachedTemplatesDir)) {
|
|
703
703
|
return cachedTemplatesDir;
|
|
704
704
|
}
|
|
705
705
|
const currentDir = typeof __dirname !== "undefined" ? __dirname : path2__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))));
|
|
706
706
|
const cand1 = path2__default.default.resolve(currentDir, "../../templates");
|
|
707
|
-
if (
|
|
707
|
+
if (fs4__default.default.existsSync(cand1)) {
|
|
708
708
|
cachedTemplatesDir = cand1;
|
|
709
709
|
return cand1;
|
|
710
710
|
}
|
|
711
711
|
const cand2 = path2__default.default.resolve(currentDir, "../templates");
|
|
712
|
-
if (
|
|
712
|
+
if (fs4__default.default.existsSync(cand2)) {
|
|
713
713
|
cachedTemplatesDir = cand2;
|
|
714
714
|
return cand2;
|
|
715
715
|
}
|
|
716
716
|
const cand3 = path2__default.default.resolve(currentDir, "templates");
|
|
717
|
-
if (
|
|
717
|
+
if (fs4__default.default.existsSync(cand3)) {
|
|
718
718
|
cachedTemplatesDir = cand3;
|
|
719
719
|
return cand3;
|
|
720
720
|
}
|
|
721
721
|
let curr = currentDir;
|
|
722
722
|
while (true) {
|
|
723
723
|
const candTemplates = path2__default.default.join(curr, "templates");
|
|
724
|
-
if (
|
|
724
|
+
if (fs4__default.default.existsSync(candTemplates)) {
|
|
725
725
|
cachedTemplatesDir = candTemplates;
|
|
726
726
|
return candTemplates;
|
|
727
727
|
}
|
|
@@ -734,7 +734,7 @@ function getTemplatesDir() {
|
|
|
734
734
|
var templateCache = /* @__PURE__ */ new Map();
|
|
735
735
|
function loadTemplate(relativePath) {
|
|
736
736
|
const fullPath = path2__default.default.isAbsolute(relativePath) ? relativePath : path2__default.default.join(getTemplatesDir(), relativePath);
|
|
737
|
-
return
|
|
737
|
+
return fs4__default.default.readFileSync(fullPath, "utf-8");
|
|
738
738
|
}
|
|
739
739
|
function renderTemplateFile(relativePath, context) {
|
|
740
740
|
let compiled = templateCache.get(relativePath);
|
|
@@ -844,7 +844,7 @@ function generateInterfaceCode(ifaceName, kind = "abstractClass", entityName, me
|
|
|
844
844
|
const idKey = `${entityKey}Id`;
|
|
845
845
|
const listKey = `${entityKey}s`;
|
|
846
846
|
const formattedCustomMethods = customMethods.map((m) => {
|
|
847
|
-
const params = m.params && m.params.length > 0 ? m.params.map((
|
|
847
|
+
const params = m.params && m.params.length > 0 ? m.params.map((p16) => `${p16.name}: ${p16.type}`).join("; ") : "";
|
|
848
848
|
const returnType = m.returnType ? `Promise<${m.returnType}>` : "Promise<void>";
|
|
849
849
|
return {
|
|
850
850
|
name: m.name,
|
|
@@ -1105,7 +1105,7 @@ function parseInterfaceMethodsAndImports(content, targetIfaceName) {
|
|
|
1105
1105
|
};
|
|
1106
1106
|
}
|
|
1107
1107
|
function findInterfaceFile(projectRoot, ifaceName, featureName, customPath) {
|
|
1108
|
-
if (customPath &&
|
|
1108
|
+
if (customPath && fs4__default.default.existsSync(customPath)) {
|
|
1109
1109
|
return { filePath: customPath, ifaceName };
|
|
1110
1110
|
}
|
|
1111
1111
|
const candidateNames = [
|
|
@@ -1116,21 +1116,21 @@ function findInterfaceFile(projectRoot, ifaceName, featureName, customPath) {
|
|
|
1116
1116
|
const features = featureName ? [featureName, ...listExistingFeatures(projectRoot).filter((f) => f !== featureName)] : listExistingFeatures(projectRoot);
|
|
1117
1117
|
for (const feat of features) {
|
|
1118
1118
|
const domainDir = path2__default.default.join(resolveFeaturesDir(projectRoot), feat, "domain");
|
|
1119
|
-
if (!
|
|
1119
|
+
if (!fs4__default.default.existsSync(domainDir)) continue;
|
|
1120
1120
|
for (const cand of candidateNames) {
|
|
1121
1121
|
const p1 = path2__default.default.join(domainDir, `${cand}.ts`);
|
|
1122
|
-
if (
|
|
1122
|
+
if (fs4__default.default.existsSync(p1)) {
|
|
1123
1123
|
return { filePath: p1, ifaceName: cand, feature: feat };
|
|
1124
1124
|
}
|
|
1125
1125
|
}
|
|
1126
1126
|
}
|
|
1127
1127
|
for (const cand of candidateNames) {
|
|
1128
1128
|
const p1 = path2__default.default.join(projectRoot, "domain", `${cand}.ts`);
|
|
1129
|
-
if (
|
|
1129
|
+
if (fs4__default.default.existsSync(p1)) return { filePath: p1, ifaceName: cand };
|
|
1130
1130
|
const p22 = path2__default.default.join(projectRoot, "src", "domain", `${cand}.ts`);
|
|
1131
|
-
if (
|
|
1131
|
+
if (fs4__default.default.existsSync(p22)) return { filePath: p22, ifaceName: cand };
|
|
1132
1132
|
const p32 = path2__default.default.join(projectRoot, "interfaces", `${cand}.ts`);
|
|
1133
|
-
if (
|
|
1133
|
+
if (fs4__default.default.existsSync(p32)) return { filePath: p32, ifaceName: cand };
|
|
1134
1134
|
}
|
|
1135
1135
|
return null;
|
|
1136
1136
|
}
|
|
@@ -1153,7 +1153,7 @@ function loadInterfaceHierarchy(projectRoot, initialIfaceName, featureName, cust
|
|
|
1153
1153
|
while (currentFile && !visited.has(currentFile)) {
|
|
1154
1154
|
visited.add(currentFile);
|
|
1155
1155
|
try {
|
|
1156
|
-
const content =
|
|
1156
|
+
const content = fs4__default.default.readFileSync(currentFile, "utf-8");
|
|
1157
1157
|
const parsed = parseInterfaceMethodsAndImports(content, currentName);
|
|
1158
1158
|
for (const m of parsed.methods) {
|
|
1159
1159
|
if (!allMethods.some((existing) => existing.name === m.name)) {
|
|
@@ -1425,22 +1425,22 @@ function generateUseCaseCode(useCaseName, dependencies = [], inputProps = [], ou
|
|
|
1425
1425
|
from: /^I[A-Z]/.test(dep) ? `../domain/${dep}.js` : `./${dep}.js`
|
|
1426
1426
|
}));
|
|
1427
1427
|
const domainTypesToImport = new Set(domainImports);
|
|
1428
|
-
for (const
|
|
1429
|
-
const rawType =
|
|
1428
|
+
for (const p16 of [...inputProps, ...outputProps]) {
|
|
1429
|
+
const rawType = p16.type.trim();
|
|
1430
1430
|
const baseType = rawType.replace(/\[\]$/, "").trim();
|
|
1431
1431
|
if (!primitiveTypes.has(baseType) && /^[A-Z][A-Za-z0-9_]*$/.test(baseType) && !dependencies.includes(baseType)) {
|
|
1432
1432
|
domainTypesToImport.add(baseType);
|
|
1433
1433
|
}
|
|
1434
1434
|
}
|
|
1435
|
-
const formattedInputProps = inputProps.map((
|
|
1436
|
-
name:
|
|
1437
|
-
optional:
|
|
1438
|
-
type:
|
|
1435
|
+
const formattedInputProps = inputProps.map((p16) => ({
|
|
1436
|
+
name: p16.name,
|
|
1437
|
+
optional: p16.optional,
|
|
1438
|
+
type: p16.optional && !p16.type.includes("undefined") ? `${p16.type} | undefined` : p16.type
|
|
1439
1439
|
}));
|
|
1440
|
-
const formattedOutputProps = outputProps.map((
|
|
1441
|
-
name:
|
|
1442
|
-
optional:
|
|
1443
|
-
type:
|
|
1440
|
+
const formattedOutputProps = outputProps.map((p16) => ({
|
|
1441
|
+
name: p16.name,
|
|
1442
|
+
optional: p16.optional,
|
|
1443
|
+
type: p16.optional && !p16.type.includes("undefined") ? `${p16.type} | undefined` : p16.type
|
|
1444
1444
|
}));
|
|
1445
1445
|
const formattedDeps = dependencies.map((dep) => ({
|
|
1446
1446
|
key: toCamelCase(dep),
|
|
@@ -1627,7 +1627,7 @@ function generateHttpHandler(options) {
|
|
|
1627
1627
|
const pxDir = path2__default.default.join(resolveFeaturesDir(projectRoot), options.feature, "pxExpress");
|
|
1628
1628
|
const handlersDir = path2__default.default.join(pxDir, "handlers");
|
|
1629
1629
|
const pxIndexPath = path2__default.default.join(pxDir, "index.ts");
|
|
1630
|
-
if (!
|
|
1630
|
+
if (!fs4__default.default.existsSync(pxIndexPath)) {
|
|
1631
1631
|
const featurePath = options.routePrefix || `/${options.feature.toLowerCase()}`;
|
|
1632
1632
|
const pxIndexContent = renderTemplate(expressIndexTemplate, {
|
|
1633
1633
|
routePath: featurePath
|
|
@@ -1664,8 +1664,8 @@ function updateOrGenerateDiProvider(featureDir, featureName, bindings = [], opti
|
|
|
1664
1664
|
const providerPath = path2__default.default.join(featureDir, "diProvider.ts");
|
|
1665
1665
|
const pascalFeature = toPascalCase(featureName);
|
|
1666
1666
|
const providerModuleName = `${pascalFeature}Provider`;
|
|
1667
|
-
if (
|
|
1668
|
-
let content =
|
|
1667
|
+
if (fs4__default.default.existsSync(providerPath) && !options.overwrite) {
|
|
1668
|
+
let content = fs4__default.default.readFileSync(providerPath, "utf-8");
|
|
1669
1669
|
content = content.replace(/\n*export\s+const\s+ScaffoldProvider\s*=[^;]+;?/g, "");
|
|
1670
1670
|
for (const b of bindings) {
|
|
1671
1671
|
const ifaceImp = b.ifaceImportPath || `./domain/${b.ifaceName}.js`;
|
|
@@ -2115,7 +2115,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2115
2115
|
}
|
|
2116
2116
|
if (!name) {
|
|
2117
2117
|
name = handleCancel(
|
|
2118
|
-
await
|
|
2118
|
+
await p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__namespace.confirm({
|
|
2350
2350
|
message: "Generate / update feature DI provider (diProvider.ts)?",
|
|
2351
2351
|
initialValue: true
|
|
2352
2352
|
})
|
|
@@ -2358,8 +2358,8 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2358
2358
|
entityNames = [defaultEntity];
|
|
2359
2359
|
}
|
|
2360
2360
|
}
|
|
2361
|
-
const s =
|
|
2362
|
-
s.start(`Generating feature '${
|
|
2361
|
+
const s = p4__namespace.spinner();
|
|
2362
|
+
s.start(`Generating feature '${pc14__default.default.cyan(normalizedName)}'...`);
|
|
2363
2363
|
const options = {
|
|
2364
2364
|
name: normalizedName,
|
|
2365
2365
|
projectRoot,
|
|
@@ -2381,7 +2381,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2381
2381
|
const files = generateFeature(options);
|
|
2382
2382
|
if (isRegistry) {
|
|
2383
2383
|
const registryPath = path2__default.default.join(targetDir, "registry.json");
|
|
2384
|
-
if (!
|
|
2384
|
+
if (!fs4__default.default.existsSync(registryPath)) {
|
|
2385
2385
|
const manifest = {
|
|
2386
2386
|
name: toKebabCase(normalizedName),
|
|
2387
2387
|
type: "feature",
|
|
@@ -2405,8 +2405,8 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2405
2405
|
}
|
|
2406
2406
|
s.stop("Feature scaffolded successfully!");
|
|
2407
2407
|
printGeneratedFiles(files, options.dryRun);
|
|
2408
|
-
|
|
2409
|
-
|
|
2408
|
+
p4__namespace.outro(
|
|
2409
|
+
pc14__default.default.green(
|
|
2410
2410
|
`\u2713 Feature '${normalizedName}' initialized in ${path2__default.default.relative(projectRoot, targetDir)} (uncommitted, unregistered)`
|
|
2411
2411
|
)
|
|
2412
2412
|
);
|
|
@@ -2520,7 +2520,7 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
|
|
|
2520
2520
|
}
|
|
2521
2521
|
if (!name) {
|
|
2522
2522
|
name = handleCancel(
|
|
2523
|
-
await
|
|
2523
|
+
await p4__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 p4__namespace.text({
|
|
2540
2540
|
message: "Target directory for the shared module:",
|
|
2541
2541
|
initialValue: defaultDir,
|
|
2542
2542
|
defaultValue: defaultDir
|
|
@@ -2548,21 +2548,21 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
|
|
|
2548
2548
|
let includeStub = true;
|
|
2549
2549
|
if (!flags.yes) {
|
|
2550
2550
|
description = handleCancel(
|
|
2551
|
-
await
|
|
2551
|
+
await p4__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 p4__namespace.confirm({
|
|
2559
2559
|
message: "Include stub implementation in infrastructure/?",
|
|
2560
2560
|
initialValue: true
|
|
2561
2561
|
})
|
|
2562
2562
|
);
|
|
2563
2563
|
}
|
|
2564
|
-
const s =
|
|
2565
|
-
s.start(`Generating shared module '${
|
|
2564
|
+
const s = p4__namespace.spinner();
|
|
2565
|
+
s.start(`Generating shared module '${pc14__default.default.cyan(normalizedName)}'...`);
|
|
2566
2566
|
const files = generateShared({
|
|
2567
2567
|
name: normalizedName,
|
|
2568
2568
|
description,
|
|
@@ -2575,8 +2575,8 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
|
|
|
2575
2575
|
});
|
|
2576
2576
|
s.stop("Shared module generated successfully!");
|
|
2577
2577
|
printGeneratedFiles(files, Boolean(flags.dryRun));
|
|
2578
|
-
|
|
2579
|
-
|
|
2578
|
+
p4__namespace.outro(
|
|
2579
|
+
pc14__default.default.green(
|
|
2580
2580
|
`\u2713 Shared module '${normalizedName}' initialized in ${path2__default.default.relative(projectRoot, targetDir)} (uncommitted, unregistered)`
|
|
2581
2581
|
)
|
|
2582
2582
|
);
|
|
@@ -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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__namespace.text({
|
|
2699
2699
|
message: "Route subpath (relative to feature prefix):",
|
|
2700
2700
|
initialValue: "/",
|
|
2701
2701
|
defaultValue: "/"
|
|
@@ -2703,8 +2703,8 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
|
|
|
2703
2703
|
).trim();
|
|
2704
2704
|
}
|
|
2705
2705
|
}
|
|
2706
|
-
const s =
|
|
2707
|
-
s.start(`Generating use case '${
|
|
2706
|
+
const s = p4__namespace.spinner();
|
|
2707
|
+
s.start(`Generating use case '${pc14__default.default.cyan(ucName)}'...`);
|
|
2708
2708
|
const options = {
|
|
2709
2709
|
name: ucName,
|
|
2710
2710
|
feature,
|
|
@@ -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
|
+
p4__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 p4__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 p4__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 p4__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 p4__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 p4__namespace.select({
|
|
2791
2791
|
message: "Select domain model type:",
|
|
2792
2792
|
options: [
|
|
2793
2793
|
{ value: "interface", label: "TypeScript Interface (pure data structure)" },
|
|
@@ -2806,8 +2806,8 @@ async function runDomainCommand(domainNameArg, flags = {}) {
|
|
|
2806
2806
|
defaults: kind === "valueObject" ? [{ name: "value", type: "string" }] : defaultProps
|
|
2807
2807
|
});
|
|
2808
2808
|
}
|
|
2809
|
-
const s =
|
|
2810
|
-
s.start(`Generating domain model '${
|
|
2809
|
+
const s = p4__namespace.spinner();
|
|
2810
|
+
s.start(`Generating domain model '${pc14__default.default.cyan(entityName)}'...`);
|
|
2811
2811
|
const options = {
|
|
2812
2812
|
name: entityName,
|
|
2813
2813
|
feature,
|
|
@@ -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
|
+
p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__namespace.confirm({
|
|
2983
2983
|
message: "Register this implementation in feature diProvider.ts?",
|
|
2984
2984
|
initialValue: true
|
|
2985
2985
|
})
|
|
@@ -2988,8 +2988,8 @@ 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 =
|
|
2992
|
-
s.start(`Generating infrastructure class '${
|
|
2991
|
+
const s = p4__namespace.spinner();
|
|
2992
|
+
s.start(`Generating infrastructure class '${pc14__default.default.cyan(className)}'...`);
|
|
2993
2993
|
const files = [];
|
|
2994
2994
|
const options = {
|
|
2995
2995
|
name: className,
|
|
@@ -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
|
+
p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__namespace.select({
|
|
3116
3116
|
message: "Method signature preset:",
|
|
3117
3117
|
options: [
|
|
3118
3118
|
{ value: "crud", label: "Standard CRUD (GetById, List, Create, Update, Delete)" },
|
|
@@ -3122,22 +3122,22 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
|
3122
3122
|
})
|
|
3123
3123
|
);
|
|
3124
3124
|
generateStub = handleCancel(
|
|
3125
|
-
await
|
|
3125
|
+
await p4__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 p4__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 =
|
|
3140
|
-
s.start(`Generating interface '${
|
|
3139
|
+
const s = p4__namespace.spinner();
|
|
3140
|
+
s.start(`Generating interface '${pc14__default.default.cyan(ifaceName)}'...`);
|
|
3141
3141
|
const files = [];
|
|
3142
3142
|
const options = {
|
|
3143
3143
|
name: ifaceName,
|
|
@@ -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
|
+
p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__namespace.select({
|
|
3292
3292
|
message: "Validation data source:",
|
|
3293
3293
|
options: [
|
|
3294
3294
|
{ value: "body", label: "req.body (for POST / PUT / PATCH payloads)" },
|
|
@@ -3302,8 +3302,8 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
|
|
|
3302
3302
|
});
|
|
3303
3303
|
}
|
|
3304
3304
|
}
|
|
3305
|
-
const s =
|
|
3306
|
-
s.start(`Generating HTTP handler '${
|
|
3305
|
+
const s = p4__namespace.spinner();
|
|
3306
|
+
s.start(`Generating HTTP handler '${pc14__default.default.cyan(className)}'...`);
|
|
3307
3307
|
const options = {
|
|
3308
3308
|
name: className,
|
|
3309
3309
|
feature,
|
|
@@ -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
|
+
p4__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) => ({
|
|
@@ -3331,7 +3331,7 @@ function generateInjectableCode(className, dependencies = [], methods = [], impl
|
|
|
3331
3331
|
const formattedMethods = methods.map((m) => {
|
|
3332
3332
|
const isAsync = m.async !== false;
|
|
3333
3333
|
const retType = m.returnType ? isAsync ? `Promise<${m.returnType}>` : m.returnType : isAsync ? "Promise<void>" : "void";
|
|
3334
|
-
const params = m.params && m.params.length > 0 ? m.params.map((
|
|
3334
|
+
const params = m.params && m.params.length > 0 ? m.params.map((p16) => `${p16.name}: ${p16.type}`).join(", ") : "";
|
|
3335
3335
|
return {
|
|
3336
3336
|
name: m.name,
|
|
3337
3337
|
isAsync,
|
|
@@ -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 p4__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 p4__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 p4__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 p4__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 p4__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 p4__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,14 +3470,14 @@ async function runInjectableCommand(classNameArg, flags = {}) {
|
|
|
3470
3470
|
let generateInterface2 = false;
|
|
3471
3471
|
if (!flags.yes) {
|
|
3472
3472
|
generateInterface2 = handleCancel(
|
|
3473
|
-
await
|
|
3473
|
+
await p4__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 =
|
|
3480
|
-
s.start(`Generating injectable '${
|
|
3479
|
+
const s = p4__namespace.spinner();
|
|
3480
|
+
s.start(`Generating injectable '${pc14__default.default.cyan(className)}'...`);
|
|
3481
3481
|
const options = {
|
|
3482
3482
|
name: className,
|
|
3483
3483
|
feature,
|
|
@@ -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
|
+
p4__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 p4__namespace.select({
|
|
3500
3500
|
message: "What would you like to create in your architecture?",
|
|
3501
3501
|
options: [
|
|
3502
3502
|
{
|
|
@@ -3604,8 +3604,8 @@ async function handleCreate(type, name, flags = {}) {
|
|
|
3604
3604
|
await runInjectableCommand(name, flags);
|
|
3605
3605
|
break;
|
|
3606
3606
|
default:
|
|
3607
|
-
|
|
3608
|
-
|
|
3607
|
+
p4__namespace.log.error(
|
|
3608
|
+
pc14__default.default.red(
|
|
3609
3609
|
`Unknown component type: "${type}". Allowed types: feature, shared, usecase, domain, infrastructure, interface, httpHandler, injectable.`
|
|
3610
3610
|
)
|
|
3611
3611
|
);
|
|
@@ -3613,8 +3613,8 @@ async function handleCreate(type, name, flags = {}) {
|
|
|
3613
3613
|
}
|
|
3614
3614
|
}
|
|
3615
3615
|
var importPrompts = {
|
|
3616
|
-
select:
|
|
3617
|
-
text:
|
|
3616
|
+
select: p4__namespace.select,
|
|
3617
|
+
text: p4__namespace.text
|
|
3618
3618
|
};
|
|
3619
3619
|
function rewriteImports(content, aliasMap) {
|
|
3620
3620
|
if (aliasMap.size === 0) return content;
|
|
@@ -3635,9 +3635,9 @@ function getModuleBaseDir(projectRoot, modType) {
|
|
|
3635
3635
|
function getExistingModuleDir(projectRoot, modType, modName) {
|
|
3636
3636
|
const folder = modType === "shared" ? "shared" : "features";
|
|
3637
3637
|
const inSrc = path2__default.default.join(projectRoot, "src", folder, modName);
|
|
3638
|
-
if (
|
|
3638
|
+
if (fs4__default.default.existsSync(inSrc)) return inSrc;
|
|
3639
3639
|
const inRoot = path2__default.default.join(projectRoot, folder, modName);
|
|
3640
|
-
if (
|
|
3640
|
+
if (fs4__default.default.existsSync(inRoot)) return inRoot;
|
|
3641
3641
|
return null;
|
|
3642
3642
|
}
|
|
3643
3643
|
function checkModuleExists(projectRoot, modType, modName) {
|
|
@@ -3655,13 +3655,13 @@ async function resolveDependency(depType, depName, aliasMap, projectRoot, flags,
|
|
|
3655
3655
|
projectRoot,
|
|
3656
3656
|
path2__default.default.join(baseDir, programmaticAlias)
|
|
3657
3657
|
);
|
|
3658
|
-
|
|
3658
|
+
p4__namespace.log.step(`Importing '${depName}' into '${displayDest}'...`);
|
|
3659
3659
|
await importModuleRecursive(depType, depName, programmaticAlias);
|
|
3660
3660
|
return;
|
|
3661
3661
|
}
|
|
3662
3662
|
const existingDir = getExistingModuleDir(projectRoot, depType, depName);
|
|
3663
3663
|
if (!existingDir) {
|
|
3664
|
-
|
|
3664
|
+
p4__namespace.log.info(` \u21B3 Resolving required ${depType} dependency: ${pc14__default.default.cyan(depName)}`);
|
|
3665
3665
|
await importModuleRecursive(depType, depName, depName);
|
|
3666
3666
|
return;
|
|
3667
3667
|
}
|
|
@@ -3678,25 +3678,25 @@ async function resolveDependency(depType, depName, aliasMap, projectRoot, flags,
|
|
|
3678
3678
|
}
|
|
3679
3679
|
const localHash = computeDirectoryHash(existingDir);
|
|
3680
3680
|
if (remoteIntegrity && localHash === remoteIntegrity) {
|
|
3681
|
-
|
|
3681
|
+
p4__namespace.log.step(`\u2713 ${depType}/${depName} is up to date (reusing existing)`);
|
|
3682
3682
|
importedModules.add(`${depType}:${depName}`);
|
|
3683
3683
|
return;
|
|
3684
3684
|
}
|
|
3685
3685
|
if (flags.overwrite) {
|
|
3686
|
-
|
|
3686
|
+
p4__namespace.log.step(`Overwriting '${depType}/${depName}' with registry version (--overwrite)...`);
|
|
3687
3687
|
const baseDir = getModuleBaseDir(projectRoot, depType);
|
|
3688
3688
|
const targetDir = path2__default.default.join(baseDir, depName);
|
|
3689
3689
|
if (!flags.dryRun) {
|
|
3690
3690
|
if (existingDir !== targetDir) {
|
|
3691
|
-
|
|
3691
|
+
fs4__default.default.rmSync(existingDir, { recursive: true, force: true });
|
|
3692
3692
|
}
|
|
3693
|
-
|
|
3693
|
+
fs4__default.default.rmSync(targetDir, { recursive: true, force: true });
|
|
3694
3694
|
}
|
|
3695
3695
|
await importModuleRecursive(depType, depName, depName, { overwrite: true });
|
|
3696
3696
|
return;
|
|
3697
3697
|
}
|
|
3698
3698
|
if (flags.yes) {
|
|
3699
|
-
|
|
3699
|
+
p4__namespace.log.info(`Using existing '${depType}/${depName}'`);
|
|
3700
3700
|
importedModules.add(`${depType}:${depName}`);
|
|
3701
3701
|
return;
|
|
3702
3702
|
}
|
|
@@ -3720,7 +3720,7 @@ async function resolveDependency(depType, depName, aliasMap, projectRoot, flags,
|
|
|
3720
3720
|
})
|
|
3721
3721
|
);
|
|
3722
3722
|
if (choice === "keep_existing" || choice === "use_existing") {
|
|
3723
|
-
|
|
3723
|
+
p4__namespace.log.step(`Skipping '${depType}/${depName}' (keeping existing)`);
|
|
3724
3724
|
importedModules.add(`${depType}:${depName}`);
|
|
3725
3725
|
return;
|
|
3726
3726
|
}
|
|
@@ -3745,19 +3745,19 @@ async function resolveDependency(depType, depName, aliasMap, projectRoot, flags,
|
|
|
3745
3745
|
aliasMap.set(`@/${folder}/${depName}/`, `@/${folder}/${newName}/`);
|
|
3746
3746
|
const baseDir = getModuleBaseDir(projectRoot, depType);
|
|
3747
3747
|
const displayDest = path2__default.default.relative(projectRoot, path2__default.default.join(baseDir, newName));
|
|
3748
|
-
|
|
3748
|
+
p4__namespace.log.step(`Importing '${depName}' into '${displayDest}'...`);
|
|
3749
3749
|
await importModuleRecursive(depType, depName, newName);
|
|
3750
3750
|
return;
|
|
3751
3751
|
}
|
|
3752
3752
|
if (choice === "overwrite") {
|
|
3753
|
-
|
|
3753
|
+
p4__namespace.log.step(`Overwriting '${depType}/${depName}' with registry version...`);
|
|
3754
3754
|
const baseDir = getModuleBaseDir(projectRoot, depType);
|
|
3755
3755
|
const targetDir = path2__default.default.join(baseDir, depName);
|
|
3756
3756
|
if (!flags.dryRun) {
|
|
3757
3757
|
if (existingDir !== targetDir) {
|
|
3758
|
-
|
|
3758
|
+
fs4__default.default.rmSync(existingDir, { recursive: true, force: true });
|
|
3759
3759
|
}
|
|
3760
|
-
|
|
3760
|
+
fs4__default.default.rmSync(targetDir, { recursive: true, force: true });
|
|
3761
3761
|
}
|
|
3762
3762
|
await importModuleRecursive(depType, depName, depName, { overwrite: true });
|
|
3763
3763
|
return;
|
|
@@ -3787,19 +3787,19 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3787
3787
|
);
|
|
3788
3788
|
}
|
|
3789
3789
|
if (type !== "shared" && type !== "feature") {
|
|
3790
|
-
|
|
3790
|
+
p4__namespace.log.error(pc14__default.default.red(`Invalid module type: "${typeArg}". Must be "shared" or "feature".`));
|
|
3791
3791
|
process.exit(1);
|
|
3792
3792
|
}
|
|
3793
3793
|
const registryBase = getRegistryBase(projectRoot, flags.registry);
|
|
3794
|
-
const s =
|
|
3795
|
-
s.start(`Connecting to registry at ${
|
|
3794
|
+
const s = p4__namespace.spinner();
|
|
3795
|
+
s.start(`Connecting to registry at ${pc14__default.default.dim(registryBase)}...`);
|
|
3796
3796
|
let index;
|
|
3797
3797
|
try {
|
|
3798
3798
|
index = await fetchRegistryIndex(registryBase);
|
|
3799
3799
|
s.stop("Registry index loaded.");
|
|
3800
3800
|
} catch (err) {
|
|
3801
|
-
s.stop(
|
|
3802
|
-
|
|
3801
|
+
s.stop(pc14__default.default.red("Failed to load registry index."));
|
|
3802
|
+
p4__namespace.log.error(pc14__default.default.red(err.message || String(err)));
|
|
3803
3803
|
process.exit(1);
|
|
3804
3804
|
}
|
|
3805
3805
|
const availableList = type === "shared" ? index.shared : index.features;
|
|
@@ -3807,7 +3807,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3807
3807
|
let name = nameArg?.trim();
|
|
3808
3808
|
if (!name) {
|
|
3809
3809
|
if (availableList.length === 0) {
|
|
3810
|
-
|
|
3810
|
+
p4__namespace.log.warn(`No ${type} modules available in the registry.`);
|
|
3811
3811
|
return;
|
|
3812
3812
|
}
|
|
3813
3813
|
name = handleCancel(
|
|
@@ -3823,9 +3823,9 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3823
3823
|
}
|
|
3824
3824
|
if (!candidateNames.includes(name)) {
|
|
3825
3825
|
const closest = findClosestMatch(name, candidateNames);
|
|
3826
|
-
|
|
3826
|
+
p4__namespace.log.error(pc14__default.default.red(`\u274C Module '${name}' not found in the ${type} registry.`));
|
|
3827
3827
|
if (closest) {
|
|
3828
|
-
|
|
3828
|
+
p4__namespace.log.info(pc14__default.default.yellow(`Did you mean '${pc14__default.default.cyan(closest)}'?`));
|
|
3829
3829
|
}
|
|
3830
3830
|
process.exit(1);
|
|
3831
3831
|
}
|
|
@@ -3835,14 +3835,14 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3835
3835
|
async function importModuleRecursive(modType, registryName, targetName = registryName, options) {
|
|
3836
3836
|
const modKey = `${modType}:${targetName}`;
|
|
3837
3837
|
if (importedModules.has(modKey)) return;
|
|
3838
|
-
|
|
3839
|
-
`Importing ${modType}: ${
|
|
3838
|
+
p4__namespace.log.step(
|
|
3839
|
+
`Importing ${modType}: ${pc14__default.default.cyan(targetName)}${targetName !== registryName ? pc14__default.default.dim(` (from ${registryName})`) : ""}...`
|
|
3840
3840
|
);
|
|
3841
3841
|
let manifest;
|
|
3842
3842
|
try {
|
|
3843
3843
|
manifest = await fetchModuleManifest(registryBase, modType, registryName);
|
|
3844
3844
|
} catch (err) {
|
|
3845
|
-
|
|
3845
|
+
p4__namespace.log.error(pc14__default.default.red(`Failed to fetch manifest for ${modType} '${registryName}': ${err.message}`));
|
|
3846
3846
|
process.exit(1);
|
|
3847
3847
|
}
|
|
3848
3848
|
const aliasMap = /* @__PURE__ */ new Map();
|
|
@@ -3888,21 +3888,21 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3888
3888
|
if (file === "registry.json") continue;
|
|
3889
3889
|
const remoteFilePath = `${folder}/${registryName}/${file}`;
|
|
3890
3890
|
const localFilePath = path2__default.default.join(targetDir, file);
|
|
3891
|
-
if (
|
|
3892
|
-
|
|
3893
|
-
` \u21B3 Skipping existing file: ${
|
|
3891
|
+
if (fs4__default.default.existsSync(localFilePath) && !isOverwrite) {
|
|
3892
|
+
p4__namespace.log.warn(
|
|
3893
|
+
` \u21B3 Skipping existing file: ${pc14__default.default.dim(path2__default.default.relative(projectRoot, localFilePath))} (use --overwrite to replace)`
|
|
3894
3894
|
);
|
|
3895
3895
|
continue;
|
|
3896
3896
|
}
|
|
3897
3897
|
let content = await fetchRegistryFile(registryBase, remoteFilePath);
|
|
3898
3898
|
content = rewriteImports(content, aliasMap);
|
|
3899
3899
|
if (!flags.dryRun) {
|
|
3900
|
-
|
|
3901
|
-
|
|
3900
|
+
fs4__default.default.mkdirSync(path2__default.default.dirname(localFilePath), { recursive: true });
|
|
3901
|
+
fs4__default.default.writeFileSync(localFilePath, content, "utf-8");
|
|
3902
3902
|
}
|
|
3903
3903
|
const displayPath = path2__default.default.relative(projectRoot, localFilePath);
|
|
3904
3904
|
totalWrittenFiles.push(displayPath);
|
|
3905
|
-
|
|
3905
|
+
p4__namespace.log.message(` ${pc14__default.default.green("+")} ${displayPath}`);
|
|
3906
3906
|
}
|
|
3907
3907
|
importedModules.add(modKey);
|
|
3908
3908
|
}
|
|
@@ -3910,564 +3910,35 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3910
3910
|
const missingNpm = getMissingNpmPackages(projectRoot, Array.from(requiredNpmPackages));
|
|
3911
3911
|
if (missingNpm.length > 0) {
|
|
3912
3912
|
if (flags.skipInstall || flags.dryRun) {
|
|
3913
|
-
|
|
3913
|
+
p4__namespace.log.info(`Required npm dependencies to install: ${pc14__default.default.cyan(missingNpm.join(", "))}`);
|
|
3914
3914
|
} else {
|
|
3915
3915
|
try {
|
|
3916
3916
|
installNpmPackages(projectRoot, missingNpm);
|
|
3917
3917
|
} catch (err) {
|
|
3918
|
-
|
|
3918
|
+
p4__namespace.log.warn(`Could not automatically install packages (${err.message}). Please run: npm install ${missingNpm.join(" ")}`);
|
|
3919
3919
|
}
|
|
3920
3920
|
}
|
|
3921
3921
|
}
|
|
3922
3922
|
if (flags.dryRun) {
|
|
3923
|
-
|
|
3923
|
+
p4__namespace.log.info(pc14__default.default.yellow("Dry run complete: No files were written to disk."));
|
|
3924
3924
|
} else {
|
|
3925
3925
|
const baseDir = getModuleBaseDir(projectRoot, type);
|
|
3926
3926
|
const displayTarget = path2__default.default.relative(projectRoot, path2__default.default.join(baseDir, name));
|
|
3927
|
-
|
|
3928
|
-
|
|
3927
|
+
p4__namespace.log.success(
|
|
3928
|
+
pc14__default.default.green(
|
|
3929
3929
|
`Successfully imported ${type} '${name}' (${totalWrittenFiles.length} file${totalWrittenFiles.length === 1 ? "" : "s"} placed in ${displayTarget})`
|
|
3930
3930
|
)
|
|
3931
3931
|
);
|
|
3932
3932
|
}
|
|
3933
3933
|
}
|
|
3934
|
-
function loadMasterIndex(projectRoot) {
|
|
3935
|
-
const indexPath = path2__default.default.join(projectRoot, "index.json");
|
|
3936
|
-
if (!fs12__default.default.existsSync(indexPath)) {
|
|
3937
|
-
const initialIndex = { shared: [], features: [] };
|
|
3938
|
-
fs12__default.default.writeFileSync(indexPath, JSON.stringify(initialIndex, null, 2) + "\n", "utf-8");
|
|
3939
|
-
return initialIndex;
|
|
3940
|
-
}
|
|
3941
|
-
return JSON.parse(fs12__default.default.readFileSync(indexPath, "utf-8"));
|
|
3942
|
-
}
|
|
3943
|
-
function saveMasterIndex(projectRoot, index) {
|
|
3944
|
-
const indexPath = path2__default.default.join(projectRoot, "index.json");
|
|
3945
|
-
index.shared.sort((a, b) => a.name.localeCompare(b.name));
|
|
3946
|
-
index.features.sort((a, b) => a.name.localeCompare(b.name));
|
|
3947
|
-
fs12__default.default.writeFileSync(indexPath, JSON.stringify(index, null, 2) + "\n", "utf-8");
|
|
3948
|
-
}
|
|
3949
|
-
function discoverDiskModules(projectRoot) {
|
|
3950
|
-
const results = [];
|
|
3951
|
-
const sharedDir = resolveSharedDir(projectRoot);
|
|
3952
|
-
if (fs12__default.default.existsSync(sharedDir)) {
|
|
3953
|
-
const entries = fs12__default.default.readdirSync(sharedDir, { withFileTypes: true });
|
|
3954
|
-
for (const entry of entries) {
|
|
3955
|
-
if (entry.isDirectory() && !entry.name.startsWith(".")) {
|
|
3956
|
-
results.push({ name: entry.name, type: "shared", dir: path2__default.default.join(sharedDir, entry.name) });
|
|
3957
|
-
}
|
|
3958
|
-
}
|
|
3959
|
-
}
|
|
3960
|
-
const featuresDir = resolveFeaturesDir(projectRoot);
|
|
3961
|
-
if (fs12__default.default.existsSync(featuresDir)) {
|
|
3962
|
-
const entries = fs12__default.default.readdirSync(featuresDir, { withFileTypes: true });
|
|
3963
|
-
for (const entry of entries) {
|
|
3964
|
-
if (entry.isDirectory() && !entry.name.startsWith(".")) {
|
|
3965
|
-
results.push({ name: entry.name, type: "feature", dir: path2__default.default.join(featuresDir, entry.name) });
|
|
3966
|
-
}
|
|
3967
|
-
}
|
|
3968
|
-
}
|
|
3969
|
-
return results;
|
|
3970
|
-
}
|
|
3971
|
-
function checkGitStatusForDir(projectRoot, dirPath) {
|
|
3972
|
-
try {
|
|
3973
|
-
const relPath = path2__default.default.relative(projectRoot, dirPath);
|
|
3974
|
-
const output = child_process.execSync(`git status --porcelain -- "${relPath}"`, {
|
|
3975
|
-
cwd: projectRoot,
|
|
3976
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
3977
|
-
encoding: "utf-8"
|
|
3978
|
-
}).trim();
|
|
3979
|
-
if (!output) {
|
|
3980
|
-
return { hasChanges: false, filesCount: 0 };
|
|
3981
|
-
}
|
|
3982
|
-
const lines = output.split("\n").filter((l) => l.trim().length > 0);
|
|
3983
|
-
return { hasChanges: true, filesCount: lines.length };
|
|
3984
|
-
} catch {
|
|
3985
|
-
return { hasChanges: false, filesCount: 0 };
|
|
3986
|
-
}
|
|
3987
|
-
}
|
|
3988
|
-
function getRegistryDiff(projectRoot) {
|
|
3989
|
-
const index = loadMasterIndex(projectRoot);
|
|
3990
|
-
const diskModules = discoverDiskModules(projectRoot);
|
|
3991
|
-
const diskMap = /* @__PURE__ */ new Map();
|
|
3992
|
-
for (const mod of diskModules) {
|
|
3993
|
-
diskMap.set(`${mod.type}:${mod.name}`, mod);
|
|
3994
|
-
}
|
|
3995
|
-
const allKeys = /* @__PURE__ */ new Set();
|
|
3996
|
-
for (const item of index.shared) {
|
|
3997
|
-
allKeys.add(`shared:${item.name}`);
|
|
3998
|
-
}
|
|
3999
|
-
for (const item of index.features) {
|
|
4000
|
-
allKeys.add(`feature:${item.name}`);
|
|
4001
|
-
}
|
|
4002
|
-
for (const mod of diskModules) {
|
|
4003
|
-
allKeys.add(`${mod.type}:${mod.name}`);
|
|
4004
|
-
}
|
|
4005
|
-
const statuses = [];
|
|
4006
|
-
for (const key of allKeys) {
|
|
4007
|
-
const [typeStr, name] = key.split(":");
|
|
4008
|
-
const type = typeStr;
|
|
4009
|
-
const registeredEntry = (type === "shared" ? index.shared : index.features).find(
|
|
4010
|
-
(e) => e.name === name
|
|
4011
|
-
);
|
|
4012
|
-
const isRegistered = Boolean(registeredEntry);
|
|
4013
|
-
const diskInfo = diskMap.get(key);
|
|
4014
|
-
const existsOnDisk = Boolean(diskInfo && fs12__default.default.existsSync(diskInfo.dir));
|
|
4015
|
-
let hasUncommittedGitChanges = false;
|
|
4016
|
-
let uncommittedFilesCount = 0;
|
|
4017
|
-
let hasIntegrityDrift = false;
|
|
4018
|
-
let localIntegrity;
|
|
4019
|
-
if (existsOnDisk && diskInfo) {
|
|
4020
|
-
const git = checkGitStatusForDir(projectRoot, diskInfo.dir);
|
|
4021
|
-
hasUncommittedGitChanges = git.hasChanges;
|
|
4022
|
-
uncommittedFilesCount = git.filesCount;
|
|
4023
|
-
localIntegrity = computeDirectoryHash(diskInfo.dir);
|
|
4024
|
-
if (isRegistered && registeredEntry?.integrity) {
|
|
4025
|
-
hasIntegrityDrift = localIntegrity !== registeredEntry.integrity;
|
|
4026
|
-
}
|
|
4027
|
-
}
|
|
4028
|
-
statuses.push({
|
|
4029
|
-
name,
|
|
4030
|
-
type,
|
|
4031
|
-
isRegistered,
|
|
4032
|
-
existsOnDisk,
|
|
4033
|
-
hasUncommittedGitChanges,
|
|
4034
|
-
uncommittedFilesCount,
|
|
4035
|
-
hasIntegrityDrift,
|
|
4036
|
-
localIntegrity,
|
|
4037
|
-
registeredIntegrity: registeredEntry?.integrity
|
|
4038
|
-
});
|
|
4039
|
-
}
|
|
4040
|
-
return statuses.sort((a, b) => a.type.localeCompare(b.type) || a.name.localeCompare(b.name));
|
|
4041
|
-
}
|
|
4042
|
-
async function registerModule(typeArg, nameArg, flags = {}) {
|
|
4043
|
-
const projectRoot = findProjectRoot();
|
|
4044
|
-
const index = loadMasterIndex(projectRoot);
|
|
4045
|
-
let type = typeArg?.trim();
|
|
4046
|
-
if (!type) {
|
|
4047
|
-
type = handleCancel(
|
|
4048
|
-
await p15__namespace.select({
|
|
4049
|
-
message: "Module type to register:",
|
|
4050
|
-
options: [
|
|
4051
|
-
{ value: "feature", label: "Feature" },
|
|
4052
|
-
{ value: "shared", label: "Shared Module" }
|
|
4053
|
-
]
|
|
4054
|
-
})
|
|
4055
|
-
);
|
|
4056
|
-
}
|
|
4057
|
-
const diskModules = discoverDiskModules(projectRoot).filter((m) => m.type === type);
|
|
4058
|
-
const registeredNames = new Set((type === "shared" ? index.shared : index.features).map((m) => m.name));
|
|
4059
|
-
const unregistered = diskModules.filter((m) => !registeredNames.has(m.name));
|
|
4060
|
-
let name = nameArg?.trim();
|
|
4061
|
-
if (!name) {
|
|
4062
|
-
if (unregistered.length > 0) {
|
|
4063
|
-
const opts = unregistered.map((m) => ({ value: m.name, label: m.name, hint: "unregistered on disk" }));
|
|
4064
|
-
opts.push({ value: "__custom__", label: "\u270F\uFE0F Enter custom name...", hint: "" });
|
|
4065
|
-
const choice = handleCancel(
|
|
4066
|
-
await p15__namespace.select({
|
|
4067
|
-
message: `Select a ${type} to register:`,
|
|
4068
|
-
options: opts
|
|
4069
|
-
})
|
|
4070
|
-
);
|
|
4071
|
-
if (choice === "__custom__") {
|
|
4072
|
-
name = handleCancel(
|
|
4073
|
-
await p15__namespace.text({
|
|
4074
|
-
message: `Enter ${type} name:`,
|
|
4075
|
-
validate: (v) => v && v.trim() ? void 0 : "Name cannot be empty"
|
|
4076
|
-
})
|
|
4077
|
-
).trim();
|
|
4078
|
-
} else {
|
|
4079
|
-
name = choice;
|
|
4080
|
-
}
|
|
4081
|
-
} else {
|
|
4082
|
-
name = handleCancel(
|
|
4083
|
-
await p15__namespace.text({
|
|
4084
|
-
message: `Enter ${type} name to register:`,
|
|
4085
|
-
validate: (v) => v && v.trim() ? void 0 : "Name cannot be empty"
|
|
4086
|
-
})
|
|
4087
|
-
).trim();
|
|
4088
|
-
}
|
|
4089
|
-
}
|
|
4090
|
-
const folder = type === "shared" ? resolveSharedDir(projectRoot) : resolveFeaturesDir(projectRoot);
|
|
4091
|
-
const modDir = path2__default.default.join(folder, name);
|
|
4092
|
-
if (!fs12__default.default.existsSync(modDir)) {
|
|
4093
|
-
p15__namespace.log.error(pc15__default.default.red(`Module directory does not exist: ${path2__default.default.relative(projectRoot, modDir)}`));
|
|
4094
|
-
process.exit(1);
|
|
4095
|
-
}
|
|
4096
|
-
const files = getAllFiles(modDir);
|
|
4097
|
-
const integrity = computeDirectoryHash(modDir, files);
|
|
4098
|
-
const manifestPath = path2__default.default.join(modDir, "registry.json");
|
|
4099
|
-
let manifest;
|
|
4100
|
-
if (fs12__default.default.existsSync(manifestPath)) {
|
|
4101
|
-
manifest = JSON.parse(fs12__default.default.readFileSync(manifestPath, "utf-8"));
|
|
4102
|
-
} else {
|
|
4103
|
-
manifest = {
|
|
4104
|
-
name,
|
|
4105
|
-
type,
|
|
4106
|
-
description: `${name} ${type} module`,
|
|
4107
|
-
version: "1.0.0",
|
|
4108
|
-
dependencies: {
|
|
4109
|
-
npm: [],
|
|
4110
|
-
shared: [],
|
|
4111
|
-
features: []
|
|
4112
|
-
},
|
|
4113
|
-
files: []
|
|
4114
|
-
};
|
|
4115
|
-
}
|
|
4116
|
-
manifest.name = name;
|
|
4117
|
-
manifest.type = type;
|
|
4118
|
-
manifest.files = files;
|
|
4119
|
-
manifest.integrity = integrity;
|
|
4120
|
-
fs12__default.default.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + "\n", "utf-8");
|
|
4121
|
-
const targetList = type === "shared" ? index.shared : index.features;
|
|
4122
|
-
const existingIdx = targetList.findIndex((item) => item.name === name);
|
|
4123
|
-
if (existingIdx >= 0) {
|
|
4124
|
-
targetList[existingIdx] = {
|
|
4125
|
-
name,
|
|
4126
|
-
description: manifest.description,
|
|
4127
|
-
version: manifest.version,
|
|
4128
|
-
integrity
|
|
4129
|
-
};
|
|
4130
|
-
} else {
|
|
4131
|
-
targetList.push({
|
|
4132
|
-
name,
|
|
4133
|
-
description: manifest.description,
|
|
4134
|
-
version: manifest.version,
|
|
4135
|
-
integrity
|
|
4136
|
-
});
|
|
4137
|
-
}
|
|
4138
|
-
saveMasterIndex(projectRoot, index);
|
|
4139
|
-
p15__namespace.log.success(
|
|
4140
|
-
pc15__default.default.green(
|
|
4141
|
-
`\u2713 Module '${type}/${name}' registered in index.json (${files.length} files, ${integrity.slice(0, 18)}...)`
|
|
4142
|
-
)
|
|
4143
|
-
);
|
|
4144
|
-
}
|
|
4145
|
-
async function commitModule(typeArg, nameArg, flags = {}) {
|
|
4146
|
-
const projectRoot = findProjectRoot();
|
|
4147
|
-
let type = typeArg?.trim();
|
|
4148
|
-
if (!type) {
|
|
4149
|
-
type = handleCancel(
|
|
4150
|
-
await p15__namespace.select({
|
|
4151
|
-
message: "Module type to commit:",
|
|
4152
|
-
options: [
|
|
4153
|
-
{ value: "feature", label: "Feature" },
|
|
4154
|
-
{ value: "shared", label: "Shared Module" }
|
|
4155
|
-
]
|
|
4156
|
-
})
|
|
4157
|
-
);
|
|
4158
|
-
}
|
|
4159
|
-
let name = nameArg?.trim();
|
|
4160
|
-
if (!name) {
|
|
4161
|
-
const diskModules = discoverDiskModules(projectRoot).filter((m) => m.type === type);
|
|
4162
|
-
const opts = diskModules.map((m) => {
|
|
4163
|
-
const git = checkGitStatusForDir(projectRoot, m.dir);
|
|
4164
|
-
return {
|
|
4165
|
-
value: m.name,
|
|
4166
|
-
label: m.name,
|
|
4167
|
-
hint: git.hasChanges ? `${git.filesCount} uncommitted files` : "clean working tree"
|
|
4168
|
-
};
|
|
4169
|
-
});
|
|
4170
|
-
name = handleCancel(
|
|
4171
|
-
await p15__namespace.select({
|
|
4172
|
-
message: `Select ${type} to commit:`,
|
|
4173
|
-
options: opts
|
|
4174
|
-
})
|
|
4175
|
-
);
|
|
4176
|
-
}
|
|
4177
|
-
const folder = type === "shared" ? resolveSharedDir(projectRoot) : resolveFeaturesDir(projectRoot);
|
|
4178
|
-
const modDir = path2__default.default.join(folder, name);
|
|
4179
|
-
if (!fs12__default.default.existsSync(modDir)) {
|
|
4180
|
-
p15__namespace.log.error(pc15__default.default.red(`Module directory does not exist: ${path2__default.default.relative(projectRoot, modDir)}`));
|
|
4181
|
-
process.exit(1);
|
|
4182
|
-
}
|
|
4183
|
-
const relModDir = path2__default.default.relative(projectRoot, modDir);
|
|
4184
|
-
const gitStatus = checkGitStatusForDir(projectRoot, modDir);
|
|
4185
|
-
if (!gitStatus.hasChanges) {
|
|
4186
|
-
p15__namespace.log.warn(pc15__default.default.yellow(`No uncommitted git changes found in '${type}/${name}'.`));
|
|
4187
|
-
return;
|
|
4188
|
-
}
|
|
4189
|
-
let message = flags.message?.trim();
|
|
4190
|
-
if (!message) {
|
|
4191
|
-
message = handleCancel(
|
|
4192
|
-
await p15__namespace.text({
|
|
4193
|
-
message: `Commit message for ${type}/${name}:`,
|
|
4194
|
-
placeholder: `e.g. feat(${name}): update use cases and dependencies`,
|
|
4195
|
-
validate: (v) => v && v.trim() ? void 0 : "Commit message cannot be empty"
|
|
4196
|
-
})
|
|
4197
|
-
).trim();
|
|
4198
|
-
}
|
|
4199
|
-
const s = p15__namespace.spinner();
|
|
4200
|
-
s.start(`Committing '${type}/${name}' to git repository...`);
|
|
4201
|
-
try {
|
|
4202
|
-
child_process.execSync(`git add "${relModDir}"`, { cwd: projectRoot, stdio: ["ignore", "pipe", "pipe"] });
|
|
4203
|
-
child_process.execSync(`git commit -m "${message.replace(/"/g, '\\"')}" -- "${relModDir}"`, {
|
|
4204
|
-
cwd: projectRoot,
|
|
4205
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
4206
|
-
});
|
|
4207
|
-
s.stop(`Changes for '${type}/${name}' committed to git.`);
|
|
4208
|
-
p15__namespace.log.success(pc15__default.default.green(`\u2713 Committed '${type}/${name}': "${message}"`));
|
|
4209
|
-
} catch (err) {
|
|
4210
|
-
s.stop(pc15__default.default.red("Git commit failed."));
|
|
4211
|
-
p15__namespace.log.error(pc15__default.default.red(err.message || String(err)));
|
|
4212
|
-
process.exit(1);
|
|
4213
|
-
}
|
|
4214
|
-
}
|
|
4215
|
-
async function registerModuleChanges(typeArg, nameArg, flags = {}) {
|
|
4216
|
-
const projectRoot = findProjectRoot();
|
|
4217
|
-
const index = loadMasterIndex(projectRoot);
|
|
4218
|
-
let type = typeArg?.trim();
|
|
4219
|
-
if (!type) {
|
|
4220
|
-
type = handleCancel(
|
|
4221
|
-
await p15__namespace.select({
|
|
4222
|
-
message: "Module type to update:",
|
|
4223
|
-
options: [
|
|
4224
|
-
{ value: "feature", label: "Feature" },
|
|
4225
|
-
{ value: "shared", label: "Shared Module" }
|
|
4226
|
-
]
|
|
4227
|
-
})
|
|
4228
|
-
);
|
|
4229
|
-
}
|
|
4230
|
-
let name = nameArg?.trim();
|
|
4231
|
-
if (!name) {
|
|
4232
|
-
const diskModules = discoverDiskModules(projectRoot).filter((m) => m.type === type);
|
|
4233
|
-
const diffs = getRegistryDiff(projectRoot).filter((d) => d.type === type && d.isRegistered);
|
|
4234
|
-
const opts = diskModules.map((m) => {
|
|
4235
|
-
const d = diffs.find((item) => item.name === m.name);
|
|
4236
|
-
return {
|
|
4237
|
-
value: m.name,
|
|
4238
|
-
label: m.name,
|
|
4239
|
-
hint: d?.hasIntegrityDrift ? "drift detected (needs register)" : "up to date"
|
|
4240
|
-
};
|
|
4241
|
-
});
|
|
4242
|
-
name = handleCancel(
|
|
4243
|
-
await p15__namespace.select({
|
|
4244
|
-
message: `Select ${type} to register changes:`,
|
|
4245
|
-
options: opts
|
|
4246
|
-
})
|
|
4247
|
-
);
|
|
4248
|
-
}
|
|
4249
|
-
const folder = type === "shared" ? resolveSharedDir(projectRoot) : resolveFeaturesDir(projectRoot);
|
|
4250
|
-
const modDir = path2__default.default.join(folder, name);
|
|
4251
|
-
if (!fs12__default.default.existsSync(modDir)) {
|
|
4252
|
-
p15__namespace.log.error(pc15__default.default.red(`Module directory does not exist: ${path2__default.default.relative(projectRoot, modDir)}`));
|
|
4253
|
-
process.exit(1);
|
|
4254
|
-
}
|
|
4255
|
-
const files = getAllFiles(modDir);
|
|
4256
|
-
const integrity = computeDirectoryHash(modDir, files);
|
|
4257
|
-
const manifestPath = path2__default.default.join(modDir, "registry.json");
|
|
4258
|
-
let manifest;
|
|
4259
|
-
if (fs12__default.default.existsSync(manifestPath)) {
|
|
4260
|
-
manifest = JSON.parse(fs12__default.default.readFileSync(manifestPath, "utf-8"));
|
|
4261
|
-
} else {
|
|
4262
|
-
manifest = {
|
|
4263
|
-
name,
|
|
4264
|
-
type,
|
|
4265
|
-
description: `${name} ${type} module`,
|
|
4266
|
-
version: "1.0.0",
|
|
4267
|
-
dependencies: { npm: [], shared: [], features: [] },
|
|
4268
|
-
files: []
|
|
4269
|
-
};
|
|
4270
|
-
}
|
|
4271
|
-
manifest.files = files;
|
|
4272
|
-
manifest.integrity = integrity;
|
|
4273
|
-
if (flags.version) {
|
|
4274
|
-
manifest.version = flags.version;
|
|
4275
|
-
}
|
|
4276
|
-
fs12__default.default.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + "\n", "utf-8");
|
|
4277
|
-
const targetList = type === "shared" ? index.shared : index.features;
|
|
4278
|
-
const existingIdx = targetList.findIndex((item) => item.name === name);
|
|
4279
|
-
if (existingIdx >= 0) {
|
|
4280
|
-
targetList[existingIdx] = {
|
|
4281
|
-
name,
|
|
4282
|
-
description: manifest.description,
|
|
4283
|
-
version: manifest.version,
|
|
4284
|
-
integrity
|
|
4285
|
-
};
|
|
4286
|
-
} else {
|
|
4287
|
-
targetList.push({
|
|
4288
|
-
name,
|
|
4289
|
-
description: manifest.description,
|
|
4290
|
-
version: manifest.version,
|
|
4291
|
-
integrity
|
|
4292
|
-
});
|
|
4293
|
-
}
|
|
4294
|
-
saveMasterIndex(projectRoot, index);
|
|
4295
|
-
p15__namespace.log.success(
|
|
4296
|
-
pc15__default.default.green(`\u2713 Registered changes for '${type}/${name}' (new integrity: ${integrity.slice(0, 18)}...)`)
|
|
4297
|
-
);
|
|
4298
|
-
}
|
|
4299
|
-
async function unregisterModule(typeArg, nameArg, flags = {}) {
|
|
4300
|
-
const projectRoot = findProjectRoot();
|
|
4301
|
-
const index = loadMasterIndex(projectRoot);
|
|
4302
|
-
let type = typeArg?.trim();
|
|
4303
|
-
if (!type) {
|
|
4304
|
-
type = handleCancel(
|
|
4305
|
-
await p15__namespace.select({
|
|
4306
|
-
message: "Module type to unregister:",
|
|
4307
|
-
options: [
|
|
4308
|
-
{ value: "feature", label: "Feature" },
|
|
4309
|
-
{ value: "shared", label: "Shared Module" }
|
|
4310
|
-
]
|
|
4311
|
-
})
|
|
4312
|
-
);
|
|
4313
|
-
}
|
|
4314
|
-
const registeredList = type === "shared" ? index.shared : index.features;
|
|
4315
|
-
if (registeredList.length === 0) {
|
|
4316
|
-
p15__namespace.log.warn(`No registered ${type} modules found in index.json.`);
|
|
4317
|
-
return;
|
|
4318
|
-
}
|
|
4319
|
-
let name = nameArg?.trim();
|
|
4320
|
-
if (!name) {
|
|
4321
|
-
name = handleCancel(
|
|
4322
|
-
await p15__namespace.select({
|
|
4323
|
-
message: `Select ${type} to unregister from index.json:`,
|
|
4324
|
-
options: registeredList.map((item) => ({
|
|
4325
|
-
value: item.name,
|
|
4326
|
-
label: item.name,
|
|
4327
|
-
hint: item.description
|
|
4328
|
-
}))
|
|
4329
|
-
})
|
|
4330
|
-
);
|
|
4331
|
-
}
|
|
4332
|
-
if (type === "shared") {
|
|
4333
|
-
index.shared = index.shared.filter((item) => item.name !== name);
|
|
4334
|
-
} else {
|
|
4335
|
-
index.features = index.features.filter((item) => item.name !== name);
|
|
4336
|
-
}
|
|
4337
|
-
saveMasterIndex(projectRoot, index);
|
|
4338
|
-
p15__namespace.log.success(
|
|
4339
|
-
pc15__default.default.green(
|
|
4340
|
-
`\u2713 Unregistered module '${type}/${name}' from index.json (source code retained on disk in ${type === "shared" ? "shared" : "features"}/${name})`
|
|
4341
|
-
)
|
|
4342
|
-
);
|
|
4343
|
-
}
|
|
4344
|
-
function diffRegistry(flags = {}) {
|
|
4345
|
-
const projectRoot = findProjectRoot();
|
|
4346
|
-
const diffs = getRegistryDiff(projectRoot);
|
|
4347
|
-
p15__namespace.log.step(pc15__default.default.bold("\u{1F4CB} Mason Registry Diff & Status Summary"));
|
|
4348
|
-
const unregistered = diffs.filter((d) => d.existsOnDisk && !d.isRegistered);
|
|
4349
|
-
const uncommitted = diffs.filter((d) => d.existsOnDisk && d.hasUncommittedGitChanges);
|
|
4350
|
-
const committedDrift = diffs.filter(
|
|
4351
|
-
(d) => d.existsOnDisk && d.isRegistered && !d.hasUncommittedGitChanges && d.hasIntegrityDrift
|
|
4352
|
-
);
|
|
4353
|
-
const upToDate = diffs.filter(
|
|
4354
|
-
(d) => d.existsOnDisk && d.isRegistered && !d.hasUncommittedGitChanges && !d.hasIntegrityDrift
|
|
4355
|
-
);
|
|
4356
|
-
const missing = diffs.filter((d) => !d.existsOnDisk && d.isRegistered);
|
|
4357
|
-
if (unregistered.length > 0) {
|
|
4358
|
-
p15__namespace.log.message(pc15__default.default.yellow(`
|
|
4359
|
-
\u{1F4E6} Unregistered Modules (${unregistered.length}):`));
|
|
4360
|
-
for (const mod of unregistered) {
|
|
4361
|
-
p15__namespace.log.message(` ${pc15__default.default.red("\u25CF")} ${pc15__default.default.bold(`${mod.type}/${mod.name}`)} ${pc15__default.default.dim("(not registered in index.json)")}`);
|
|
4362
|
-
}
|
|
4363
|
-
}
|
|
4364
|
-
if (uncommitted.length > 0) {
|
|
4365
|
-
p15__namespace.log.message(pc15__default.default.yellow(`
|
|
4366
|
-
\u{1F4BE} Uncommitted Changes in Git (${uncommitted.length}):`));
|
|
4367
|
-
for (const mod of uncommitted) {
|
|
4368
|
-
p15__namespace.log.message(
|
|
4369
|
-
` ${pc15__default.default.yellow("\u25B2")} ${pc15__default.default.bold(`${mod.type}/${mod.name}`)} ${pc15__default.default.dim(`(${mod.uncommittedFilesCount} modified/untracked files)`)}`
|
|
4370
|
-
);
|
|
4371
|
-
}
|
|
4372
|
-
}
|
|
4373
|
-
if (committedDrift.length > 0) {
|
|
4374
|
-
p15__namespace.log.message(pc15__default.default.cyan(`
|
|
4375
|
-
\u{1F680} Committed But Unregistered Changes (${committedDrift.length}):`));
|
|
4376
|
-
for (const mod of committedDrift) {
|
|
4377
|
-
p15__namespace.log.message(
|
|
4378
|
-
` ${pc15__default.default.cyan("\u25C6")} ${pc15__default.default.bold(`${mod.type}/${mod.name}`)} ${pc15__default.default.dim(
|
|
4379
|
-
`local: ${mod.localIntegrity?.slice(0, 16)}... != registered: ${mod.registeredIntegrity?.slice(0, 16)}...`
|
|
4380
|
-
)}`
|
|
4381
|
-
);
|
|
4382
|
-
}
|
|
4383
|
-
}
|
|
4384
|
-
if (missing.length > 0) {
|
|
4385
|
-
p15__namespace.log.message(pc15__default.default.red(`
|
|
4386
|
-
\u26A0\uFE0F Missing on Disk (${missing.length}):`));
|
|
4387
|
-
for (const mod of missing) {
|
|
4388
|
-
p15__namespace.log.message(` ${pc15__default.default.red("\u2715")} ${pc15__default.default.bold(`${mod.type}/${mod.name}`)} ${pc15__default.default.dim("(in index.json, but folder missing)")}`);
|
|
4389
|
-
}
|
|
4390
|
-
}
|
|
4391
|
-
if (upToDate.length > 0) {
|
|
4392
|
-
p15__namespace.log.message(pc15__default.default.green(`
|
|
4393
|
-
\u2713 Up to Date & Registered (${upToDate.length}):`));
|
|
4394
|
-
for (const mod of upToDate) {
|
|
4395
|
-
p15__namespace.log.message(` ${pc15__default.default.green("\u2714")} ${mod.type}/${mod.name} ${pc15__default.default.dim(`(${mod.registeredIntegrity?.slice(0, 18)}...)`)}`);
|
|
4396
|
-
}
|
|
4397
|
-
}
|
|
4398
|
-
p15__namespace.log.message("");
|
|
4399
|
-
}
|
|
4400
|
-
async function handleRegistry(actionArg, typeArg, nameArg, flags = {}) {
|
|
4401
|
-
let action = actionArg?.trim().toLowerCase();
|
|
4402
|
-
if (!action) {
|
|
4403
|
-
action = handleCancel(
|
|
4404
|
-
await p15__namespace.select({
|
|
4405
|
-
message: "\u{1F3DB}\uFE0F Mason Registry: What would you like to do?",
|
|
4406
|
-
options: [
|
|
4407
|
-
{
|
|
4408
|
-
value: "diff",
|
|
4409
|
-
label: "Inspect Diff & Status",
|
|
4410
|
-
hint: "Summary of unregistered, uncommitted, and drifted modules"
|
|
4411
|
-
},
|
|
4412
|
-
{
|
|
4413
|
-
value: "register",
|
|
4414
|
-
label: "Register Module",
|
|
4415
|
-
hint: "Add an existing module to index.json with integrity checksum"
|
|
4416
|
-
},
|
|
4417
|
-
{
|
|
4418
|
-
value: "commit",
|
|
4419
|
-
label: "Commit Changes",
|
|
4420
|
-
hint: "Commit a module's working changes to git in the background"
|
|
4421
|
-
},
|
|
4422
|
-
{
|
|
4423
|
-
value: "register-changes",
|
|
4424
|
-
label: "Register Changes",
|
|
4425
|
-
hint: "Update index.json & registry.json with latest checksums"
|
|
4426
|
-
},
|
|
4427
|
-
{
|
|
4428
|
-
value: "unregister",
|
|
4429
|
-
label: "Unregister Module",
|
|
4430
|
-
hint: "Remove module from index.json (source code stays on disk)"
|
|
4431
|
-
}
|
|
4432
|
-
]
|
|
4433
|
-
})
|
|
4434
|
-
);
|
|
4435
|
-
}
|
|
4436
|
-
switch (action) {
|
|
4437
|
-
case "diff":
|
|
4438
|
-
case "status":
|
|
4439
|
-
diffRegistry(flags);
|
|
4440
|
-
break;
|
|
4441
|
-
case "register":
|
|
4442
|
-
await registerModule(typeArg, nameArg, flags);
|
|
4443
|
-
break;
|
|
4444
|
-
case "commit":
|
|
4445
|
-
await commitModule(typeArg, nameArg, flags);
|
|
4446
|
-
break;
|
|
4447
|
-
case "register-changes":
|
|
4448
|
-
case "update":
|
|
4449
|
-
await registerModuleChanges(typeArg, nameArg, flags);
|
|
4450
|
-
break;
|
|
4451
|
-
case "unregister":
|
|
4452
|
-
await unregisterModule(typeArg, nameArg, flags);
|
|
4453
|
-
break;
|
|
4454
|
-
default:
|
|
4455
|
-
p15__namespace.log.error(
|
|
4456
|
-
pc15__default.default.red(
|
|
4457
|
-
`Unknown registry action: "${action}". Valid actions: diff, register, commit, register-changes, unregister.`
|
|
4458
|
-
)
|
|
4459
|
-
);
|
|
4460
|
-
process.exit(1);
|
|
4461
|
-
}
|
|
4462
|
-
}
|
|
4463
3934
|
|
|
4464
3935
|
// src/cli.ts
|
|
4465
3936
|
function createCli() {
|
|
4466
3937
|
const cli = cac.cac("mason");
|
|
4467
3938
|
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) => {
|
|
4468
3939
|
if (args && args.length > 0) {
|
|
4469
|
-
|
|
4470
|
-
|
|
3940
|
+
p4__namespace.log.error(
|
|
3941
|
+
pc14__default.default.red(
|
|
4471
3942
|
`Unknown command: "${args.join(" ")}". Use --help to list available commands.`
|
|
4472
3943
|
)
|
|
4473
3944
|
);
|
|
@@ -4478,14 +3949,9 @@ function createCli() {
|
|
|
4478
3949
|
const mode = getEffectiveMode(projectRoot, flags);
|
|
4479
3950
|
if (mode === "registry") {
|
|
4480
3951
|
const choice2 = handleCancel(
|
|
4481
|
-
await
|
|
4482
|
-
message: "\u{1F3DB}\uFE0F Mason Registry
|
|
3952
|
+
await p4__namespace.select({
|
|
3953
|
+
message: "\u{1F3DB}\uFE0F Mason (Registry Mode): What would you like to scaffold?",
|
|
4483
3954
|
options: [
|
|
4484
|
-
{
|
|
4485
|
-
value: "diff",
|
|
4486
|
-
label: "Inspect Diff & Status",
|
|
4487
|
-
hint: "Overview of unregistered, uncommitted, or drifted modules"
|
|
4488
|
-
},
|
|
4489
3955
|
{
|
|
4490
3956
|
value: "create_feature",
|
|
4491
3957
|
label: "Initialize New Feature",
|
|
@@ -4501,26 +3967,6 @@ function createCli() {
|
|
|
4501
3967
|
label: "Create New Use Case",
|
|
4502
3968
|
hint: "Add a new use case to an existing feature"
|
|
4503
3969
|
},
|
|
4504
|
-
{
|
|
4505
|
-
value: "register",
|
|
4506
|
-
label: "Register Module",
|
|
4507
|
-
hint: "Add a module to index.json with integrity checksum"
|
|
4508
|
-
},
|
|
4509
|
-
{
|
|
4510
|
-
value: "commit",
|
|
4511
|
-
label: "Commit Module Changes",
|
|
4512
|
-
hint: "Commit working changes in a module to git"
|
|
4513
|
-
},
|
|
4514
|
-
{
|
|
4515
|
-
value: "register_changes",
|
|
4516
|
-
label: "Register Changes",
|
|
4517
|
-
hint: "Recompute checksums and update index.json"
|
|
4518
|
-
},
|
|
4519
|
-
{
|
|
4520
|
-
value: "unregister",
|
|
4521
|
-
label: "Unregister Module",
|
|
4522
|
-
hint: "Remove from index.json but keep source on disk"
|
|
4523
|
-
},
|
|
4524
3970
|
{
|
|
4525
3971
|
value: "import",
|
|
4526
3972
|
label: "Import from Remote Registry",
|
|
@@ -4530,9 +3976,6 @@ function createCli() {
|
|
|
4530
3976
|
})
|
|
4531
3977
|
);
|
|
4532
3978
|
switch (choice2) {
|
|
4533
|
-
case "diff":
|
|
4534
|
-
await handleRegistry("diff", void 0, void 0, flags);
|
|
4535
|
-
break;
|
|
4536
3979
|
case "create_feature":
|
|
4537
3980
|
await handleCreate("feature", void 0, flags);
|
|
4538
3981
|
break;
|
|
@@ -4542,18 +3985,6 @@ function createCli() {
|
|
|
4542
3985
|
case "create_usecase":
|
|
4543
3986
|
await handleCreate("usecase", void 0, flags);
|
|
4544
3987
|
break;
|
|
4545
|
-
case "register":
|
|
4546
|
-
await handleRegistry("register", void 0, void 0, flags);
|
|
4547
|
-
break;
|
|
4548
|
-
case "commit":
|
|
4549
|
-
await handleRegistry("commit", void 0, void 0, flags);
|
|
4550
|
-
break;
|
|
4551
|
-
case "register_changes":
|
|
4552
|
-
await handleRegistry("register-changes", void 0, void 0, flags);
|
|
4553
|
-
break;
|
|
4554
|
-
case "unregister":
|
|
4555
|
-
await handleRegistry("unregister", void 0, void 0, flags);
|
|
4556
|
-
break;
|
|
4557
3988
|
case "import":
|
|
4558
3989
|
await handleImport(void 0, void 0, flags);
|
|
4559
3990
|
break;
|
|
@@ -4561,31 +3992,24 @@ function createCli() {
|
|
|
4561
3992
|
return;
|
|
4562
3993
|
}
|
|
4563
3994
|
const choice = handleCancel(
|
|
4564
|
-
await
|
|
3995
|
+
await p4__namespace.select({
|
|
4565
3996
|
message: "\u{1F9F1} Mason: What would you like to do?",
|
|
4566
3997
|
options: [
|
|
4567
3998
|
{
|
|
4568
3999
|
value: "create",
|
|
4569
|
-
label: "Create
|
|
4000
|
+
label: "Create component",
|
|
4570
4001
|
hint: "Scaffold a new feature, shared module, use case, domain entity, etc."
|
|
4571
4002
|
},
|
|
4572
4003
|
{
|
|
4573
4004
|
value: "import",
|
|
4574
4005
|
label: "Import from registry",
|
|
4575
4006
|
hint: "Download and link pre-built shared modules or features from the registry"
|
|
4576
|
-
},
|
|
4577
|
-
{
|
|
4578
|
-
value: "registry",
|
|
4579
|
-
label: "Registry management",
|
|
4580
|
-
hint: "Inspect diff, register modules, or commit module changes"
|
|
4581
4007
|
}
|
|
4582
4008
|
]
|
|
4583
4009
|
})
|
|
4584
4010
|
);
|
|
4585
4011
|
if (choice === "create") {
|
|
4586
4012
|
await handleCreate(void 0, void 0, flags);
|
|
4587
|
-
} else if (choice === "registry") {
|
|
4588
|
-
await handleRegistry(void 0, void 0, void 0, flags);
|
|
4589
4013
|
} else {
|
|
4590
4014
|
await handleImport(void 0, void 0, flags);
|
|
4591
4015
|
}
|
|
@@ -4613,25 +4037,6 @@ function createCli() {
|
|
|
4613
4037
|
handleCliError(err);
|
|
4614
4038
|
}
|
|
4615
4039
|
});
|
|
4616
|
-
cli.command(
|
|
4617
|
-
"registry [action] [type] [name]",
|
|
4618
|
-
"Registry & version management (diff, register, commit, register-changes, unregister)"
|
|
4619
|
-
).option("-m, --message <message>", "Commit message for 'commit' command").option("-y, --yes", "Accept defaults and skip interactive prompts").example("mason registry diff").example("mason registry register feature authn").example("mason registry commit shared hasher -m 'Add bcrypt engine'").example("mason registry register-changes shared hasher").example("mason registry unregister feature oldFeature").action(
|
|
4620
|
-
async (action, type, name, flags = {}) => {
|
|
4621
|
-
try {
|
|
4622
|
-
await handleRegistry(action, type, name, flags);
|
|
4623
|
-
} catch (err) {
|
|
4624
|
-
handleCliError(err);
|
|
4625
|
-
}
|
|
4626
|
-
}
|
|
4627
|
-
);
|
|
4628
|
-
cli.command("diff", "Inspect registry status and diff (alias for 'mason registry diff')").allowUnknownOptions().action(async (flags = {}) => {
|
|
4629
|
-
try {
|
|
4630
|
-
await handleRegistry("diff", void 0, void 0, flags);
|
|
4631
|
-
} catch (err) {
|
|
4632
|
-
handleCliError(err);
|
|
4633
|
-
}
|
|
4634
|
-
});
|
|
4635
4040
|
const createSubtypes = [
|
|
4636
4041
|
"feature",
|
|
4637
4042
|
"shared",
|
|
@@ -4655,7 +4060,7 @@ function createCli() {
|
|
|
4655
4060
|
});
|
|
4656
4061
|
}
|
|
4657
4062
|
cli.help();
|
|
4658
|
-
cli.version("1.0.
|
|
4063
|
+
cli.version("1.0.14");
|
|
4659
4064
|
return cli;
|
|
4660
4065
|
}
|
|
4661
4066
|
function handleCliError(err) {
|
|
@@ -4663,7 +4068,7 @@ function handleCliError(err) {
|
|
|
4663
4068
|
process.exit(0);
|
|
4664
4069
|
}
|
|
4665
4070
|
const message = err instanceof Error ? err.message : String(err);
|
|
4666
|
-
|
|
4071
|
+
p4__namespace.log.error(pc14__default.default.red(`Error: ${message}`));
|
|
4667
4072
|
process.exit(1);
|
|
4668
4073
|
}
|
|
4669
4074
|
async function runCli(argv = process.argv) {
|
|
@@ -4716,7 +4121,6 @@ exports.getTemplatesDir = getTemplatesDir;
|
|
|
4716
4121
|
exports.handleCancel = handleCancel;
|
|
4717
4122
|
exports.handleCreate = handleCreate;
|
|
4718
4123
|
exports.handleImport = handleImport;
|
|
4719
|
-
exports.handleRegistry = handleRegistry;
|
|
4720
4124
|
exports.hbs = hbs;
|
|
4721
4125
|
exports.httpHandlerTemplate = httpHandlerTemplate;
|
|
4722
4126
|
exports.injectableInterfaceTemplate = injectableInterfaceTemplate;
|