@solid-stack/mason 1.0.25 → 1.0.26
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 +351 -285
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +348 -282
- package/dist/bin.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/commands/envExamples.d.ts +3 -0
- package/dist/commands/envExamples.d.ts.map +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/menu.d.ts.map +1 -1
- package/dist/index.cjs +276 -209
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +274 -208
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/bin.cjs
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var cac = require('cac');
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
var
|
|
5
|
+
var p16 = require('@clack/prompts');
|
|
6
|
+
var pc16 = require('picocolors');
|
|
7
|
+
var fs11 = require('fs');
|
|
8
8
|
var path2 = require('path');
|
|
9
9
|
var url = require('url');
|
|
10
10
|
var Handlebars = require('handlebars');
|
|
@@ -32,16 +32,16 @@ function _interopNamespace(e) {
|
|
|
32
32
|
return Object.freeze(n);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
var
|
|
36
|
-
var
|
|
37
|
-
var
|
|
35
|
+
var p16__namespace = /*#__PURE__*/_interopNamespace(p16);
|
|
36
|
+
var pc16__default = /*#__PURE__*/_interopDefault(pc16);
|
|
37
|
+
var fs11__default = /*#__PURE__*/_interopDefault(fs11);
|
|
38
38
|
var path2__default = /*#__PURE__*/_interopDefault(path2);
|
|
39
39
|
var Handlebars__default = /*#__PURE__*/_interopDefault(Handlebars);
|
|
40
40
|
|
|
41
41
|
function writeFileSafely(absolutePath, content, options = {}) {
|
|
42
42
|
const projectRoot = options.projectRoot || process.cwd();
|
|
43
43
|
const relPath = path2__default.default.relative(projectRoot, absolutePath).replace(/\\/g, "/");
|
|
44
|
-
const existedBefore =
|
|
44
|
+
const existedBefore = fs11__default.default.existsSync(absolutePath);
|
|
45
45
|
if (options.dryRun) {
|
|
46
46
|
return {
|
|
47
47
|
relativePath: relPath,
|
|
@@ -61,10 +61,10 @@ function writeFileSafely(absolutePath, content, options = {}) {
|
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
63
|
const dir = path2__default.default.dirname(absolutePath);
|
|
64
|
-
if (!
|
|
65
|
-
|
|
64
|
+
if (!fs11__default.default.existsSync(dir)) {
|
|
65
|
+
fs11__default.default.mkdirSync(dir, { recursive: true });
|
|
66
66
|
}
|
|
67
|
-
|
|
67
|
+
fs11__default.default.writeFileSync(absolutePath, content, "utf-8");
|
|
68
68
|
return {
|
|
69
69
|
relativePath: relPath,
|
|
70
70
|
absolutePath,
|
|
@@ -76,17 +76,17 @@ function writeFileSafely(absolutePath, content, options = {}) {
|
|
|
76
76
|
function printGeneratedFiles(files, isDryRun = false) {
|
|
77
77
|
console.log("");
|
|
78
78
|
if (isDryRun) {
|
|
79
|
-
|
|
79
|
+
p16__namespace.log.warn(pc16__default.default.yellow(pc16__default.default.bold("[DRY RUN PREVIEW] No files were written to disk.")));
|
|
80
80
|
}
|
|
81
81
|
for (const f of files) {
|
|
82
82
|
if (f.action === "created") {
|
|
83
|
-
|
|
83
|
+
p16__namespace.log.success(`${pc16__default.default.bold(f.relativePath)} ${pc16__default.default.dim("(created)")}`);
|
|
84
84
|
} else if (f.action === "overwritten") {
|
|
85
|
-
|
|
85
|
+
p16__namespace.log.warn(`${pc16__default.default.bold(f.relativePath)} ${pc16__default.default.dim("(overwritten)")}`);
|
|
86
86
|
} else if (f.action === "skipped") {
|
|
87
|
-
|
|
87
|
+
p16__namespace.log.info(`${pc16__default.default.dim(f.relativePath)} ${pc16__default.default.dim("(skipped - already exists, pass -o to overwrite)")}`);
|
|
88
88
|
} else {
|
|
89
|
-
|
|
89
|
+
p16__namespace.log.info(`${pc16__default.default.bold(f.relativePath)} ${pc16__default.default.dim("(preview)")}`);
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
}
|
|
@@ -158,9 +158,9 @@ function loadMasonConfig(startDir = process.cwd()) {
|
|
|
158
158
|
let current = path2__default.default.resolve(startDir);
|
|
159
159
|
while (true) {
|
|
160
160
|
const configPath = path2__default.default.join(current, "mason.config.json");
|
|
161
|
-
if (
|
|
161
|
+
if (fs11__default.default.existsSync(configPath)) {
|
|
162
162
|
try {
|
|
163
|
-
return JSON.parse(
|
|
163
|
+
return JSON.parse(fs11__default.default.readFileSync(configPath, "utf-8"));
|
|
164
164
|
} catch {
|
|
165
165
|
return null;
|
|
166
166
|
}
|
|
@@ -175,7 +175,7 @@ function getEffectiveMode(projectRoot, flags) {
|
|
|
175
175
|
if (flags?.registry) return "registry";
|
|
176
176
|
const config = loadMasonConfig(projectRoot);
|
|
177
177
|
if (config?.mode) return config.mode;
|
|
178
|
-
if (
|
|
178
|
+
if (fs11__default.default.existsSync(path2__default.default.join(projectRoot, "index.json")) && (fs11__default.default.existsSync(path2__default.default.join(projectRoot, "features")) || fs11__default.default.existsSync(path2__default.default.join(projectRoot, "shared")) || fs11__default.default.existsSync(path2__default.default.join(projectRoot, "src/features")) || fs11__default.default.existsSync(path2__default.default.join(projectRoot, "src/shared")))) {
|
|
179
179
|
return "registry";
|
|
180
180
|
}
|
|
181
181
|
return "app";
|
|
@@ -189,12 +189,12 @@ function getConfiguredFeaturesDir(projectRoot, flags) {
|
|
|
189
189
|
}
|
|
190
190
|
const mode = getEffectiveMode(projectRoot, flags);
|
|
191
191
|
if (mode === "registry") {
|
|
192
|
-
if (
|
|
192
|
+
if (fs11__default.default.existsSync(path2__default.default.join(projectRoot, "src/features"))) {
|
|
193
193
|
return path2__default.default.join(projectRoot, "src/features");
|
|
194
194
|
}
|
|
195
195
|
return path2__default.default.join(projectRoot, "features");
|
|
196
196
|
}
|
|
197
|
-
if (
|
|
197
|
+
if (fs11__default.default.existsSync(path2__default.default.join(projectRoot, "src/features"))) {
|
|
198
198
|
return path2__default.default.join(projectRoot, "src/features");
|
|
199
199
|
}
|
|
200
200
|
return path2__default.default.join(projectRoot, "features");
|
|
@@ -208,12 +208,12 @@ function getConfiguredSharedDir(projectRoot, flags) {
|
|
|
208
208
|
}
|
|
209
209
|
const mode = getEffectiveMode(projectRoot, flags);
|
|
210
210
|
if (mode === "registry") {
|
|
211
|
-
if (
|
|
211
|
+
if (fs11__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");
|
|
215
215
|
}
|
|
216
|
-
if (
|
|
216
|
+
if (fs11__default.default.existsSync(path2__default.default.join(projectRoot, "src/shared"))) {
|
|
217
217
|
return path2__default.default.join(projectRoot, "src/shared");
|
|
218
218
|
}
|
|
219
219
|
return path2__default.default.join(projectRoot, "shared");
|
|
@@ -223,7 +223,7 @@ function getConfiguredSharedDir(projectRoot, flags) {
|
|
|
223
223
|
function findProjectRoot(startDir = process.cwd()) {
|
|
224
224
|
let current = path2__default.default.resolve(startDir);
|
|
225
225
|
while (true) {
|
|
226
|
-
if (
|
|
226
|
+
if (fs11__default.default.existsSync(path2__default.default.join(current, "package.json"))) {
|
|
227
227
|
return current;
|
|
228
228
|
}
|
|
229
229
|
const parent = path2__default.default.dirname(current);
|
|
@@ -241,9 +241,9 @@ function resolveSharedDir(projectRoot, flags) {
|
|
|
241
241
|
}
|
|
242
242
|
function listExistingFeatures(projectRoot) {
|
|
243
243
|
const featuresDir = resolveFeaturesDir(projectRoot);
|
|
244
|
-
if (!
|
|
244
|
+
if (!fs11__default.default.existsSync(featuresDir)) return [];
|
|
245
245
|
try {
|
|
246
|
-
const entries =
|
|
246
|
+
const entries = fs11__default.default.readdirSync(featuresDir, { withFileTypes: true });
|
|
247
247
|
return entries.filter((e) => e.isDirectory()).map((e) => e.name).sort();
|
|
248
248
|
} catch {
|
|
249
249
|
return [];
|
|
@@ -254,9 +254,9 @@ function listDomainInterfaces(projectRoot, featureName) {
|
|
|
254
254
|
const features = featureName ? [featureName] : listExistingFeatures(projectRoot);
|
|
255
255
|
for (const feat of features) {
|
|
256
256
|
const domainDir = path2__default.default.join(resolveFeaturesDir(projectRoot), feat, "domain");
|
|
257
|
-
if (!
|
|
257
|
+
if (!fs11__default.default.existsSync(domainDir)) continue;
|
|
258
258
|
try {
|
|
259
|
-
const files =
|
|
259
|
+
const files = fs11__default.default.readdirSync(domainDir);
|
|
260
260
|
for (const file of files) {
|
|
261
261
|
if (file.endsWith(".ts") && !file.endsWith(".test.ts") && !file.endsWith(".d.ts")) {
|
|
262
262
|
const name = file.replace(/\.ts$/, "");
|
|
@@ -269,7 +269,7 @@ function listDomainInterfaces(projectRoot, featureName) {
|
|
|
269
269
|
});
|
|
270
270
|
} else {
|
|
271
271
|
try {
|
|
272
|
-
const content =
|
|
272
|
+
const content = fs11__default.default.readFileSync(fullPath, "utf-8");
|
|
273
273
|
if (/export\s+(?:abstract\s+class|interface)\s+(\w+)/.test(content)) {
|
|
274
274
|
results.push({
|
|
275
275
|
name,
|
|
@@ -292,9 +292,9 @@ function listDomainEntities(projectRoot, featureName) {
|
|
|
292
292
|
const features = featureName ? [featureName] : listExistingFeatures(projectRoot);
|
|
293
293
|
for (const feat of features) {
|
|
294
294
|
const domainDir = path2__default.default.join(resolveFeaturesDir(projectRoot), feat, "domain");
|
|
295
|
-
if (!
|
|
295
|
+
if (!fs11__default.default.existsSync(domainDir)) continue;
|
|
296
296
|
try {
|
|
297
|
-
const files =
|
|
297
|
+
const files = fs11__default.default.readdirSync(domainDir);
|
|
298
298
|
for (const file of files) {
|
|
299
299
|
if (file.endsWith(".ts") && !file.endsWith(".test.ts") && !file.endsWith(".d.ts")) {
|
|
300
300
|
const name = file.replace(/\.ts$/, "");
|
|
@@ -317,9 +317,9 @@ function listUseCases(projectRoot, featureName) {
|
|
|
317
317
|
const features = featureName ? [featureName] : listExistingFeatures(projectRoot);
|
|
318
318
|
for (const feat of features) {
|
|
319
319
|
const useCasesDir = path2__default.default.join(resolveFeaturesDir(projectRoot), feat, "useCases");
|
|
320
|
-
if (!
|
|
320
|
+
if (!fs11__default.default.existsSync(useCasesDir)) continue;
|
|
321
321
|
try {
|
|
322
|
-
const files =
|
|
322
|
+
const files = fs11__default.default.readdirSync(useCasesDir);
|
|
323
323
|
for (const file of files) {
|
|
324
324
|
if (file.endsWith(".ts") && !file.endsWith(".test.ts") && !file.endsWith(".d.ts")) {
|
|
325
325
|
const name = file.replace(/\.ts$/, "");
|
|
@@ -351,29 +351,29 @@ hbs.registerHelper("join", (arr, sep) => {
|
|
|
351
351
|
});
|
|
352
352
|
var cachedTemplatesDir = null;
|
|
353
353
|
function getTemplatesDir() {
|
|
354
|
-
if (cachedTemplatesDir &&
|
|
354
|
+
if (cachedTemplatesDir && fs11__default.default.existsSync(cachedTemplatesDir)) {
|
|
355
355
|
return cachedTemplatesDir;
|
|
356
356
|
}
|
|
357
357
|
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('bin.cjs', document.baseURI).href))));
|
|
358
358
|
const cand1 = path2__default.default.resolve(currentDir, "../../templates");
|
|
359
|
-
if (
|
|
359
|
+
if (fs11__default.default.existsSync(cand1)) {
|
|
360
360
|
cachedTemplatesDir = cand1;
|
|
361
361
|
return cand1;
|
|
362
362
|
}
|
|
363
363
|
const cand2 = path2__default.default.resolve(currentDir, "../templates");
|
|
364
|
-
if (
|
|
364
|
+
if (fs11__default.default.existsSync(cand2)) {
|
|
365
365
|
cachedTemplatesDir = cand2;
|
|
366
366
|
return cand2;
|
|
367
367
|
}
|
|
368
368
|
const cand3 = path2__default.default.resolve(currentDir, "templates");
|
|
369
|
-
if (
|
|
369
|
+
if (fs11__default.default.existsSync(cand3)) {
|
|
370
370
|
cachedTemplatesDir = cand3;
|
|
371
371
|
return cand3;
|
|
372
372
|
}
|
|
373
373
|
let curr = currentDir;
|
|
374
374
|
while (true) {
|
|
375
375
|
const candTemplates = path2__default.default.join(curr, "templates");
|
|
376
|
-
if (
|
|
376
|
+
if (fs11__default.default.existsSync(candTemplates)) {
|
|
377
377
|
cachedTemplatesDir = candTemplates;
|
|
378
378
|
return candTemplates;
|
|
379
379
|
}
|
|
@@ -386,7 +386,7 @@ function getTemplatesDir() {
|
|
|
386
386
|
var templateCache = /* @__PURE__ */ new Map();
|
|
387
387
|
function loadTemplate(relativePath) {
|
|
388
388
|
const fullPath = path2__default.default.isAbsolute(relativePath) ? relativePath : path2__default.default.join(getTemplatesDir(), relativePath);
|
|
389
|
-
return
|
|
389
|
+
return fs11__default.default.readFileSync(fullPath, "utf-8");
|
|
390
390
|
}
|
|
391
391
|
function renderTemplateFile(relativePath, context) {
|
|
392
392
|
let compiled = templateCache.get(relativePath);
|
|
@@ -498,7 +498,7 @@ function generateInterfaceCode(ifaceName, kind = "abstractClass", entityName, me
|
|
|
498
498
|
const idKey = `${entityKey}Id`;
|
|
499
499
|
const listKey = `${entityKey}s`;
|
|
500
500
|
const formattedCustomMethods = customMethods.map((m) => {
|
|
501
|
-
const params = m.params && m.params.length > 0 ? m.params.map((
|
|
501
|
+
const params = m.params && m.params.length > 0 ? m.params.map((p19) => `${p19.name}: ${p19.type}`).join("; ") : "";
|
|
502
502
|
const returnType = m.returnType ? `Promise<${m.returnType}>` : "Promise<void>";
|
|
503
503
|
return {
|
|
504
504
|
name: m.name,
|
|
@@ -759,7 +759,7 @@ function parseInterfaceMethodsAndImports(content, targetIfaceName) {
|
|
|
759
759
|
};
|
|
760
760
|
}
|
|
761
761
|
function findInterfaceFile(projectRoot, ifaceName, featureName, customPath) {
|
|
762
|
-
if (customPath &&
|
|
762
|
+
if (customPath && fs11__default.default.existsSync(customPath)) {
|
|
763
763
|
return { filePath: customPath, ifaceName };
|
|
764
764
|
}
|
|
765
765
|
const candidateNames = [
|
|
@@ -770,21 +770,21 @@ function findInterfaceFile(projectRoot, ifaceName, featureName, customPath) {
|
|
|
770
770
|
const features = featureName ? [featureName, ...listExistingFeatures(projectRoot).filter((f) => f !== featureName)] : listExistingFeatures(projectRoot);
|
|
771
771
|
for (const feat of features) {
|
|
772
772
|
const domainDir = path2__default.default.join(resolveFeaturesDir(projectRoot), feat, "domain");
|
|
773
|
-
if (!
|
|
773
|
+
if (!fs11__default.default.existsSync(domainDir)) continue;
|
|
774
774
|
for (const cand of candidateNames) {
|
|
775
775
|
const p1 = path2__default.default.join(domainDir, `${cand}.ts`);
|
|
776
|
-
if (
|
|
776
|
+
if (fs11__default.default.existsSync(p1)) {
|
|
777
777
|
return { filePath: p1, ifaceName: cand, feature: feat };
|
|
778
778
|
}
|
|
779
779
|
}
|
|
780
780
|
}
|
|
781
781
|
for (const cand of candidateNames) {
|
|
782
782
|
const p1 = path2__default.default.join(projectRoot, "domain", `${cand}.ts`);
|
|
783
|
-
if (
|
|
783
|
+
if (fs11__default.default.existsSync(p1)) return { filePath: p1, ifaceName: cand };
|
|
784
784
|
const p22 = path2__default.default.join(projectRoot, "src", "domain", `${cand}.ts`);
|
|
785
|
-
if (
|
|
785
|
+
if (fs11__default.default.existsSync(p22)) return { filePath: p22, ifaceName: cand };
|
|
786
786
|
const p32 = path2__default.default.join(projectRoot, "interfaces", `${cand}.ts`);
|
|
787
|
-
if (
|
|
787
|
+
if (fs11__default.default.existsSync(p32)) return { filePath: p32, ifaceName: cand };
|
|
788
788
|
}
|
|
789
789
|
return null;
|
|
790
790
|
}
|
|
@@ -807,7 +807,7 @@ function loadInterfaceHierarchy(projectRoot, initialIfaceName, featureName, cust
|
|
|
807
807
|
while (currentFile && !visited.has(currentFile)) {
|
|
808
808
|
visited.add(currentFile);
|
|
809
809
|
try {
|
|
810
|
-
const content =
|
|
810
|
+
const content = fs11__default.default.readFileSync(currentFile, "utf-8");
|
|
811
811
|
const parsed = parseInterfaceMethodsAndImports(content, currentName);
|
|
812
812
|
for (const m of parsed.methods) {
|
|
813
813
|
if (!allMethods.some((existing) => existing.name === m.name)) {
|
|
@@ -1079,22 +1079,22 @@ function generateUseCaseCode(useCaseName, dependencies = [], inputProps = [], ou
|
|
|
1079
1079
|
from: /^I[A-Z]/.test(dep) ? `../domain/${dep}.js` : `./${dep}.js`
|
|
1080
1080
|
}));
|
|
1081
1081
|
const domainTypesToImport = new Set(domainImports);
|
|
1082
|
-
for (const
|
|
1083
|
-
const rawType =
|
|
1082
|
+
for (const p19 of [...inputProps, ...outputProps]) {
|
|
1083
|
+
const rawType = p19.type.trim();
|
|
1084
1084
|
const baseType = rawType.replace(/\[\]$/, "").trim();
|
|
1085
1085
|
if (!primitiveTypes.has(baseType) && /^[A-Z][A-Za-z0-9_]*$/.test(baseType) && !dependencies.includes(baseType)) {
|
|
1086
1086
|
domainTypesToImport.add(baseType);
|
|
1087
1087
|
}
|
|
1088
1088
|
}
|
|
1089
|
-
const formattedInputProps = inputProps.map((
|
|
1090
|
-
name:
|
|
1091
|
-
optional:
|
|
1092
|
-
type:
|
|
1089
|
+
const formattedInputProps = inputProps.map((p19) => ({
|
|
1090
|
+
name: p19.name,
|
|
1091
|
+
optional: p19.optional,
|
|
1092
|
+
type: p19.optional && !p19.type.includes("undefined") ? `${p19.type} | undefined` : p19.type
|
|
1093
1093
|
}));
|
|
1094
|
-
const formattedOutputProps = outputProps.map((
|
|
1095
|
-
name:
|
|
1096
|
-
optional:
|
|
1097
|
-
type:
|
|
1094
|
+
const formattedOutputProps = outputProps.map((p19) => ({
|
|
1095
|
+
name: p19.name,
|
|
1096
|
+
optional: p19.optional,
|
|
1097
|
+
type: p19.optional && !p19.type.includes("undefined") ? `${p19.type} | undefined` : p19.type
|
|
1098
1098
|
}));
|
|
1099
1099
|
const formattedDeps = dependencies.map((dep) => ({
|
|
1100
1100
|
key: toCamelCase(dep),
|
|
@@ -1281,7 +1281,7 @@ function generateHttpHandler(options) {
|
|
|
1281
1281
|
const pxDir = path2__default.default.join(resolveFeaturesDir(projectRoot), options.feature, "pxExpress");
|
|
1282
1282
|
const handlersDir = path2__default.default.join(pxDir, "handlers");
|
|
1283
1283
|
const pxIndexPath = path2__default.default.join(pxDir, "index.ts");
|
|
1284
|
-
if (!
|
|
1284
|
+
if (!fs11__default.default.existsSync(pxIndexPath)) {
|
|
1285
1285
|
const featurePath = options.routePrefix || `/${options.feature.toLowerCase()}`;
|
|
1286
1286
|
const pxIndexContent = renderTemplate(expressIndexTemplate, {
|
|
1287
1287
|
routePath: featurePath
|
|
@@ -1318,8 +1318,8 @@ function updateOrGenerateDiProvider(featureDir, featureName, bindings = [], opti
|
|
|
1318
1318
|
const providerPath = path2__default.default.join(featureDir, "diProvider.ts");
|
|
1319
1319
|
const pascalFeature = toPascalCase(featureName);
|
|
1320
1320
|
const providerModuleName = `${pascalFeature}Provider`;
|
|
1321
|
-
if (
|
|
1322
|
-
let content =
|
|
1321
|
+
if (fs11__default.default.existsSync(providerPath) && !options.overwrite) {
|
|
1322
|
+
let content = fs11__default.default.readFileSync(providerPath, "utf-8");
|
|
1323
1323
|
content = content.replace(/\n*export\s+const\s+ScaffoldProvider\s*=[^;]+;?/g, "");
|
|
1324
1324
|
for (const b of bindings) {
|
|
1325
1325
|
const ifaceImp = b.ifaceImportPath || `./domain/${b.ifaceName}.js`;
|
|
@@ -1765,23 +1765,23 @@ var PromptCancelledError = class extends Error {
|
|
|
1765
1765
|
}
|
|
1766
1766
|
};
|
|
1767
1767
|
function handleCancel(result) {
|
|
1768
|
-
if (
|
|
1769
|
-
|
|
1768
|
+
if (p16__namespace.isCancel(result)) {
|
|
1769
|
+
p16__namespace.cancel("Operation cancelled.");
|
|
1770
1770
|
throw new PromptCancelledError();
|
|
1771
1771
|
}
|
|
1772
1772
|
return result;
|
|
1773
1773
|
}
|
|
1774
1774
|
function printBanner() {
|
|
1775
1775
|
console.log("");
|
|
1776
|
-
|
|
1776
|
+
p16__namespace.intro(pc16__default.default.bgCyan(pc16__default.default.black(" @solid-stack/mason ")));
|
|
1777
1777
|
}
|
|
1778
1778
|
async function promptProperties(options = {}) {
|
|
1779
1779
|
const properties = options.defaults ? [...options.defaults] : [];
|
|
1780
1780
|
if (properties.length > 0) {
|
|
1781
|
-
const summary = properties.map((
|
|
1782
|
-
|
|
1781
|
+
const summary = properties.map((p19) => `${p19.name}: ${p19.type}${p19.optional ? "?" : ""}`).join(", ");
|
|
1782
|
+
p16__namespace.log.info(pc16__default.default.dim(`Pre-configured fields: ${summary}`));
|
|
1783
1783
|
const addMore = handleCancel(
|
|
1784
|
-
await
|
|
1784
|
+
await p16__namespace.confirm({
|
|
1785
1785
|
message: "Would you like to add custom fields/properties?",
|
|
1786
1786
|
initialValue: false
|
|
1787
1787
|
})
|
|
@@ -1790,10 +1790,10 @@ async function promptProperties(options = {}) {
|
|
|
1790
1790
|
return properties;
|
|
1791
1791
|
}
|
|
1792
1792
|
}
|
|
1793
|
-
|
|
1793
|
+
p16__namespace.log.info(pc16__default.default.cyan("Enter properties (leave name blank when finished):"));
|
|
1794
1794
|
while (true) {
|
|
1795
1795
|
const name = handleCancel(
|
|
1796
|
-
await
|
|
1796
|
+
await p16__namespace.text({
|
|
1797
1797
|
message: "Property name (or press Enter to finish):",
|
|
1798
1798
|
placeholder: "e.g. title, email, status"
|
|
1799
1799
|
})
|
|
@@ -1802,7 +1802,7 @@ async function promptProperties(options = {}) {
|
|
|
1802
1802
|
break;
|
|
1803
1803
|
}
|
|
1804
1804
|
const type = handleCancel(
|
|
1805
|
-
await
|
|
1805
|
+
await p16__namespace.select({
|
|
1806
1806
|
message: `Type for property "${name.trim()}":`,
|
|
1807
1807
|
options: [
|
|
1808
1808
|
{ value: "string", label: "string" },
|
|
@@ -1819,7 +1819,7 @@ async function promptProperties(options = {}) {
|
|
|
1819
1819
|
let finalType = type;
|
|
1820
1820
|
if (type === "custom") {
|
|
1821
1821
|
finalType = handleCancel(
|
|
1822
|
-
await
|
|
1822
|
+
await p16__namespace.text({
|
|
1823
1823
|
message: `Enter custom type for "${name.trim()}":`,
|
|
1824
1824
|
placeholder: "e.g. UserRole, string | null",
|
|
1825
1825
|
validate: (val) => val && val.trim() ? void 0 : "Type cannot be empty"
|
|
@@ -1827,7 +1827,7 @@ async function promptProperties(options = {}) {
|
|
|
1827
1827
|
);
|
|
1828
1828
|
}
|
|
1829
1829
|
const optional = handleCancel(
|
|
1830
|
-
await
|
|
1830
|
+
await p16__namespace.confirm({
|
|
1831
1831
|
message: `Is "${name.trim()}" optional?`,
|
|
1832
1832
|
initialValue: false
|
|
1833
1833
|
})
|
|
@@ -1837,8 +1837,8 @@ async function promptProperties(options = {}) {
|
|
|
1837
1837
|
type: finalType.trim(),
|
|
1838
1838
|
optional
|
|
1839
1839
|
});
|
|
1840
|
-
|
|
1841
|
-
|
|
1840
|
+
p16__namespace.log.success(
|
|
1841
|
+
pc16__default.default.green(`Added: ${name.trim()}${optional ? "?" : ""}: ${finalType.trim()}`)
|
|
1842
1842
|
);
|
|
1843
1843
|
}
|
|
1844
1844
|
return properties;
|
|
@@ -1854,7 +1854,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
1854
1854
|
}
|
|
1855
1855
|
if (!name) {
|
|
1856
1856
|
name = handleCancel(
|
|
1857
|
-
await
|
|
1857
|
+
await p16__namespace.text({
|
|
1858
1858
|
message: "What is the feature name?",
|
|
1859
1859
|
placeholder: "e.g. users, auth, orders, billing",
|
|
1860
1860
|
validate: (val) => {
|
|
@@ -1870,7 +1870,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
1870
1870
|
let targetDirRel = defaultDir;
|
|
1871
1871
|
if (!flags.yes && !flags.target && !flags.dest) {
|
|
1872
1872
|
targetDirRel = handleCancel(
|
|
1873
|
-
await
|
|
1873
|
+
await p16__namespace.text({
|
|
1874
1874
|
message: "Target directory for the feature:",
|
|
1875
1875
|
initialValue: defaultDir,
|
|
1876
1876
|
defaultValue: defaultDir
|
|
@@ -1892,14 +1892,14 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
1892
1892
|
const customUseCases = [];
|
|
1893
1893
|
if (!flags.yes) {
|
|
1894
1894
|
includeExpress = handleCancel(
|
|
1895
|
-
await
|
|
1895
|
+
await p16__namespace.confirm({
|
|
1896
1896
|
message: "Include Express Presentation layer (pxExpress routes & handlers)?",
|
|
1897
1897
|
initialValue: true
|
|
1898
1898
|
})
|
|
1899
1899
|
);
|
|
1900
1900
|
if (includeExpress) {
|
|
1901
1901
|
routePath = handleCancel(
|
|
1902
|
-
await
|
|
1902
|
+
await p16__namespace.text({
|
|
1903
1903
|
message: "Express route prefix:",
|
|
1904
1904
|
initialValue: `/${normalizedName}`,
|
|
1905
1905
|
defaultValue: `/${normalizedName}`
|
|
@@ -1907,14 +1907,14 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
1907
1907
|
).trim();
|
|
1908
1908
|
}
|
|
1909
1909
|
includeDomain = handleCancel(
|
|
1910
|
-
await
|
|
1910
|
+
await p16__namespace.confirm({
|
|
1911
1911
|
message: "Include Domain Entity/Entities?",
|
|
1912
1912
|
initialValue: true
|
|
1913
1913
|
})
|
|
1914
1914
|
);
|
|
1915
1915
|
if (includeDomain) {
|
|
1916
1916
|
const domainInput = handleCancel(
|
|
1917
|
-
await
|
|
1917
|
+
await p16__namespace.text({
|
|
1918
1918
|
message: "Domain entity name(s) (comma-separated):",
|
|
1919
1919
|
initialValue: defaultEntity,
|
|
1920
1920
|
defaultValue: defaultEntity,
|
|
@@ -1933,21 +1933,21 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
1933
1933
|
entityNames = [defaultEntity];
|
|
1934
1934
|
}
|
|
1935
1935
|
includeInterface = handleCancel(
|
|
1936
|
-
await
|
|
1936
|
+
await p16__namespace.confirm({
|
|
1937
1937
|
message: `Include Domain Repository interface(s) for ${entityNames.join(", ")}?`,
|
|
1938
1938
|
initialValue: true
|
|
1939
1939
|
})
|
|
1940
1940
|
);
|
|
1941
1941
|
if (includeInterface) {
|
|
1942
1942
|
includeInfra = handleCancel(
|
|
1943
|
-
await
|
|
1943
|
+
await p16__namespace.confirm({
|
|
1944
1944
|
message: `Include Infrastructure Stub implementation(s) for ${entityNames.join(", ")}?`,
|
|
1945
1945
|
initialValue: true
|
|
1946
1946
|
})
|
|
1947
1947
|
);
|
|
1948
1948
|
}
|
|
1949
1949
|
includeUseCase = handleCancel(
|
|
1950
|
-
await
|
|
1950
|
+
await p16__namespace.confirm({
|
|
1951
1951
|
message: "Include Domain Use Cases?",
|
|
1952
1952
|
initialValue: true
|
|
1953
1953
|
})
|
|
@@ -1961,7 +1961,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
1961
1961
|
{ value: "delete", label: "Delete (Delete<Entity>)", hint: "DELETE /:id" }
|
|
1962
1962
|
];
|
|
1963
1963
|
crudOperations = handleCancel(
|
|
1964
|
-
await
|
|
1964
|
+
await p16__namespace.multiselect({
|
|
1965
1965
|
message: "Select standard CRUD use cases to generate:",
|
|
1966
1966
|
options: crudChoices,
|
|
1967
1967
|
initialValues: ["create", "read", "list", "update", "delete"],
|
|
@@ -1969,13 +1969,13 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
1969
1969
|
})
|
|
1970
1970
|
);
|
|
1971
1971
|
includeTests = handleCancel(
|
|
1972
|
-
await
|
|
1972
|
+
await p16__namespace.confirm({
|
|
1973
1973
|
message: "Generate Vitest unit tests for use cases?",
|
|
1974
1974
|
initialValue: true
|
|
1975
1975
|
})
|
|
1976
1976
|
);
|
|
1977
1977
|
const wantCustom = handleCancel(
|
|
1978
|
-
await
|
|
1978
|
+
await p16__namespace.confirm({
|
|
1979
1979
|
message: "Do you want to add any custom use cases to this feature?",
|
|
1980
1980
|
initialValue: false
|
|
1981
1981
|
})
|
|
@@ -1985,7 +1985,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
1985
1985
|
const availableIfaces = entityNames.map((e) => `I${e}Repository`);
|
|
1986
1986
|
while (addMore) {
|
|
1987
1987
|
const customName = handleCancel(
|
|
1988
|
-
await
|
|
1988
|
+
await p16__namespace.text({
|
|
1989
1989
|
message: "Custom Use Case name:",
|
|
1990
1990
|
placeholder: "e.g. ResetPassword, VerifyEmail, AssignRole",
|
|
1991
1991
|
validate: (v) => v && v.trim() ? void 0 : "Use Case name cannot be empty"
|
|
@@ -1995,7 +1995,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
1995
1995
|
let selectedDeps = [];
|
|
1996
1996
|
if (availableIfaces.length > 0) {
|
|
1997
1997
|
selectedDeps = handleCancel(
|
|
1998
|
-
await
|
|
1998
|
+
await p16__namespace.multiselect({
|
|
1999
1999
|
message: `Select domain interfaces to inject into ${customUcName}:`,
|
|
2000
2000
|
options: availableIfaces.map((i) => ({ value: i, label: i })),
|
|
2001
2001
|
required: false
|
|
@@ -2004,7 +2004,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2004
2004
|
}
|
|
2005
2005
|
let customInputProps = [];
|
|
2006
2006
|
const hasInput = handleCancel(
|
|
2007
|
-
await
|
|
2007
|
+
await p16__namespace.confirm({
|
|
2008
2008
|
message: `Does ${customUcName} accept input arguments?`,
|
|
2009
2009
|
initialValue: true
|
|
2010
2010
|
})
|
|
@@ -2015,7 +2015,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2015
2015
|
}
|
|
2016
2016
|
let customOutputProps = [];
|
|
2017
2017
|
const hasCustomOutput = handleCancel(
|
|
2018
|
-
await
|
|
2018
|
+
await p16__namespace.confirm({
|
|
2019
2019
|
message: `Does ${customUcName} return custom output data?`,
|
|
2020
2020
|
initialValue: false
|
|
2021
2021
|
})
|
|
@@ -2025,7 +2025,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2025
2025
|
});
|
|
2026
2026
|
}
|
|
2027
2027
|
const customIncludeTest = handleCancel(
|
|
2028
|
-
await
|
|
2028
|
+
await p16__namespace.confirm({
|
|
2029
2029
|
message: `Generate Vitest unit test for ${customUcName}?`,
|
|
2030
2030
|
initialValue: true
|
|
2031
2031
|
})
|
|
@@ -2035,14 +2035,14 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2035
2035
|
let customHttpPath = `/${toKebabCase(customUcName)}`;
|
|
2036
2036
|
if (includeExpress) {
|
|
2037
2037
|
customCreateHttp = handleCancel(
|
|
2038
|
-
await
|
|
2038
|
+
await p16__namespace.confirm({
|
|
2039
2039
|
message: `Generate a matching ExpressRoute HTTP handler for ${customUcName}?`,
|
|
2040
2040
|
initialValue: true
|
|
2041
2041
|
})
|
|
2042
2042
|
);
|
|
2043
2043
|
if (customCreateHttp) {
|
|
2044
2044
|
customHttpMethod = handleCancel(
|
|
2045
|
-
await
|
|
2045
|
+
await p16__namespace.select({
|
|
2046
2046
|
message: "HTTP method for route:",
|
|
2047
2047
|
options: [
|
|
2048
2048
|
{ value: "post", label: "POST" },
|
|
@@ -2055,7 +2055,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2055
2055
|
})
|
|
2056
2056
|
);
|
|
2057
2057
|
customHttpPath = handleCancel(
|
|
2058
|
-
await
|
|
2058
|
+
await p16__namespace.text({
|
|
2059
2059
|
message: "Route subpath (relative to feature prefix):",
|
|
2060
2060
|
initialValue: `/${toKebabCase(customUcName)}`,
|
|
2061
2061
|
defaultValue: `/${toKebabCase(customUcName)}`
|
|
@@ -2076,7 +2076,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2076
2076
|
validationFields: customInputProps
|
|
2077
2077
|
});
|
|
2078
2078
|
addMore = handleCancel(
|
|
2079
|
-
await
|
|
2079
|
+
await p16__namespace.confirm({
|
|
2080
2080
|
message: "Add another custom use case?",
|
|
2081
2081
|
initialValue: false
|
|
2082
2082
|
})
|
|
@@ -2085,7 +2085,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2085
2085
|
}
|
|
2086
2086
|
}
|
|
2087
2087
|
includeDiProvider = handleCancel(
|
|
2088
|
-
await
|
|
2088
|
+
await p16__namespace.confirm({
|
|
2089
2089
|
message: "Generate / update feature DI provider (diProvider.ts)?",
|
|
2090
2090
|
initialValue: true
|
|
2091
2091
|
})
|
|
@@ -2097,8 +2097,8 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2097
2097
|
entityNames = [defaultEntity];
|
|
2098
2098
|
}
|
|
2099
2099
|
}
|
|
2100
|
-
const s =
|
|
2101
|
-
s.start(`Generating feature '${
|
|
2100
|
+
const s = p16__namespace.spinner();
|
|
2101
|
+
s.start(`Generating feature '${pc16__default.default.cyan(normalizedName)}'...`);
|
|
2102
2102
|
const options = {
|
|
2103
2103
|
name: normalizedName,
|
|
2104
2104
|
projectRoot,
|
|
@@ -2120,7 +2120,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2120
2120
|
const files = generateFeature(options);
|
|
2121
2121
|
if (isRegistry) {
|
|
2122
2122
|
const registryPath = path2__default.default.join(targetDir, "registry.json");
|
|
2123
|
-
if (!
|
|
2123
|
+
if (!fs11__default.default.existsSync(registryPath)) {
|
|
2124
2124
|
const manifest = {
|
|
2125
2125
|
name: toKebabCase(normalizedName),
|
|
2126
2126
|
type: "feature",
|
|
@@ -2144,8 +2144,8 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2144
2144
|
}
|
|
2145
2145
|
s.stop("Feature scaffolded successfully!");
|
|
2146
2146
|
printGeneratedFiles(files, options.dryRun);
|
|
2147
|
-
|
|
2148
|
-
|
|
2147
|
+
p16__namespace.outro(
|
|
2148
|
+
pc16__default.default.green(
|
|
2149
2149
|
`\u2713 Feature '${normalizedName}' initialized in ${path2__default.default.relative(projectRoot, targetDir)} (uncommitted, unregistered)`
|
|
2150
2150
|
)
|
|
2151
2151
|
);
|
|
@@ -2259,7 +2259,7 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
|
|
|
2259
2259
|
}
|
|
2260
2260
|
if (!name) {
|
|
2261
2261
|
name = handleCancel(
|
|
2262
|
-
await
|
|
2262
|
+
await p16__namespace.text({
|
|
2263
2263
|
message: "What is the shared module name?",
|
|
2264
2264
|
placeholder: "e.g. hasher, time, uuid, cache, logger",
|
|
2265
2265
|
validate: (val) => {
|
|
@@ -2275,7 +2275,7 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
|
|
|
2275
2275
|
let targetDirRel = defaultDir;
|
|
2276
2276
|
if (!flags.yes && !flags.target && !flags.dest) {
|
|
2277
2277
|
targetDirRel = handleCancel(
|
|
2278
|
-
await
|
|
2278
|
+
await p16__namespace.text({
|
|
2279
2279
|
message: "Target directory for the shared module:",
|
|
2280
2280
|
initialValue: defaultDir,
|
|
2281
2281
|
defaultValue: defaultDir
|
|
@@ -2287,21 +2287,21 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
|
|
|
2287
2287
|
let includeStub = true;
|
|
2288
2288
|
if (!flags.yes) {
|
|
2289
2289
|
description = handleCancel(
|
|
2290
|
-
await
|
|
2290
|
+
await p16__namespace.text({
|
|
2291
2291
|
message: "Module description (optional):",
|
|
2292
2292
|
placeholder: "e.g. In-memory caching and Redis port abstraction",
|
|
2293
2293
|
initialValue: ""
|
|
2294
2294
|
})
|
|
2295
2295
|
).trim();
|
|
2296
2296
|
includeStub = handleCancel(
|
|
2297
|
-
await
|
|
2297
|
+
await p16__namespace.confirm({
|
|
2298
2298
|
message: "Include stub implementation in infrastructure/?",
|
|
2299
2299
|
initialValue: true
|
|
2300
2300
|
})
|
|
2301
2301
|
);
|
|
2302
2302
|
}
|
|
2303
|
-
const s =
|
|
2304
|
-
s.start(`Generating shared module '${
|
|
2303
|
+
const s = p16__namespace.spinner();
|
|
2304
|
+
s.start(`Generating shared module '${pc16__default.default.cyan(normalizedName)}'...`);
|
|
2305
2305
|
const files = generateShared({
|
|
2306
2306
|
name: normalizedName,
|
|
2307
2307
|
description,
|
|
@@ -2314,8 +2314,8 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
|
|
|
2314
2314
|
});
|
|
2315
2315
|
s.stop("Shared module generated successfully!");
|
|
2316
2316
|
printGeneratedFiles(files, Boolean(flags.dryRun));
|
|
2317
|
-
|
|
2318
|
-
|
|
2317
|
+
p16__namespace.outro(
|
|
2318
|
+
pc16__default.default.green(
|
|
2319
2319
|
`\u2713 Shared module '${normalizedName}' initialized in ${path2__default.default.relative(projectRoot, targetDir)} (uncommitted, unregistered)`
|
|
2320
2320
|
)
|
|
2321
2321
|
);
|
|
@@ -2329,14 +2329,14 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
|
|
|
2329
2329
|
const featureOptions = existingFeatures.map((f) => ({ value: f, label: f }));
|
|
2330
2330
|
featureOptions.push({ value: "__custom__", label: "\u270F\uFE0F Enter custom feature name..." });
|
|
2331
2331
|
const selected = handleCancel(
|
|
2332
|
-
await
|
|
2332
|
+
await p16__namespace.select({
|
|
2333
2333
|
message: "Select target feature:",
|
|
2334
2334
|
options: featureOptions
|
|
2335
2335
|
})
|
|
2336
2336
|
);
|
|
2337
2337
|
if (selected === "__custom__") {
|
|
2338
2338
|
feature = handleCancel(
|
|
2339
|
-
await
|
|
2339
|
+
await p16__namespace.text({
|
|
2340
2340
|
message: "Enter feature name:",
|
|
2341
2341
|
validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
|
|
2342
2342
|
})
|
|
@@ -2346,7 +2346,7 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
|
|
|
2346
2346
|
}
|
|
2347
2347
|
} else {
|
|
2348
2348
|
feature = handleCancel(
|
|
2349
|
-
await
|
|
2349
|
+
await p16__namespace.text({
|
|
2350
2350
|
message: "Enter target feature name:",
|
|
2351
2351
|
validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
|
|
2352
2352
|
})
|
|
@@ -2357,7 +2357,7 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
|
|
|
2357
2357
|
let name = useCaseNameArg?.trim();
|
|
2358
2358
|
if (!name) {
|
|
2359
2359
|
name = handleCancel(
|
|
2360
|
-
await
|
|
2360
|
+
await p16__namespace.text({
|
|
2361
2361
|
message: "Use Case name:",
|
|
2362
2362
|
placeholder: "e.g. CreateUser, GetUser, CancelOrder",
|
|
2363
2363
|
validate: (v) => v && v.trim() ? void 0 : "Use Case name cannot be empty"
|
|
@@ -2373,7 +2373,7 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
|
|
|
2373
2373
|
label: i.name
|
|
2374
2374
|
}));
|
|
2375
2375
|
selectedDeps = handleCancel(
|
|
2376
|
-
await
|
|
2376
|
+
await p16__namespace.multiselect({
|
|
2377
2377
|
message: "Select domain interfaces to inject into use case:",
|
|
2378
2378
|
options: multiOptions,
|
|
2379
2379
|
required: false
|
|
@@ -2388,7 +2388,7 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
|
|
|
2388
2388
|
let httpPath = "/";
|
|
2389
2389
|
if (!flags.yes) {
|
|
2390
2390
|
const hasInput = handleCancel(
|
|
2391
|
-
await
|
|
2391
|
+
await p16__namespace.confirm({
|
|
2392
2392
|
message: "Does this use case accept input arguments?",
|
|
2393
2393
|
initialValue: true
|
|
2394
2394
|
})
|
|
@@ -2398,7 +2398,7 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
|
|
|
2398
2398
|
});
|
|
2399
2399
|
}
|
|
2400
2400
|
const hasCustomOutput = handleCancel(
|
|
2401
|
-
await
|
|
2401
|
+
await p16__namespace.confirm({
|
|
2402
2402
|
message: "Does this use case return custom output data?",
|
|
2403
2403
|
initialValue: false
|
|
2404
2404
|
})
|
|
@@ -2408,20 +2408,20 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
|
|
|
2408
2408
|
});
|
|
2409
2409
|
}
|
|
2410
2410
|
includeTest = handleCancel(
|
|
2411
|
-
await
|
|
2411
|
+
await p16__namespace.confirm({
|
|
2412
2412
|
message: "Generate Vitest unit test skeleton (.test.ts)?",
|
|
2413
2413
|
initialValue: true
|
|
2414
2414
|
})
|
|
2415
2415
|
);
|
|
2416
2416
|
createHttp = handleCancel(
|
|
2417
|
-
await
|
|
2417
|
+
await p16__namespace.confirm({
|
|
2418
2418
|
message: "Generate a matching ExpressRoute HTTP handler?",
|
|
2419
2419
|
initialValue: false
|
|
2420
2420
|
})
|
|
2421
2421
|
);
|
|
2422
2422
|
if (createHttp) {
|
|
2423
2423
|
httpMethod = handleCancel(
|
|
2424
|
-
await
|
|
2424
|
+
await p16__namespace.select({
|
|
2425
2425
|
message: "HTTP method for route:",
|
|
2426
2426
|
options: [
|
|
2427
2427
|
{ value: "post", label: "POST" },
|
|
@@ -2434,7 +2434,7 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
|
|
|
2434
2434
|
})
|
|
2435
2435
|
);
|
|
2436
2436
|
httpPath = handleCancel(
|
|
2437
|
-
await
|
|
2437
|
+
await p16__namespace.text({
|
|
2438
2438
|
message: "Route subpath (relative to feature prefix):",
|
|
2439
2439
|
initialValue: "/",
|
|
2440
2440
|
defaultValue: "/"
|
|
@@ -2442,8 +2442,8 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
|
|
|
2442
2442
|
).trim();
|
|
2443
2443
|
}
|
|
2444
2444
|
}
|
|
2445
|
-
const s =
|
|
2446
|
-
s.start(`Generating use case '${
|
|
2445
|
+
const s = p16__namespace.spinner();
|
|
2446
|
+
s.start(`Generating use case '${pc16__default.default.cyan(ucName)}'...`);
|
|
2447
2447
|
const options = {
|
|
2448
2448
|
name: ucName,
|
|
2449
2449
|
feature,
|
|
@@ -2475,7 +2475,7 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
|
|
|
2475
2475
|
}
|
|
2476
2476
|
s.stop("Use case generated successfully!");
|
|
2477
2477
|
printGeneratedFiles(files, options.dryRun);
|
|
2478
|
-
|
|
2478
|
+
p16__namespace.outro(pc16__default.default.green(`Use case '${ucName}' created in feature '${feature}'!`));
|
|
2479
2479
|
}
|
|
2480
2480
|
async function runDomainCommand(domainNameArg, flags = {}) {
|
|
2481
2481
|
const projectRoot = findProjectRoot();
|
|
@@ -2486,14 +2486,14 @@ async function runDomainCommand(domainNameArg, flags = {}) {
|
|
|
2486
2486
|
const featureOptions = existingFeatures.map((f) => ({ value: f, label: f }));
|
|
2487
2487
|
featureOptions.push({ value: "__custom__", label: "\u270F\uFE0F Enter custom feature name..." });
|
|
2488
2488
|
const selected = handleCancel(
|
|
2489
|
-
await
|
|
2489
|
+
await p16__namespace.select({
|
|
2490
2490
|
message: "Select target feature:",
|
|
2491
2491
|
options: featureOptions
|
|
2492
2492
|
})
|
|
2493
2493
|
);
|
|
2494
2494
|
if (selected === "__custom__") {
|
|
2495
2495
|
feature = handleCancel(
|
|
2496
|
-
await
|
|
2496
|
+
await p16__namespace.text({
|
|
2497
2497
|
message: "Enter feature name:",
|
|
2498
2498
|
validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
|
|
2499
2499
|
})
|
|
@@ -2503,7 +2503,7 @@ async function runDomainCommand(domainNameArg, flags = {}) {
|
|
|
2503
2503
|
}
|
|
2504
2504
|
} else {
|
|
2505
2505
|
feature = handleCancel(
|
|
2506
|
-
await
|
|
2506
|
+
await p16__namespace.text({
|
|
2507
2507
|
message: "Enter target feature name:",
|
|
2508
2508
|
validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
|
|
2509
2509
|
})
|
|
@@ -2514,7 +2514,7 @@ async function runDomainCommand(domainNameArg, flags = {}) {
|
|
|
2514
2514
|
let name = domainNameArg?.trim();
|
|
2515
2515
|
if (!name) {
|
|
2516
2516
|
name = handleCancel(
|
|
2517
|
-
await
|
|
2517
|
+
await p16__namespace.text({
|
|
2518
2518
|
message: "Domain model / entity name:",
|
|
2519
2519
|
placeholder: "e.g. User, Order, Product, Address",
|
|
2520
2520
|
validate: (v) => v && v.trim() ? void 0 : "Domain name cannot be empty"
|
|
@@ -2526,7 +2526,7 @@ async function runDomainCommand(domainNameArg, flags = {}) {
|
|
|
2526
2526
|
let properties = [];
|
|
2527
2527
|
if (!flags.yes) {
|
|
2528
2528
|
kind = handleCancel(
|
|
2529
|
-
await
|
|
2529
|
+
await p16__namespace.select({
|
|
2530
2530
|
message: "Select domain model type:",
|
|
2531
2531
|
options: [
|
|
2532
2532
|
{ value: "interface", label: "TypeScript Interface (pure data structure)" },
|
|
@@ -2545,8 +2545,8 @@ async function runDomainCommand(domainNameArg, flags = {}) {
|
|
|
2545
2545
|
defaults: kind === "valueObject" ? [{ name: "value", type: "string" }] : defaultProps
|
|
2546
2546
|
});
|
|
2547
2547
|
}
|
|
2548
|
-
const s =
|
|
2549
|
-
s.start(`Generating domain model '${
|
|
2548
|
+
const s = p16__namespace.spinner();
|
|
2549
|
+
s.start(`Generating domain model '${pc16__default.default.cyan(entityName)}'...`);
|
|
2550
2550
|
const options = {
|
|
2551
2551
|
name: entityName,
|
|
2552
2552
|
feature,
|
|
@@ -2559,7 +2559,7 @@ async function runDomainCommand(domainNameArg, flags = {}) {
|
|
|
2559
2559
|
const file = generateDomain(options);
|
|
2560
2560
|
s.stop("Domain model generated successfully!");
|
|
2561
2561
|
printGeneratedFiles([file], options.dryRun);
|
|
2562
|
-
|
|
2562
|
+
p16__namespace.outro(pc16__default.default.green(`Domain model '${entityName}' created in feature '${feature}'!`));
|
|
2563
2563
|
}
|
|
2564
2564
|
async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
2565
2565
|
const projectRoot = findProjectRoot();
|
|
@@ -2568,7 +2568,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2568
2568
|
let feature = flags.feature?.trim();
|
|
2569
2569
|
if (!flags.yes && !flags.global && !flags.feature) {
|
|
2570
2570
|
scope = handleCancel(
|
|
2571
|
-
await
|
|
2571
|
+
await p16__namespace.select({
|
|
2572
2572
|
message: "Where should this infrastructure implementation be placed?",
|
|
2573
2573
|
options: [
|
|
2574
2574
|
{ value: "feature", label: "Feature-level (features/<feature>/infrastructure)" },
|
|
@@ -2583,14 +2583,14 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2583
2583
|
const featureOptions = existingFeatures.map((f) => ({ value: f, label: f }));
|
|
2584
2584
|
featureOptions.push({ value: "__custom__", label: "\u270F\uFE0F Enter custom feature name..." });
|
|
2585
2585
|
const selected = handleCancel(
|
|
2586
|
-
await
|
|
2586
|
+
await p16__namespace.select({
|
|
2587
2587
|
message: "Select target feature:",
|
|
2588
2588
|
options: featureOptions
|
|
2589
2589
|
})
|
|
2590
2590
|
);
|
|
2591
2591
|
if (selected === "__custom__") {
|
|
2592
2592
|
feature = handleCancel(
|
|
2593
|
-
await
|
|
2593
|
+
await p16__namespace.text({
|
|
2594
2594
|
message: "Enter feature name:",
|
|
2595
2595
|
validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
|
|
2596
2596
|
})
|
|
@@ -2600,7 +2600,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2600
2600
|
}
|
|
2601
2601
|
} else {
|
|
2602
2602
|
feature = handleCancel(
|
|
2603
|
-
await
|
|
2603
|
+
await p16__namespace.text({
|
|
2604
2604
|
message: "Enter target feature name:",
|
|
2605
2605
|
validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
|
|
2606
2606
|
})
|
|
@@ -2613,7 +2613,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2613
2613
|
let name = classNameArg?.trim();
|
|
2614
2614
|
if (!name) {
|
|
2615
2615
|
name = handleCancel(
|
|
2616
|
-
await
|
|
2616
|
+
await p16__namespace.text({
|
|
2617
2617
|
message: "Infrastructure class name:",
|
|
2618
2618
|
placeholder: "e.g. StubUserRepository, PostgresUserRepository, S3FileStorage",
|
|
2619
2619
|
validate: (v) => v && v.trim() ? void 0 : "Class name cannot be empty"
|
|
@@ -2632,7 +2632,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2632
2632
|
(i) => className.toLowerCase().includes(removeInterfacePrefix(i.name).toLowerCase())
|
|
2633
2633
|
);
|
|
2634
2634
|
const ifaceChoice = handleCancel(
|
|
2635
|
-
await
|
|
2635
|
+
await p16__namespace.select({
|
|
2636
2636
|
message: "Does this class implement a domain interface or abstract class?",
|
|
2637
2637
|
options: [
|
|
2638
2638
|
...interfaces.map((i) => ({ value: i.name, label: i.name })),
|
|
@@ -2644,7 +2644,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2644
2644
|
);
|
|
2645
2645
|
if (ifaceChoice === "__custom__") {
|
|
2646
2646
|
implementsInterface = handleCancel(
|
|
2647
|
-
await
|
|
2647
|
+
await p16__namespace.text({
|
|
2648
2648
|
message: "Enter interface or abstract class name:",
|
|
2649
2649
|
placeholder: "e.g. IUserRepository, BaseStorageAdapter",
|
|
2650
2650
|
validate: (v) => v && v.trim() ? void 0 : "Name cannot be empty"
|
|
@@ -2655,14 +2655,14 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2655
2655
|
}
|
|
2656
2656
|
} else {
|
|
2657
2657
|
const wantImpl = handleCancel(
|
|
2658
|
-
await
|
|
2658
|
+
await p16__namespace.confirm({
|
|
2659
2659
|
message: "Does this class implement a domain interface or abstract class?",
|
|
2660
2660
|
initialValue: false
|
|
2661
2661
|
})
|
|
2662
2662
|
);
|
|
2663
2663
|
if (wantImpl) {
|
|
2664
2664
|
implementsInterface = handleCancel(
|
|
2665
|
-
await
|
|
2665
|
+
await p16__namespace.text({
|
|
2666
2666
|
message: "Enter interface or abstract class name:",
|
|
2667
2667
|
placeholder: "e.g. IUserRepository, BaseStorageAdapter",
|
|
2668
2668
|
validate: (v) => v && v.trim() ? void 0 : "Name cannot be empty"
|
|
@@ -2682,7 +2682,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2682
2682
|
const allInterfaces = listDomainInterfaces(projectRoot);
|
|
2683
2683
|
if (allInterfaces.length > 0) {
|
|
2684
2684
|
const ifaceChoice = handleCancel(
|
|
2685
|
-
await
|
|
2685
|
+
await p16__namespace.select({
|
|
2686
2686
|
message: "Does this class implement an interface or abstract class?",
|
|
2687
2687
|
options: [
|
|
2688
2688
|
...allInterfaces.map((i) => ({ value: i.name, label: `${i.name} (${i.feature})` })),
|
|
@@ -2694,7 +2694,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2694
2694
|
);
|
|
2695
2695
|
if (ifaceChoice === "__custom__") {
|
|
2696
2696
|
implementsInterface = handleCancel(
|
|
2697
|
-
await
|
|
2697
|
+
await p16__namespace.text({
|
|
2698
2698
|
message: "Enter interface or abstract class name:",
|
|
2699
2699
|
placeholder: "e.g. IAuthRepository",
|
|
2700
2700
|
validate: (v) => v && v.trim() ? void 0 : "Name cannot be empty"
|
|
@@ -2707,7 +2707,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2707
2707
|
}
|
|
2708
2708
|
if (!flags.yes && !flags.kind) {
|
|
2709
2709
|
kind = handleCancel(
|
|
2710
|
-
await
|
|
2710
|
+
await p16__namespace.select({
|
|
2711
2711
|
message: "Select implementation kind:",
|
|
2712
2712
|
options: [
|
|
2713
2713
|
{ value: "stub", label: "In-Memory Stub (with in-memory store and test helper methods)" },
|
|
@@ -2718,7 +2718,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2718
2718
|
);
|
|
2719
2719
|
if (scope === "feature" && feature && implementsInterface) {
|
|
2720
2720
|
registerInProvider = handleCancel(
|
|
2721
|
-
await
|
|
2721
|
+
await p16__namespace.confirm({
|
|
2722
2722
|
message: "Register this implementation in feature diProvider.ts?",
|
|
2723
2723
|
initialValue: true
|
|
2724
2724
|
})
|
|
@@ -2727,8 +2727,8 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2727
2727
|
} else if (flags.yes && scope === "feature" && feature && implementsInterface) {
|
|
2728
2728
|
registerInProvider = !flags.noProvider;
|
|
2729
2729
|
}
|
|
2730
|
-
const s =
|
|
2731
|
-
s.start(`Generating infrastructure class '${
|
|
2730
|
+
const s = p16__namespace.spinner();
|
|
2731
|
+
s.start(`Generating infrastructure class '${pc16__default.default.cyan(className)}'...`);
|
|
2732
2732
|
const files = [];
|
|
2733
2733
|
const options = {
|
|
2734
2734
|
name: className,
|
|
@@ -2763,7 +2763,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2763
2763
|
}
|
|
2764
2764
|
s.stop("Infrastructure class generated successfully!");
|
|
2765
2765
|
printGeneratedFiles(files, options.dryRun);
|
|
2766
|
-
|
|
2766
|
+
p16__namespace.outro(pc16__default.default.green(`Infrastructure class '${className}' created!`));
|
|
2767
2767
|
}
|
|
2768
2768
|
async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
2769
2769
|
const projectRoot = findProjectRoot();
|
|
@@ -2774,14 +2774,14 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
|
2774
2774
|
const featureOptions = existingFeatures.map((f) => ({ value: f, label: f }));
|
|
2775
2775
|
featureOptions.push({ value: "__custom__", label: "\u270F\uFE0F Enter custom feature name..." });
|
|
2776
2776
|
const selected = handleCancel(
|
|
2777
|
-
await
|
|
2777
|
+
await p16__namespace.select({
|
|
2778
2778
|
message: "Select target feature:",
|
|
2779
2779
|
options: featureOptions
|
|
2780
2780
|
})
|
|
2781
2781
|
);
|
|
2782
2782
|
if (selected === "__custom__") {
|
|
2783
2783
|
feature = handleCancel(
|
|
2784
|
-
await
|
|
2784
|
+
await p16__namespace.text({
|
|
2785
2785
|
message: "Enter feature name:",
|
|
2786
2786
|
validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
|
|
2787
2787
|
})
|
|
@@ -2791,7 +2791,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
|
2791
2791
|
}
|
|
2792
2792
|
} else {
|
|
2793
2793
|
feature = handleCancel(
|
|
2794
|
-
await
|
|
2794
|
+
await p16__namespace.text({
|
|
2795
2795
|
message: "Enter target feature name:",
|
|
2796
2796
|
validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
|
|
2797
2797
|
})
|
|
@@ -2802,7 +2802,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
|
2802
2802
|
let name = interfaceNameArg?.trim();
|
|
2803
2803
|
if (!name) {
|
|
2804
2804
|
name = handleCancel(
|
|
2805
|
-
await
|
|
2805
|
+
await p16__namespace.text({
|
|
2806
2806
|
message: "Domain interface name:",
|
|
2807
2807
|
placeholder: "e.g. IUserRepository, IPaymentService",
|
|
2808
2808
|
validate: (v) => v && v.trim() ? void 0 : "Interface name cannot be empty"
|
|
@@ -2820,7 +2820,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
|
2820
2820
|
if (!flags.yes) {
|
|
2821
2821
|
if (existingEntities.length > 0) {
|
|
2822
2822
|
const selectedEntity = handleCancel(
|
|
2823
|
-
await
|
|
2823
|
+
await p16__namespace.select({
|
|
2824
2824
|
message: "Select domain entity associated with this interface:",
|
|
2825
2825
|
options: [
|
|
2826
2826
|
...existingEntities.map((e) => ({ value: e.name, label: e.name })),
|
|
@@ -2831,7 +2831,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
|
2831
2831
|
);
|
|
2832
2832
|
if (selectedEntity === "__custom__") {
|
|
2833
2833
|
entityName = handleCancel(
|
|
2834
|
-
await
|
|
2834
|
+
await p16__namespace.text({
|
|
2835
2835
|
message: "Enter entity name:",
|
|
2836
2836
|
defaultValue: removeInterfacePrefix(ifaceName).replace(/Repository$|Service$/, "")
|
|
2837
2837
|
})
|
|
@@ -2841,7 +2841,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
|
2841
2841
|
}
|
|
2842
2842
|
}
|
|
2843
2843
|
kind = handleCancel(
|
|
2844
|
-
await
|
|
2844
|
+
await p16__namespace.select({
|
|
2845
2845
|
message: "Interface definition style:",
|
|
2846
2846
|
options: [
|
|
2847
2847
|
{ value: "abstractClass", label: "Abstract Class (Recommended - acts as DI token & type)" },
|
|
@@ -2851,7 +2851,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
|
2851
2851
|
})
|
|
2852
2852
|
);
|
|
2853
2853
|
methodsPreset = handleCancel(
|
|
2854
|
-
await
|
|
2854
|
+
await p16__namespace.select({
|
|
2855
2855
|
message: "Method signature preset:",
|
|
2856
2856
|
options: [
|
|
2857
2857
|
{ value: "crud", label: "Standard CRUD (GetById, List, Create, Update, Delete)" },
|
|
@@ -2861,22 +2861,22 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
|
2861
2861
|
})
|
|
2862
2862
|
);
|
|
2863
2863
|
generateStub = handleCancel(
|
|
2864
|
-
await
|
|
2864
|
+
await p16__namespace.confirm({
|
|
2865
2865
|
message: "Auto-generate Infrastructure Stub implementation?",
|
|
2866
2866
|
initialValue: true
|
|
2867
2867
|
})
|
|
2868
2868
|
);
|
|
2869
2869
|
if (generateStub) {
|
|
2870
2870
|
registerInProvider = handleCancel(
|
|
2871
|
-
await
|
|
2871
|
+
await p16__namespace.confirm({
|
|
2872
2872
|
message: "Auto-register interface & stub in feature diProvider.ts?",
|
|
2873
2873
|
initialValue: true
|
|
2874
2874
|
})
|
|
2875
2875
|
);
|
|
2876
2876
|
}
|
|
2877
2877
|
}
|
|
2878
|
-
const s =
|
|
2879
|
-
s.start(`Generating interface '${
|
|
2878
|
+
const s = p16__namespace.spinner();
|
|
2879
|
+
s.start(`Generating interface '${pc16__default.default.cyan(ifaceName)}'...`);
|
|
2880
2880
|
const files = [];
|
|
2881
2881
|
const options = {
|
|
2882
2882
|
name: ifaceName,
|
|
@@ -2925,7 +2925,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
|
2925
2925
|
}
|
|
2926
2926
|
s.stop("Interface generated successfully!");
|
|
2927
2927
|
printGeneratedFiles(files, options.dryRun);
|
|
2928
|
-
|
|
2928
|
+
p16__namespace.outro(pc16__default.default.green(`Interface '${ifaceName}' created in feature '${feature}'!`));
|
|
2929
2929
|
}
|
|
2930
2930
|
async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
|
|
2931
2931
|
const projectRoot = findProjectRoot();
|
|
@@ -2936,14 +2936,14 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
|
|
|
2936
2936
|
const featureOptions = existingFeatures.map((f) => ({ value: f, label: f }));
|
|
2937
2937
|
featureOptions.push({ value: "__custom__", label: "\u270F\uFE0F Enter custom feature name..." });
|
|
2938
2938
|
const selected = handleCancel(
|
|
2939
|
-
await
|
|
2939
|
+
await p16__namespace.select({
|
|
2940
2940
|
message: "Select target feature:",
|
|
2941
2941
|
options: featureOptions
|
|
2942
2942
|
})
|
|
2943
2943
|
);
|
|
2944
2944
|
if (selected === "__custom__") {
|
|
2945
2945
|
feature = handleCancel(
|
|
2946
|
-
await
|
|
2946
|
+
await p16__namespace.text({
|
|
2947
2947
|
message: "Enter feature name:",
|
|
2948
2948
|
validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
|
|
2949
2949
|
})
|
|
@@ -2953,7 +2953,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
|
|
|
2953
2953
|
}
|
|
2954
2954
|
} else {
|
|
2955
2955
|
feature = handleCancel(
|
|
2956
|
-
await
|
|
2956
|
+
await p16__namespace.text({
|
|
2957
2957
|
message: "Enter target feature name:",
|
|
2958
2958
|
validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
|
|
2959
2959
|
})
|
|
@@ -2964,7 +2964,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
|
|
|
2964
2964
|
let name = handlerNameArg?.trim();
|
|
2965
2965
|
if (!name) {
|
|
2966
2966
|
name = handleCancel(
|
|
2967
|
-
await
|
|
2967
|
+
await p16__namespace.text({
|
|
2968
2968
|
message: "HTTP Route Handler class name:",
|
|
2969
2969
|
placeholder: "e.g. CreateUserHttp, GetUserHttp, HealthHttp",
|
|
2970
2970
|
validate: (v) => v && v.trim() ? void 0 : "Handler name cannot be empty"
|
|
@@ -2983,7 +2983,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
|
|
|
2983
2983
|
let validationFields = [];
|
|
2984
2984
|
if (!flags.yes) {
|
|
2985
2985
|
method = handleCancel(
|
|
2986
|
-
await
|
|
2986
|
+
await p16__namespace.select({
|
|
2987
2987
|
message: "HTTP Method:",
|
|
2988
2988
|
options: [
|
|
2989
2989
|
{ value: "get", label: "GET" },
|
|
@@ -2997,7 +2997,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
|
|
|
2997
2997
|
);
|
|
2998
2998
|
const defaultPath = method === "get" ? "/" : "/";
|
|
2999
2999
|
subPath = handleCancel(
|
|
3000
|
-
await
|
|
3000
|
+
await p16__namespace.text({
|
|
3001
3001
|
message: "Route subpath (relative to feature prefix):",
|
|
3002
3002
|
initialValue: defaultPath,
|
|
3003
3003
|
defaultValue: defaultPath
|
|
@@ -3008,7 +3008,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
|
|
|
3008
3008
|
const ucOptions = useCases.map((u) => ({ value: u.name, label: u.name }));
|
|
3009
3009
|
ucOptions.push({ value: "__none__", label: "None / Standalone Handler" });
|
|
3010
3010
|
const chosenUc = handleCancel(
|
|
3011
|
-
await
|
|
3011
|
+
await p16__namespace.select({
|
|
3012
3012
|
message: "Connect this handler to a domain Use Case?",
|
|
3013
3013
|
options: ucOptions,
|
|
3014
3014
|
initialValue: ucOptions[0]?.value
|
|
@@ -3019,7 +3019,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
|
|
|
3019
3019
|
}
|
|
3020
3020
|
}
|
|
3021
3021
|
includeValidation = handleCancel(
|
|
3022
|
-
await
|
|
3022
|
+
await p16__namespace.confirm({
|
|
3023
3023
|
message: "Include Zod inbound request validation?",
|
|
3024
3024
|
initialValue: method !== "delete"
|
|
3025
3025
|
})
|
|
@@ -3027,7 +3027,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
|
|
|
3027
3027
|
if (includeValidation) {
|
|
3028
3028
|
const defaultSource = method === "get" ? "query" : "body";
|
|
3029
3029
|
validationSource = handleCancel(
|
|
3030
|
-
await
|
|
3030
|
+
await p16__namespace.select({
|
|
3031
3031
|
message: "Validation data source:",
|
|
3032
3032
|
options: [
|
|
3033
3033
|
{ value: "body", label: "req.body (for POST / PUT / PATCH payloads)" },
|
|
@@ -3041,8 +3041,8 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
|
|
|
3041
3041
|
});
|
|
3042
3042
|
}
|
|
3043
3043
|
}
|
|
3044
|
-
const s =
|
|
3045
|
-
s.start(`Generating HTTP handler '${
|
|
3044
|
+
const s = p16__namespace.spinner();
|
|
3045
|
+
s.start(`Generating HTTP handler '${pc16__default.default.cyan(className)}'...`);
|
|
3046
3046
|
const options = {
|
|
3047
3047
|
name: className,
|
|
3048
3048
|
feature,
|
|
@@ -3060,7 +3060,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
|
|
|
3060
3060
|
const files = generateHttpHandler(options);
|
|
3061
3061
|
s.stop("HTTP handler generated successfully!");
|
|
3062
3062
|
printGeneratedFiles(files, options.dryRun);
|
|
3063
|
-
|
|
3063
|
+
p16__namespace.outro(pc16__default.default.green(`HTTP handler '${className}' created in feature '${feature}'!`));
|
|
3064
3064
|
}
|
|
3065
3065
|
function generateInjectableCode(className, dependencies = [], methods = [], implementsInterface) {
|
|
3066
3066
|
const formattedDeps = dependencies.map((dep) => ({
|
|
@@ -3070,7 +3070,7 @@ function generateInjectableCode(className, dependencies = [], methods = [], impl
|
|
|
3070
3070
|
const formattedMethods = methods.map((m) => {
|
|
3071
3071
|
const isAsync = m.async !== false;
|
|
3072
3072
|
const retType = m.returnType ? isAsync ? `Promise<${m.returnType}>` : m.returnType : isAsync ? "Promise<void>" : "void";
|
|
3073
|
-
const params = m.params && m.params.length > 0 ? m.params.map((
|
|
3073
|
+
const params = m.params && m.params.length > 0 ? m.params.map((p19) => `${p19.name}: ${p19.type}`).join(", ") : "";
|
|
3074
3074
|
return {
|
|
3075
3075
|
name: m.name,
|
|
3076
3076
|
isAsync,
|
|
@@ -3140,7 +3140,7 @@ async function runInjectableCommand(classNameArg, flags = {}) {
|
|
|
3140
3140
|
let name = classNameArg?.trim();
|
|
3141
3141
|
if (!name) {
|
|
3142
3142
|
name = handleCancel(
|
|
3143
|
-
await
|
|
3143
|
+
await p16__namespace.text({
|
|
3144
3144
|
message: "Injectable class name:",
|
|
3145
3145
|
placeholder: "e.g. PasswordHasher, TokenService, UserTransformer",
|
|
3146
3146
|
validate: (v) => v && v.trim() ? void 0 : "Class name cannot be empty"
|
|
@@ -3153,7 +3153,7 @@ async function runInjectableCommand(classNameArg, flags = {}) {
|
|
|
3153
3153
|
let customPath;
|
|
3154
3154
|
if (!flags.yes) {
|
|
3155
3155
|
location = handleCancel(
|
|
3156
|
-
await
|
|
3156
|
+
await p16__namespace.select({
|
|
3157
3157
|
message: "Select target architectural location:",
|
|
3158
3158
|
options: [
|
|
3159
3159
|
{ value: "feature-service", label: "Feature Service (features/<feature>/services/)" },
|
|
@@ -3171,14 +3171,14 @@ async function runInjectableCommand(classNameArg, flags = {}) {
|
|
|
3171
3171
|
const featureOptions = existingFeatures.map((f) => ({ value: f, label: f }));
|
|
3172
3172
|
featureOptions.push({ value: "__custom__", label: "\u270F\uFE0F Enter custom feature name..." });
|
|
3173
3173
|
const selected = handleCancel(
|
|
3174
|
-
await
|
|
3174
|
+
await p16__namespace.select({
|
|
3175
3175
|
message: "Select target feature:",
|
|
3176
3176
|
options: featureOptions
|
|
3177
3177
|
})
|
|
3178
3178
|
);
|
|
3179
3179
|
if (selected === "__custom__") {
|
|
3180
3180
|
feature = handleCancel(
|
|
3181
|
-
await
|
|
3181
|
+
await p16__namespace.text({
|
|
3182
3182
|
message: "Enter feature name:",
|
|
3183
3183
|
validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
|
|
3184
3184
|
})
|
|
@@ -3188,7 +3188,7 @@ async function runInjectableCommand(classNameArg, flags = {}) {
|
|
|
3188
3188
|
}
|
|
3189
3189
|
} else {
|
|
3190
3190
|
feature = handleCancel(
|
|
3191
|
-
await
|
|
3191
|
+
await p16__namespace.text({
|
|
3192
3192
|
message: "Enter target feature name:",
|
|
3193
3193
|
validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
|
|
3194
3194
|
})
|
|
@@ -3198,7 +3198,7 @@ async function runInjectableCommand(classNameArg, flags = {}) {
|
|
|
3198
3198
|
feature = toCamelCase(feature);
|
|
3199
3199
|
} else if (location === "custom") {
|
|
3200
3200
|
customPath = handleCancel(
|
|
3201
|
-
await
|
|
3201
|
+
await p16__namespace.text({
|
|
3202
3202
|
message: "Enter destination directory path:",
|
|
3203
3203
|
placeholder: "e.g. src/services or lib/utils",
|
|
3204
3204
|
validate: (v) => v && v.trim() ? void 0 : "Path cannot be empty"
|
|
@@ -3209,14 +3209,14 @@ async function runInjectableCommand(classNameArg, flags = {}) {
|
|
|
3209
3209
|
let generateInterface2 = false;
|
|
3210
3210
|
if (!flags.yes) {
|
|
3211
3211
|
generateInterface2 = handleCancel(
|
|
3212
|
-
await
|
|
3212
|
+
await p16__namespace.confirm({
|
|
3213
3213
|
message: `Generate abstract class interface (I${className}) as runtime DI token?`,
|
|
3214
3214
|
initialValue: false
|
|
3215
3215
|
})
|
|
3216
3216
|
);
|
|
3217
3217
|
}
|
|
3218
|
-
const s =
|
|
3219
|
-
s.start(`Generating injectable '${
|
|
3218
|
+
const s = p16__namespace.spinner();
|
|
3219
|
+
s.start(`Generating injectable '${pc16__default.default.cyan(className)}'...`);
|
|
3220
3220
|
const options = {
|
|
3221
3221
|
name: className,
|
|
3222
3222
|
feature,
|
|
@@ -3230,17 +3230,17 @@ async function runInjectableCommand(classNameArg, flags = {}) {
|
|
|
3230
3230
|
const files = generateInjectable(options);
|
|
3231
3231
|
s.stop("Injectable class generated successfully!");
|
|
3232
3232
|
printGeneratedFiles(files, options.dryRun);
|
|
3233
|
-
|
|
3233
|
+
p16__namespace.outro(pc16__default.default.green(`Injectable '${className}' created successfully!`));
|
|
3234
3234
|
}
|
|
3235
3235
|
async function runEnvCommand(flags = {}) {
|
|
3236
3236
|
const projectRoot = flags.cwd || flags.targetDir || findProjectRoot();
|
|
3237
|
-
const s =
|
|
3237
|
+
const s = p16__namespace.spinner();
|
|
3238
3238
|
s.start("Scanning for .example environment files...");
|
|
3239
|
-
const files =
|
|
3239
|
+
const files = fs11__default.default.readdirSync(projectRoot);
|
|
3240
3240
|
const exampleFiles = files.filter((file) => file.startsWith(".env") && file.endsWith(".example")).sort();
|
|
3241
3241
|
if (exampleFiles.length === 0) {
|
|
3242
3242
|
s.stop("No .example files found.");
|
|
3243
|
-
|
|
3243
|
+
p16__namespace.log.info(pc16__default.default.yellow(`No files matching '.env*.example' were found in ${projectRoot}`));
|
|
3244
3244
|
return [];
|
|
3245
3245
|
}
|
|
3246
3246
|
s.message(`Found ${exampleFiles.length} template(s). Generating...`);
|
|
@@ -3249,7 +3249,7 @@ async function runEnvCommand(flags = {}) {
|
|
|
3249
3249
|
const sourcePath = path2__default.default.join(projectRoot, exampleFile);
|
|
3250
3250
|
const targetFile = exampleFile.replace(/\.example$/, "");
|
|
3251
3251
|
const targetPath = path2__default.default.join(projectRoot, targetFile);
|
|
3252
|
-
const content =
|
|
3252
|
+
const content = fs11__default.default.readFileSync(sourcePath, "utf-8");
|
|
3253
3253
|
const genFile = writeFileSafely(targetPath, content, {
|
|
3254
3254
|
projectRoot,
|
|
3255
3255
|
dryRun: Boolean(flags.dryRun),
|
|
@@ -3259,7 +3259,46 @@ async function runEnvCommand(flags = {}) {
|
|
|
3259
3259
|
}
|
|
3260
3260
|
s.stop("Environment files processed!");
|
|
3261
3261
|
printGeneratedFiles(generatedFiles, Boolean(flags.dryRun));
|
|
3262
|
-
|
|
3262
|
+
p16__namespace.outro(pc16__default.default.green("\u2713 Local environment files are ready!"));
|
|
3263
|
+
return generatedFiles;
|
|
3264
|
+
}
|
|
3265
|
+
async function runEnvExamplesCommand(flags = {}) {
|
|
3266
|
+
const projectRoot = flags.cwd || flags.targetDir || findProjectRoot();
|
|
3267
|
+
const s = p16__namespace.spinner();
|
|
3268
|
+
s.start("Scanning for local environment files...");
|
|
3269
|
+
const files = fs11__default.default.readdirSync(projectRoot, { withFileTypes: true });
|
|
3270
|
+
const envFiles = files.filter((dirent) => dirent.isFile() && dirent.name.startsWith(".env") && !dirent.name.endsWith(".example")).map((dirent) => dirent.name).sort();
|
|
3271
|
+
if (envFiles.length === 0) {
|
|
3272
|
+
s.stop("No local .env files found.");
|
|
3273
|
+
p16__namespace.log.info(pc16__default.default.yellow(`No files matching '.env*' were found in ${projectRoot}`));
|
|
3274
|
+
return [];
|
|
3275
|
+
}
|
|
3276
|
+
s.message(`Found ${envFiles.length} local .env file(s). Generating templates...`);
|
|
3277
|
+
const generatedFiles = [];
|
|
3278
|
+
for (const envFile of envFiles) {
|
|
3279
|
+
const sourcePath = path2__default.default.join(projectRoot, envFile);
|
|
3280
|
+
const targetFile = `${envFile}.example`;
|
|
3281
|
+
const targetPath = path2__default.default.join(projectRoot, targetFile);
|
|
3282
|
+
const content = fs11__default.default.readFileSync(sourcePath, "utf-8");
|
|
3283
|
+
const redactedContent = content.split(/\r?\n/).map((line) => {
|
|
3284
|
+
const trimmed = line.trim();
|
|
3285
|
+
if (trimmed.startsWith("#") || !trimmed) return line;
|
|
3286
|
+
const eqIndex = line.indexOf("=");
|
|
3287
|
+
if (eqIndex !== -1) {
|
|
3288
|
+
return line.substring(0, eqIndex + 1);
|
|
3289
|
+
}
|
|
3290
|
+
return line;
|
|
3291
|
+
}).join("\n");
|
|
3292
|
+
const genFile = writeFileSafely(targetPath, redactedContent, {
|
|
3293
|
+
projectRoot,
|
|
3294
|
+
dryRun: Boolean(flags.dryRun),
|
|
3295
|
+
overwrite: Boolean(flags.overwrite)
|
|
3296
|
+
});
|
|
3297
|
+
generatedFiles.push(genFile);
|
|
3298
|
+
}
|
|
3299
|
+
s.stop("Environment example templates generated!");
|
|
3300
|
+
printGeneratedFiles(generatedFiles, Boolean(flags.dryRun));
|
|
3301
|
+
p16__namespace.outro(pc16__default.default.green("\u2713 .env*.example files are up to date and safely redacted!"));
|
|
3263
3302
|
return generatedFiles;
|
|
3264
3303
|
}
|
|
3265
3304
|
|
|
@@ -3267,7 +3306,7 @@ async function runEnvCommand(flags = {}) {
|
|
|
3267
3306
|
async function runInteractiveMenu(flags = {}) {
|
|
3268
3307
|
printBanner();
|
|
3269
3308
|
const choice = handleCancel(
|
|
3270
|
-
await
|
|
3309
|
+
await p16__namespace.select({
|
|
3271
3310
|
message: "What would you like to create in your architecture?",
|
|
3272
3311
|
options: [
|
|
3273
3312
|
{
|
|
@@ -3313,7 +3352,12 @@ async function runInteractiveMenu(flags = {}) {
|
|
|
3313
3352
|
{
|
|
3314
3353
|
value: "env",
|
|
3315
3354
|
label: "Generate Env Files",
|
|
3316
|
-
hint: "Clone .env*.example files to local .env equivalents"
|
|
3355
|
+
hint: "Clone .env*.example files to local .env equivalents (Setup)"
|
|
3356
|
+
},
|
|
3357
|
+
{
|
|
3358
|
+
value: "envExamples",
|
|
3359
|
+
label: "Sync Env Examples",
|
|
3360
|
+
hint: "Safely clone and redact local .env files to .example templates (Sync)"
|
|
3317
3361
|
}
|
|
3318
3362
|
]
|
|
3319
3363
|
})
|
|
@@ -3346,6 +3390,9 @@ async function runInteractiveMenu(flags = {}) {
|
|
|
3346
3390
|
case "env":
|
|
3347
3391
|
await runEnvCommand(flags);
|
|
3348
3392
|
break;
|
|
3393
|
+
case "envExamples":
|
|
3394
|
+
await runEnvExamplesCommand({ ...flags, overwrite: flags.overwrite ?? true });
|
|
3395
|
+
break;
|
|
3349
3396
|
}
|
|
3350
3397
|
}
|
|
3351
3398
|
|
|
@@ -3383,8 +3430,8 @@ async function handleCreate(type, name, flags = {}) {
|
|
|
3383
3430
|
await runInjectableCommand(name, flags);
|
|
3384
3431
|
break;
|
|
3385
3432
|
default:
|
|
3386
|
-
|
|
3387
|
-
|
|
3433
|
+
p16__namespace.log.error(
|
|
3434
|
+
pc16__default.default.red(
|
|
3388
3435
|
`Unknown component type: "${type}". Allowed types: feature, shared, usecase, domain, infrastructure, interface, httpHandler, injectable.`
|
|
3389
3436
|
)
|
|
3390
3437
|
);
|
|
@@ -3416,7 +3463,7 @@ function findLocalRegistry(startDir = process.cwd()) {
|
|
|
3416
3463
|
let current = path2__default.default.resolve(startDir);
|
|
3417
3464
|
while (true) {
|
|
3418
3465
|
const candidate = path2__default.default.join(current, "mason-registry");
|
|
3419
|
-
if (
|
|
3466
|
+
if (fs11__default.default.existsSync(candidate) && fs11__default.default.existsSync(path2__default.default.join(candidate, "index.json"))) {
|
|
3420
3467
|
return candidate;
|
|
3421
3468
|
}
|
|
3422
3469
|
const parent = path2__default.default.dirname(current);
|
|
@@ -3438,9 +3485,9 @@ function getRegistryBase(projectRoot, override) {
|
|
|
3438
3485
|
path2__default.default.join(process.cwd(), "mason.config.json")
|
|
3439
3486
|
];
|
|
3440
3487
|
for (const configPath of configLocations) {
|
|
3441
|
-
if (
|
|
3488
|
+
if (fs11__default.default.existsSync(configPath)) {
|
|
3442
3489
|
try {
|
|
3443
|
-
const config = JSON.parse(
|
|
3490
|
+
const config = JSON.parse(fs11__default.default.readFileSync(configPath, "utf-8"));
|
|
3444
3491
|
if (config.registry && typeof config.registry === "string") {
|
|
3445
3492
|
return normalizeRegistryUrl(config.registry.trim(), path2__default.default.dirname(configPath));
|
|
3446
3493
|
}
|
|
@@ -3453,9 +3500,9 @@ function getRegistryBase(projectRoot, override) {
|
|
|
3453
3500
|
path2__default.default.join(process.cwd(), "package.json")
|
|
3454
3501
|
];
|
|
3455
3502
|
for (const pkgPath of pkgLocations) {
|
|
3456
|
-
if (
|
|
3503
|
+
if (fs11__default.default.existsSync(pkgPath)) {
|
|
3457
3504
|
try {
|
|
3458
|
-
const pkg = JSON.parse(
|
|
3505
|
+
const pkg = JSON.parse(fs11__default.default.readFileSync(pkgPath, "utf-8"));
|
|
3459
3506
|
if (pkg.mason?.registry && typeof pkg.mason.registry === "string") {
|
|
3460
3507
|
return normalizeRegistryUrl(pkg.mason.registry.trim(), path2__default.default.dirname(pkgPath));
|
|
3461
3508
|
}
|
|
@@ -3506,15 +3553,15 @@ async function fetchRegistryFile(registryBase, relPath) {
|
|
|
3506
3553
|
baseDir = url.fileURLToPath(baseDir);
|
|
3507
3554
|
}
|
|
3508
3555
|
let filePath = path2__default.default.resolve(baseDir, cleanRelPath);
|
|
3509
|
-
if (!
|
|
3556
|
+
if (!fs11__default.default.existsSync(filePath)) {
|
|
3510
3557
|
const inSrcPath = path2__default.default.resolve(baseDir, "src", cleanRelPath);
|
|
3511
|
-
if (
|
|
3558
|
+
if (fs11__default.default.existsSync(inSrcPath)) {
|
|
3512
3559
|
filePath = inSrcPath;
|
|
3513
3560
|
} else {
|
|
3514
3561
|
throw new Error(`Registry file not found at ${filePath}`);
|
|
3515
3562
|
}
|
|
3516
3563
|
}
|
|
3517
|
-
return
|
|
3564
|
+
return fs11__default.default.promises.readFile(filePath, "utf-8");
|
|
3518
3565
|
}
|
|
3519
3566
|
async function fetchRegistryIndex(registryBase) {
|
|
3520
3567
|
const content = await fetchRegistryFile(registryBase, "index.json");
|
|
@@ -3576,26 +3623,26 @@ function findClosestMatch(target, candidates) {
|
|
|
3576
3623
|
return null;
|
|
3577
3624
|
}
|
|
3578
3625
|
function detectPackageManager(projectRoot) {
|
|
3579
|
-
if (
|
|
3580
|
-
if (
|
|
3581
|
-
if (
|
|
3626
|
+
if (fs11__default.default.existsSync(path2__default.default.join(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
|
|
3627
|
+
if (fs11__default.default.existsSync(path2__default.default.join(projectRoot, "yarn.lock"))) return "yarn";
|
|
3628
|
+
if (fs11__default.default.existsSync(path2__default.default.join(projectRoot, "bun.lockb")) || fs11__default.default.existsSync(path2__default.default.join(projectRoot, "bun.lock"))) return "bun";
|
|
3582
3629
|
return "npm";
|
|
3583
3630
|
}
|
|
3584
3631
|
function getMissingNpmPackages(projectRoot, requiredPackages) {
|
|
3585
3632
|
if (!requiredPackages || requiredPackages.length === 0) return [];
|
|
3586
3633
|
const pkgJsonPath = path2__default.default.join(projectRoot, "package.json");
|
|
3587
|
-
if (!
|
|
3634
|
+
if (!fs11__default.default.existsSync(pkgJsonPath)) {
|
|
3588
3635
|
return requiredPackages;
|
|
3589
3636
|
}
|
|
3590
3637
|
try {
|
|
3591
|
-
const pkg = JSON.parse(
|
|
3638
|
+
const pkg = JSON.parse(fs11__default.default.readFileSync(pkgJsonPath, "utf-8"));
|
|
3592
3639
|
const installed = /* @__PURE__ */ new Set([
|
|
3593
3640
|
...Object.keys(pkg.dependencies || {}),
|
|
3594
3641
|
...Object.keys(pkg.devDependencies || {}),
|
|
3595
3642
|
...Object.keys(pkg.peerDependencies || {})
|
|
3596
3643
|
]);
|
|
3597
|
-
return requiredPackages.filter((
|
|
3598
|
-
const nameOnly =
|
|
3644
|
+
return requiredPackages.filter((p19) => {
|
|
3645
|
+
const nameOnly = p19.startsWith("@") ? `@${p19.slice(1).split("@")[0] || ""}` : p19.split("@")[0] || p19;
|
|
3599
3646
|
return !installed.has(nameOnly);
|
|
3600
3647
|
});
|
|
3601
3648
|
} catch {
|
|
@@ -3620,15 +3667,15 @@ function installNpmPackages(projectRoot, packages, pm) {
|
|
|
3620
3667
|
installCmd = `npm install ${packages.join(" ")}`;
|
|
3621
3668
|
break;
|
|
3622
3669
|
}
|
|
3623
|
-
|
|
3670
|
+
p16__namespace.log.info(`Installing missing dependencies with ${manager}: ${pc16__default.default.cyan(packages.join(", "))}`);
|
|
3624
3671
|
child_process.execSync(installCmd, {
|
|
3625
3672
|
cwd: projectRoot,
|
|
3626
3673
|
stdio: "inherit"
|
|
3627
3674
|
});
|
|
3628
3675
|
}
|
|
3629
3676
|
function getAllFiles(dir, baseDir = dir) {
|
|
3630
|
-
if (!
|
|
3631
|
-
const entries =
|
|
3677
|
+
if (!fs11__default.default.existsSync(dir)) return [];
|
|
3678
|
+
const entries = fs11__default.default.readdirSync(dir, { withFileTypes: true });
|
|
3632
3679
|
const files = [];
|
|
3633
3680
|
for (const entry of entries) {
|
|
3634
3681
|
const fullPath = path2__default.default.join(dir, entry.name);
|
|
@@ -3648,13 +3695,13 @@ function getAllFiles(dir, baseDir = dir) {
|
|
|
3648
3695
|
return files.sort();
|
|
3649
3696
|
}
|
|
3650
3697
|
function computeDirectoryHash(dirPath, files) {
|
|
3651
|
-
if (!
|
|
3698
|
+
if (!fs11__default.default.existsSync(dirPath)) return "";
|
|
3652
3699
|
const hash = crypto.createHash("sha256");
|
|
3653
3700
|
const fileList = (getAllFiles(dirPath)).sort();
|
|
3654
3701
|
for (const relativePath of fileList) {
|
|
3655
3702
|
const absolutePath = path2__default.default.join(dirPath, relativePath);
|
|
3656
|
-
if (!
|
|
3657
|
-
const content =
|
|
3703
|
+
if (!fs11__default.default.existsSync(absolutePath)) continue;
|
|
3704
|
+
const content = fs11__default.default.readFileSync(absolutePath, "utf8");
|
|
3658
3705
|
const normalizedContent = content.replace(/\r\n/g, "\n");
|
|
3659
3706
|
hash.update(relativePath);
|
|
3660
3707
|
hash.update(normalizedContent);
|
|
@@ -3664,9 +3711,9 @@ function computeDirectoryHash(dirPath, files) {
|
|
|
3664
3711
|
|
|
3665
3712
|
// src/commands/import.ts
|
|
3666
3713
|
var importPrompts = {
|
|
3667
|
-
select:
|
|
3668
|
-
text:
|
|
3669
|
-
confirm:
|
|
3714
|
+
select: p16__namespace.select,
|
|
3715
|
+
text: p16__namespace.text,
|
|
3716
|
+
confirm: p16__namespace.confirm
|
|
3670
3717
|
};
|
|
3671
3718
|
function isTestFile(filePath) {
|
|
3672
3719
|
const normalized = filePath.replace(/\\/g, "/");
|
|
@@ -3698,11 +3745,11 @@ function getExistingModuleDir(projectRoot, modType, modName) {
|
|
|
3698
3745
|
const folder = modType === "shared" ? "shared" : "features";
|
|
3699
3746
|
const configuredDir = modType === "shared" ? getConfiguredSharedDir(projectRoot) : getConfiguredFeaturesDir(projectRoot);
|
|
3700
3747
|
const inConfigured = path2__default.default.join(configuredDir, modName);
|
|
3701
|
-
if (
|
|
3748
|
+
if (fs11__default.default.existsSync(inConfigured)) return inConfigured;
|
|
3702
3749
|
const inSrc = path2__default.default.join(projectRoot, "src", folder, modName);
|
|
3703
|
-
if (
|
|
3750
|
+
if (fs11__default.default.existsSync(inSrc)) return inSrc;
|
|
3704
3751
|
const inRoot = path2__default.default.join(projectRoot, folder, modName);
|
|
3705
|
-
if (
|
|
3752
|
+
if (fs11__default.default.existsSync(inRoot)) return inRoot;
|
|
3706
3753
|
return null;
|
|
3707
3754
|
}
|
|
3708
3755
|
function checkModuleExists(projectRoot, modType, modName) {
|
|
@@ -3718,9 +3765,9 @@ function getAvailableLocalModules(projectRoot, modType) {
|
|
|
3718
3765
|
];
|
|
3719
3766
|
const set = /* @__PURE__ */ new Set();
|
|
3720
3767
|
for (const dir of dirs) {
|
|
3721
|
-
if (
|
|
3768
|
+
if (fs11__default.default.existsSync(dir)) {
|
|
3722
3769
|
try {
|
|
3723
|
-
const entries =
|
|
3770
|
+
const entries = fs11__default.default.readdirSync(dir, { withFileTypes: true });
|
|
3724
3771
|
for (const e of entries) {
|
|
3725
3772
|
if (e.isDirectory() && !e.name.startsWith(".")) {
|
|
3726
3773
|
set.add(e.name);
|
|
@@ -3776,19 +3823,19 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3776
3823
|
);
|
|
3777
3824
|
}
|
|
3778
3825
|
if (type !== "shared" && type !== "feature") {
|
|
3779
|
-
|
|
3826
|
+
p16__namespace.log.error(pc16__default.default.red(`Invalid module type: "${typeArg}". Must be "shared" or "feature".`));
|
|
3780
3827
|
process.exit(1);
|
|
3781
3828
|
}
|
|
3782
3829
|
const registryBase = getRegistryBase(projectRoot, flags.registry);
|
|
3783
|
-
const s =
|
|
3784
|
-
s.start(`Connecting to registry at ${
|
|
3830
|
+
const s = p16__namespace.spinner();
|
|
3831
|
+
s.start(`Connecting to registry at ${pc16__default.default.dim(registryBase)}...`);
|
|
3785
3832
|
let index;
|
|
3786
3833
|
try {
|
|
3787
3834
|
index = await fetchRegistryIndex(registryBase);
|
|
3788
3835
|
s.stop("Registry index loaded.");
|
|
3789
3836
|
} catch (err) {
|
|
3790
|
-
s.stop(
|
|
3791
|
-
|
|
3837
|
+
s.stop(pc16__default.default.red("Failed to load registry index."));
|
|
3838
|
+
p16__namespace.log.error(pc16__default.default.red(err.message || String(err)));
|
|
3792
3839
|
process.exit(1);
|
|
3793
3840
|
}
|
|
3794
3841
|
const availableList = type === "shared" ? index.shared : index.features;
|
|
@@ -3796,7 +3843,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3796
3843
|
let name = nameArg?.trim();
|
|
3797
3844
|
if (!name) {
|
|
3798
3845
|
if (availableList.length === 0) {
|
|
3799
|
-
|
|
3846
|
+
p16__namespace.log.warn(`No ${type} modules available in the registry.`);
|
|
3800
3847
|
return;
|
|
3801
3848
|
}
|
|
3802
3849
|
name = handleCancel(
|
|
@@ -3812,9 +3859,9 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3812
3859
|
}
|
|
3813
3860
|
if (!candidateNames.includes(name)) {
|
|
3814
3861
|
const closest = findClosestMatch(name, candidateNames);
|
|
3815
|
-
|
|
3862
|
+
p16__namespace.log.error(pc16__default.default.red(`\u274C Module '${name}' not found in the ${type} registry.`));
|
|
3816
3863
|
if (closest) {
|
|
3817
|
-
|
|
3864
|
+
p16__namespace.log.info(pc16__default.default.yellow(`Did you mean '${pc16__default.default.cyan(closest)}'?`));
|
|
3818
3865
|
}
|
|
3819
3866
|
process.exit(1);
|
|
3820
3867
|
}
|
|
@@ -3826,7 +3873,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3826
3873
|
try {
|
|
3827
3874
|
manifest = await fetchModuleManifest(registryBase, modType, modName);
|
|
3828
3875
|
} catch (err) {
|
|
3829
|
-
|
|
3876
|
+
p16__namespace.log.error(pc16__default.default.red(`Failed to fetch manifest for ${modType} '${modName}': ${err.message}`));
|
|
3830
3877
|
process.exit(1);
|
|
3831
3878
|
}
|
|
3832
3879
|
nodes.set(key, {
|
|
@@ -3866,7 +3913,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3866
3913
|
buildTopologicalOrder(rootKey);
|
|
3867
3914
|
const resolutions = /* @__PURE__ */ new Map();
|
|
3868
3915
|
const globalAliasMap = /* @__PURE__ */ new Map();
|
|
3869
|
-
|
|
3916
|
+
p16__namespace.log.step(`Importing ${type}: ${pc16__default.default.cyan(name)}...`);
|
|
3870
3917
|
for (const key of orderedKeys) {
|
|
3871
3918
|
const node = nodes.get(key);
|
|
3872
3919
|
const { type: modType, name: registryName, manifest } = node;
|
|
@@ -3898,8 +3945,8 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3898
3945
|
const programmaticPointTo = pointToMap[registryName] || pointToMap[`${modType}/${registryName}`];
|
|
3899
3946
|
if (programmaticPointTo) {
|
|
3900
3947
|
if (!checkModuleExists(projectRoot, modType, programmaticPointTo)) {
|
|
3901
|
-
|
|
3902
|
-
|
|
3948
|
+
p16__namespace.log.error(
|
|
3949
|
+
pc16__default.default.red(
|
|
3903
3950
|
`Module '${programmaticPointTo}' specified in --point-to does not exist in ${folder}.`
|
|
3904
3951
|
)
|
|
3905
3952
|
);
|
|
@@ -3907,7 +3954,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3907
3954
|
}
|
|
3908
3955
|
globalAliasMap.set(`@/${folder}/${registryName}/`, `@/${folder}/${programmaticPointTo}/`);
|
|
3909
3956
|
globalAliasMap.set(`@/${folder}/${registryName}`, `@/${folder}/${programmaticPointTo}`);
|
|
3910
|
-
|
|
3957
|
+
p16__namespace.log.step(`Pointing '${modType}/${registryName}' to existing '${folder}/${programmaticPointTo}'`);
|
|
3911
3958
|
resolutions.set(key, {
|
|
3912
3959
|
type: modType,
|
|
3913
3960
|
registryName,
|
|
@@ -3923,7 +3970,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3923
3970
|
globalAliasMap.set(`@/${folder}/${registryName}`, `@/${folder}/${programmaticAlias}`);
|
|
3924
3971
|
const baseDir = getModuleBaseDir(projectRoot, modType);
|
|
3925
3972
|
const displayDest = path2__default.default.relative(projectRoot, path2__default.default.join(baseDir, programmaticAlias));
|
|
3926
|
-
|
|
3973
|
+
p16__namespace.log.step(`Importing '${registryName}' into '${displayDest}'...`);
|
|
3927
3974
|
resolutions.set(key, {
|
|
3928
3975
|
type: modType,
|
|
3929
3976
|
registryName,
|
|
@@ -3935,7 +3982,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3935
3982
|
}
|
|
3936
3983
|
const existingDir = getExistingModuleDir(projectRoot, modType, registryName);
|
|
3937
3984
|
if (!existingDir) {
|
|
3938
|
-
|
|
3985
|
+
p16__namespace.log.info(` \u21B3 Resolving required ${modType} dependency: ${pc16__default.default.cyan(registryName)}`);
|
|
3939
3986
|
resolutions.set(key, {
|
|
3940
3987
|
type: modType,
|
|
3941
3988
|
registryName,
|
|
@@ -3951,7 +3998,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3951
3998
|
const remoteIntegrity = manifest.integrity || entry?.integrity;
|
|
3952
3999
|
const localHash = computeDirectoryHash(existingDir);
|
|
3953
4000
|
if (remoteIntegrity && localHash === remoteIntegrity) {
|
|
3954
|
-
|
|
4001
|
+
p16__namespace.log.step(`\u2713 ${modType}/${registryName} is up to date (reusing existing)`);
|
|
3955
4002
|
resolutions.set(key, {
|
|
3956
4003
|
type: modType,
|
|
3957
4004
|
registryName,
|
|
@@ -3962,7 +4009,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3962
4009
|
continue;
|
|
3963
4010
|
}
|
|
3964
4011
|
if (flags.overwrite) {
|
|
3965
|
-
|
|
4012
|
+
p16__namespace.log.step(`Overwriting '${modType}/${registryName}' with registry version (--overwrite)...`);
|
|
3966
4013
|
resolutions.set(key, {
|
|
3967
4014
|
type: modType,
|
|
3968
4015
|
registryName,
|
|
@@ -3973,7 +4020,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3973
4020
|
continue;
|
|
3974
4021
|
}
|
|
3975
4022
|
if (flags.yes) {
|
|
3976
|
-
|
|
4023
|
+
p16__namespace.log.info(`Using existing '${modType}/${registryName}'`);
|
|
3977
4024
|
resolutions.set(key, {
|
|
3978
4025
|
type: modType,
|
|
3979
4026
|
registryName,
|
|
@@ -4007,7 +4054,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
4007
4054
|
})
|
|
4008
4055
|
);
|
|
4009
4056
|
if (choice === "keep_existing" || choice === "use_existing") {
|
|
4010
|
-
|
|
4057
|
+
p16__namespace.log.step(`Skipping '${modType}/${registryName}' (keeping existing)`);
|
|
4011
4058
|
resolutions.set(key, {
|
|
4012
4059
|
type: modType,
|
|
4013
4060
|
registryName,
|
|
@@ -4079,7 +4126,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
4079
4126
|
chosenName = chosenName.replace(/^@\/(shared|features)\//, "").replace(/^(src\/)?(shared|features)\//, "").replace(/^\/+|\/+$/g, "").trim();
|
|
4080
4127
|
globalAliasMap.set(`@/${folder}/${registryName}/`, `@/${folder}/${chosenName}/`);
|
|
4081
4128
|
globalAliasMap.set(`@/${folder}/${registryName}`, `@/${folder}/${chosenName}`);
|
|
4082
|
-
|
|
4129
|
+
p16__namespace.log.step(`Pointing '${modType}/${registryName}' to existing '${folder}/${chosenName}'`);
|
|
4083
4130
|
resolutions.set(key, {
|
|
4084
4131
|
type: modType,
|
|
4085
4132
|
registryName,
|
|
@@ -4111,7 +4158,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
4111
4158
|
globalAliasMap.set(`@/${folder}/${registryName}`, `@/${folder}/${newName}`);
|
|
4112
4159
|
const baseDir = getModuleBaseDir(projectRoot, modType);
|
|
4113
4160
|
const displayDest = path2__default.default.relative(projectRoot, path2__default.default.join(baseDir, newName));
|
|
4114
|
-
|
|
4161
|
+
p16__namespace.log.step(`Importing '${registryName}' into '${displayDest}'...`);
|
|
4115
4162
|
resolutions.set(key, {
|
|
4116
4163
|
type: modType,
|
|
4117
4164
|
registryName,
|
|
@@ -4122,7 +4169,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
4122
4169
|
continue;
|
|
4123
4170
|
}
|
|
4124
4171
|
if (choice === "overwrite") {
|
|
4125
|
-
|
|
4172
|
+
p16__namespace.log.step(`Overwriting '${modType}/${registryName}' with registry version...`);
|
|
4126
4173
|
resolutions.set(key, {
|
|
4127
4174
|
type: modType,
|
|
4128
4175
|
registryName,
|
|
@@ -4165,17 +4212,17 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
4165
4212
|
const targetDir = path2__default.default.join(getModuleBaseDir(projectRoot, res.type), res.targetName);
|
|
4166
4213
|
const isOverwrite = Boolean(flags.overwrite || res.action === "overwrite");
|
|
4167
4214
|
if (key !== rootKey) {
|
|
4168
|
-
|
|
4169
|
-
`Importing ${res.type}: ${
|
|
4215
|
+
p16__namespace.log.step(
|
|
4216
|
+
`Importing ${res.type}: ${pc16__default.default.cyan(res.targetName)}${res.targetName !== res.registryName ? pc16__default.default.dim(` (from ${res.registryName})`) : ""}...`
|
|
4170
4217
|
);
|
|
4171
4218
|
}
|
|
4172
4219
|
if (res.action === "overwrite" && !flags.dryRun) {
|
|
4173
4220
|
const existingDir = getExistingModuleDir(projectRoot, res.type, res.targetName);
|
|
4174
4221
|
if (existingDir && existingDir !== targetDir) {
|
|
4175
|
-
|
|
4222
|
+
fs11__default.default.rmSync(existingDir, { recursive: true, force: true });
|
|
4176
4223
|
}
|
|
4177
|
-
if (
|
|
4178
|
-
|
|
4224
|
+
if (fs11__default.default.existsSync(targetDir)) {
|
|
4225
|
+
fs11__default.default.rmSync(targetDir, { recursive: true, force: true });
|
|
4179
4226
|
}
|
|
4180
4227
|
}
|
|
4181
4228
|
for (const file of res.manifest.files || []) {
|
|
@@ -4183,32 +4230,32 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
4183
4230
|
if (!includeTests && isTestFile(file)) continue;
|
|
4184
4231
|
const remoteFilePath = `${folder}/${res.registryName}/${file}`;
|
|
4185
4232
|
const localFilePath = path2__default.default.join(targetDir, file);
|
|
4186
|
-
if (
|
|
4187
|
-
|
|
4188
|
-
` \u21B3 Skipping existing file: ${
|
|
4233
|
+
if (fs11__default.default.existsSync(localFilePath) && !isOverwrite) {
|
|
4234
|
+
p16__namespace.log.warn(
|
|
4235
|
+
` \u21B3 Skipping existing file: ${pc16__default.default.dim(path2__default.default.relative(projectRoot, localFilePath))} (use --overwrite to replace)`
|
|
4189
4236
|
);
|
|
4190
4237
|
continue;
|
|
4191
4238
|
}
|
|
4192
4239
|
let content = await fetchRegistryFile(registryBase, remoteFilePath);
|
|
4193
4240
|
content = rewriteImports(content, globalAliasMap);
|
|
4194
4241
|
if (!flags.dryRun) {
|
|
4195
|
-
|
|
4196
|
-
|
|
4242
|
+
fs11__default.default.mkdirSync(path2__default.default.dirname(localFilePath), { recursive: true });
|
|
4243
|
+
fs11__default.default.writeFileSync(localFilePath, content, "utf-8");
|
|
4197
4244
|
}
|
|
4198
4245
|
const displayPath = path2__default.default.relative(projectRoot, localFilePath);
|
|
4199
4246
|
totalWrittenFiles.push(displayPath);
|
|
4200
|
-
|
|
4247
|
+
p16__namespace.log.message(` ${pc16__default.default.green("+")} ${displayPath}`);
|
|
4201
4248
|
}
|
|
4202
4249
|
}
|
|
4203
4250
|
const missingNpm = getMissingNpmPackages(projectRoot, Array.from(requiredNpmPackages));
|
|
4204
4251
|
if (missingNpm.length > 0) {
|
|
4205
4252
|
if (flags.skipInstall || flags.dryRun) {
|
|
4206
|
-
|
|
4253
|
+
p16__namespace.log.info(`Required npm dependencies to install: ${pc16__default.default.cyan(missingNpm.join(", "))}`);
|
|
4207
4254
|
} else {
|
|
4208
4255
|
try {
|
|
4209
4256
|
installNpmPackages(projectRoot, missingNpm);
|
|
4210
4257
|
} catch (err) {
|
|
4211
|
-
|
|
4258
|
+
p16__namespace.log.warn(
|
|
4212
4259
|
`Could not automatically install packages (${err.message}). Please run: npm install ${missingNpm.join(
|
|
4213
4260
|
" "
|
|
4214
4261
|
)}`
|
|
@@ -4217,13 +4264,13 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
4217
4264
|
}
|
|
4218
4265
|
}
|
|
4219
4266
|
if (flags.dryRun) {
|
|
4220
|
-
|
|
4267
|
+
p16__namespace.log.info(pc16__default.default.yellow("Dry run complete: No files were written to disk."));
|
|
4221
4268
|
} else {
|
|
4222
4269
|
const rootRes = resolutions.get(rootKey);
|
|
4223
4270
|
const baseDir = getModuleBaseDir(projectRoot, type);
|
|
4224
4271
|
const displayTarget = path2__default.default.relative(projectRoot, path2__default.default.join(baseDir, rootRes.targetName));
|
|
4225
|
-
|
|
4226
|
-
|
|
4272
|
+
p16__namespace.log.success(
|
|
4273
|
+
pc16__default.default.green(
|
|
4227
4274
|
`Successfully imported ${type} '${name}' (${totalWrittenFiles.length} file${totalWrittenFiles.length === 1 ? "" : "s"} placed in ${displayTarget})`
|
|
4228
4275
|
)
|
|
4229
4276
|
);
|
|
@@ -4245,8 +4292,8 @@ function isTestFile2(filePath, projectRoot) {
|
|
|
4245
4292
|
return base.endsWith(".test.ts") || base.endsWith(".test.js") || base.endsWith(".spec.ts") || base.endsWith(".spec.js") || base.endsWith(".d.ts") || norm.includes("/__tests__/") || norm.startsWith("__tests__/") || /(?:^|\/)tests?\//.test(norm);
|
|
4246
4293
|
}
|
|
4247
4294
|
function scanDirFiles(dir, projectRoot) {
|
|
4248
|
-
if (!
|
|
4249
|
-
const entries =
|
|
4295
|
+
if (!fs11__default.default.existsSync(dir)) return [];
|
|
4296
|
+
const entries = fs11__default.default.readdirSync(dir, { withFileTypes: true });
|
|
4250
4297
|
const files = [];
|
|
4251
4298
|
for (const entry of entries) {
|
|
4252
4299
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "__tests__" || entry.name.startsWith(".")) {
|
|
@@ -4446,10 +4493,10 @@ var FeatureDependencyGraph = class {
|
|
|
4446
4493
|
if (cycle) return cycle;
|
|
4447
4494
|
} else if (inStack.has(next)) {
|
|
4448
4495
|
const cycle = [next];
|
|
4449
|
-
let
|
|
4450
|
-
while (
|
|
4451
|
-
cycle.push(
|
|
4452
|
-
|
|
4496
|
+
let p19 = curr;
|
|
4497
|
+
while (p19 !== next) {
|
|
4498
|
+
cycle.push(p19);
|
|
4499
|
+
p19 = parent.get(p19) || next;
|
|
4453
4500
|
}
|
|
4454
4501
|
cycle.push(next);
|
|
4455
4502
|
cycle.reverse();
|
|
@@ -4465,8 +4512,8 @@ var FeatureDependencyGraph = class {
|
|
|
4465
4512
|
};
|
|
4466
4513
|
function discoverAllFeatures(projectRoot) {
|
|
4467
4514
|
const featuresBase = resolveFeaturesDir(projectRoot);
|
|
4468
|
-
if (!
|
|
4469
|
-
const entries =
|
|
4515
|
+
if (!fs11__default.default.existsSync(featuresBase)) return [];
|
|
4516
|
+
const entries = fs11__default.default.readdirSync(featuresBase, { withFileTypes: true });
|
|
4470
4517
|
return entries.filter((e) => e.isDirectory() && !e.name.startsWith(".") && e.name !== "__tests__" && e.name !== "tests").map((e) => ({
|
|
4471
4518
|
name: e.name,
|
|
4472
4519
|
dir: path2__default.default.join(featuresBase, e.name)
|
|
@@ -4857,7 +4904,7 @@ Code: ${v.code}`;
|
|
|
4857
4904
|
const relPath = path2__default.default.relative(projectRoot, file).replace(/\\/g, "/");
|
|
4858
4905
|
const { layer } = classifyFile(file, projectRoot);
|
|
4859
4906
|
if (!layer) continue;
|
|
4860
|
-
const content =
|
|
4907
|
+
const content = fs11__default.default.readFileSync(file, "utf-8");
|
|
4861
4908
|
const statements = extractImportStatements(content);
|
|
4862
4909
|
const baseName = path2__default.default.basename(file);
|
|
4863
4910
|
const isBarrel = baseName === "index.ts" || baseName === "index.js";
|
|
@@ -5351,15 +5398,15 @@ ${compiledDetails}
|
|
|
5351
5398
|
// src/commands/lint.ts
|
|
5352
5399
|
function formatViolation(v) {
|
|
5353
5400
|
const lines = [];
|
|
5354
|
-
lines.push(
|
|
5401
|
+
lines.push(pc16__default.default.underline(pc16__default.default.cyan(v.relativePath)) + pc16__default.default.dim(":") + pc16__default.default.yellow(String(v.line)));
|
|
5355
5402
|
const gutter = `${String(v.line).padStart(4, " ")} | `;
|
|
5356
|
-
lines.push(
|
|
5403
|
+
lines.push(pc16__default.default.dim(gutter) + v.code);
|
|
5357
5404
|
const categoryShort = v.category.replace(" Violation", "");
|
|
5358
5405
|
lines.push(
|
|
5359
|
-
" " +
|
|
5406
|
+
" " + pc16__default.default.red(pc16__default.default.bold("\u2716")) + " " + pc16__default.default.red(`[${categoryShort}]`) + " " + v.advice
|
|
5360
5407
|
);
|
|
5361
5408
|
if (v.fixExample?.good) {
|
|
5362
|
-
lines.push(" " +
|
|
5409
|
+
lines.push(" " + pc16__default.default.dim("\u2192") + " " + pc16__default.default.dim(v.fixExample.good));
|
|
5363
5410
|
}
|
|
5364
5411
|
return lines.join("\n");
|
|
5365
5412
|
}
|
|
@@ -5384,7 +5431,7 @@ async function handleLint(flags = {}) {
|
|
|
5384
5431
|
console.log("");
|
|
5385
5432
|
}
|
|
5386
5433
|
console.log(
|
|
5387
|
-
|
|
5434
|
+
pc16__default.default.red(
|
|
5388
5435
|
`\u2716 Dependency rules check failed with ${summary.totalViolations} error${summary.totalViolations > 1 ? "s" : ""} across ${summary.violatedFeatures} feature${summary.violatedFeatures > 1 ? "s" : ""} (${summary.totalFeatures} features scanned).`
|
|
5389
5436
|
)
|
|
5390
5437
|
);
|
|
@@ -5403,7 +5450,7 @@ ${compiledDetails}
|
|
|
5403
5450
|
}
|
|
5404
5451
|
if (!quiet) {
|
|
5405
5452
|
console.log(
|
|
5406
|
-
|
|
5453
|
+
pc16__default.default.green(
|
|
5407
5454
|
`\u2714 Dependency rules verified across ${summary.totalFeatures} feature${summary.totalFeatures === 1 ? "" : "s"}.`
|
|
5408
5455
|
)
|
|
5409
5456
|
);
|
|
@@ -5418,7 +5465,7 @@ ${compiledDetails}
|
|
|
5418
5465
|
console.log(formatViolation(v));
|
|
5419
5466
|
console.log("");
|
|
5420
5467
|
}
|
|
5421
|
-
console.log(
|
|
5468
|
+
console.log(pc16__default.default.red(`\u2716 Dependency rules check failed (1 error).`));
|
|
5422
5469
|
console.log("");
|
|
5423
5470
|
}
|
|
5424
5471
|
}
|
|
@@ -5428,33 +5475,42 @@ ${compiledDetails}
|
|
|
5428
5475
|
async function handleInit(type, flags = {}) {
|
|
5429
5476
|
if (!type) {
|
|
5430
5477
|
const choice = handleCancel(
|
|
5431
|
-
await
|
|
5478
|
+
await p16__namespace.select({
|
|
5432
5479
|
message: "What would you like to initialize?",
|
|
5433
5480
|
options: [
|
|
5434
5481
|
{
|
|
5435
5482
|
value: "env",
|
|
5436
5483
|
label: "Environment Files",
|
|
5437
5484
|
hint: "Generate local .env files from .env*.example templates"
|
|
5485
|
+
},
|
|
5486
|
+
{
|
|
5487
|
+
value: "env-examples",
|
|
5488
|
+
label: "Sync Env Examples",
|
|
5489
|
+
hint: "Safely clone and redact local .env files to .example templates"
|
|
5438
5490
|
}
|
|
5439
5491
|
]
|
|
5440
5492
|
})
|
|
5441
5493
|
);
|
|
5442
5494
|
if (choice === "env") {
|
|
5443
5495
|
await runEnvCommand(flags);
|
|
5496
|
+
} else if (choice === "env-examples") {
|
|
5497
|
+
await runEnvExamplesCommand(flags);
|
|
5444
5498
|
}
|
|
5445
5499
|
return;
|
|
5446
5500
|
}
|
|
5447
5501
|
const normalized = type.trim().toLowerCase();
|
|
5448
5502
|
if (normalized === "env") {
|
|
5449
5503
|
await runEnvCommand(flags);
|
|
5504
|
+
} else if (normalized === "env-examples" || normalized === "envexamples") {
|
|
5505
|
+
await runEnvExamplesCommand(flags);
|
|
5450
5506
|
} else {
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
`Unknown init target: "${type}". Allowed targets: env.`
|
|
5507
|
+
p16__namespace.log.error(
|
|
5508
|
+
pc16__default.default.red(
|
|
5509
|
+
`Unknown init target: "${type}". Allowed targets: env, env-examples.`
|
|
5454
5510
|
)
|
|
5455
5511
|
);
|
|
5456
5512
|
if (process.env.VITEST) {
|
|
5457
|
-
throw new Error(`Unknown init target: "${type}". Allowed targets: env.`);
|
|
5513
|
+
throw new Error(`Unknown init target: "${type}". Allowed targets: env, env-examples.`);
|
|
5458
5514
|
}
|
|
5459
5515
|
process.exit(1);
|
|
5460
5516
|
}
|
|
@@ -5465,8 +5521,8 @@ function createCli() {
|
|
|
5465
5521
|
const cli = cac.cac("mason");
|
|
5466
5522
|
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").option("--point-to <mapping>", "Point a dependency to an existing local module (e.g. --point-to time:mytime)").option("--alias <mapping>", "Import a dependency fresh under an alias name (e.g. --alias time:time-mason)").option("--tests", "Include test files (use --no-tests to exclude)").action(async (args, flags) => {
|
|
5467
5523
|
if (args && args.length > 0) {
|
|
5468
|
-
|
|
5469
|
-
|
|
5524
|
+
p16__namespace.log.error(
|
|
5525
|
+
pc16__default.default.red(
|
|
5470
5526
|
`Unknown command: "${args.join(" ")}". Use --help to list available commands.`
|
|
5471
5527
|
)
|
|
5472
5528
|
);
|
|
@@ -5477,7 +5533,7 @@ function createCli() {
|
|
|
5477
5533
|
const mode = getEffectiveMode(projectRoot, flags);
|
|
5478
5534
|
if (mode === "registry") {
|
|
5479
5535
|
const choice2 = handleCancel(
|
|
5480
|
-
await
|
|
5536
|
+
await p16__namespace.select({
|
|
5481
5537
|
message: "\u{1F3DB}\uFE0F Mason (Registry Mode): What would you like to scaffold?",
|
|
5482
5538
|
options: [
|
|
5483
5539
|
{
|
|
@@ -5520,7 +5576,7 @@ function createCli() {
|
|
|
5520
5576
|
return;
|
|
5521
5577
|
}
|
|
5522
5578
|
const choice = handleCancel(
|
|
5523
|
-
await
|
|
5579
|
+
await p16__namespace.select({
|
|
5524
5580
|
message: "\u{1F9F1} Mason: What would you like to do?",
|
|
5525
5581
|
options: [
|
|
5526
5582
|
{
|
|
@@ -5603,14 +5659,24 @@ function createCli() {
|
|
|
5603
5659
|
});
|
|
5604
5660
|
cli.command(
|
|
5605
5661
|
"init [type]",
|
|
5606
|
-
"Initialize project configurations and resources (e.g. 'mason init env')"
|
|
5607
|
-
).option("-d, --dry-run", "Preview changes without writing to disk").option("-o, --overwrite", "Overwrite existing .env
|
|
5662
|
+
"Initialize project configurations and resources (e.g. 'mason init env', 'mason init env-examples')"
|
|
5663
|
+
).option("-d, --dry-run", "Preview changes without writing to disk").option("-o, --overwrite", "Overwrite existing files").example("mason init env").example("mason init env --overwrite").example("mason init env --dry-run").example("mason init env-examples").example("mason init env-examples --overwrite").example("mason init env-examples --dry-run").action(async (type, flags = {}) => {
|
|
5608
5664
|
try {
|
|
5609
5665
|
await handleInit(type, flags);
|
|
5610
5666
|
} catch (err) {
|
|
5611
5667
|
handleCliError(err);
|
|
5612
5668
|
}
|
|
5613
5669
|
});
|
|
5670
|
+
cli.command(
|
|
5671
|
+
"env-examples",
|
|
5672
|
+
"Shorthand for 'mason init env-examples'"
|
|
5673
|
+
).option("-d, --dry-run", "Preview changes without writing to disk").option("-o, --overwrite", "Overwrite existing .env*.example files").action(async (flags = {}) => {
|
|
5674
|
+
try {
|
|
5675
|
+
await handleInit("env-examples", flags);
|
|
5676
|
+
} catch (err) {
|
|
5677
|
+
handleCliError(err);
|
|
5678
|
+
}
|
|
5679
|
+
});
|
|
5614
5680
|
const createSubtypes = [
|
|
5615
5681
|
"feature",
|
|
5616
5682
|
"shared",
|
|
@@ -5642,7 +5708,7 @@ function handleCliError(err) {
|
|
|
5642
5708
|
process.exit(0);
|
|
5643
5709
|
}
|
|
5644
5710
|
const message = err instanceof Error ? err.message : String(err);
|
|
5645
|
-
|
|
5711
|
+
p16__namespace.log.error(pc16__default.default.red(`Error: ${message}`));
|
|
5646
5712
|
if (process.env.VITEST) {
|
|
5647
5713
|
throw err;
|
|
5648
5714
|
}
|