@solid-stack/mason 1.0.11 → 1.0.12
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 +158 -93
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +157 -92
- package/dist/bin.js.map +1 -1
- package/dist/index.cjs +160 -93
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +158 -93
- package/dist/index.js.map +1 -1
- package/dist/utils/registry.d.ts +18 -0
- package/dist/utils/registry.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import fs3 from 'fs';
|
|
2
|
-
import
|
|
2
|
+
import path3 from 'path';
|
|
3
3
|
import * as p4 from '@clack/prompts';
|
|
4
4
|
import pc13 from 'picocolors';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
@@ -75,7 +75,7 @@ function isValidIdentifier(str) {
|
|
|
75
75
|
}
|
|
76
76
|
function writeFileSafely(absolutePath, content, options = {}) {
|
|
77
77
|
const projectRoot = options.projectRoot || process.cwd();
|
|
78
|
-
const relPath =
|
|
78
|
+
const relPath = path3.relative(projectRoot, absolutePath).replace(/\\/g, "/");
|
|
79
79
|
const existedBefore = fs3.existsSync(absolutePath);
|
|
80
80
|
if (options.dryRun) {
|
|
81
81
|
return {
|
|
@@ -95,7 +95,7 @@ function writeFileSafely(absolutePath, content, options = {}) {
|
|
|
95
95
|
existedBefore: true
|
|
96
96
|
};
|
|
97
97
|
}
|
|
98
|
-
const dir =
|
|
98
|
+
const dir = path3.dirname(absolutePath);
|
|
99
99
|
if (!fs3.existsSync(dir)) {
|
|
100
100
|
fs3.mkdirSync(dir, { recursive: true });
|
|
101
101
|
}
|
|
@@ -126,20 +126,20 @@ function printGeneratedFiles(files, isDryRun = false) {
|
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
function findProjectRoot(startDir = process.cwd()) {
|
|
129
|
-
let current =
|
|
129
|
+
let current = path3.resolve(startDir);
|
|
130
130
|
while (true) {
|
|
131
|
-
if (fs3.existsSync(
|
|
131
|
+
if (fs3.existsSync(path3.join(current, "package.json"))) {
|
|
132
132
|
return current;
|
|
133
133
|
}
|
|
134
|
-
const parent =
|
|
134
|
+
const parent = path3.dirname(current);
|
|
135
135
|
if (parent === current) {
|
|
136
|
-
return
|
|
136
|
+
return path3.resolve(startDir);
|
|
137
137
|
}
|
|
138
138
|
current = parent;
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
141
|
function resolveFeaturesDir(projectRoot) {
|
|
142
|
-
return
|
|
142
|
+
return path3.join(projectRoot, "features");
|
|
143
143
|
}
|
|
144
144
|
function listExistingFeatures(projectRoot) {
|
|
145
145
|
const featuresDir = resolveFeaturesDir(projectRoot);
|
|
@@ -155,14 +155,14 @@ function listDomainInterfaces(projectRoot, featureName) {
|
|
|
155
155
|
const results = [];
|
|
156
156
|
const features = featureName ? [featureName] : listExistingFeatures(projectRoot);
|
|
157
157
|
for (const feat of features) {
|
|
158
|
-
const domainDir =
|
|
158
|
+
const domainDir = path3.join(resolveFeaturesDir(projectRoot), feat, "domain");
|
|
159
159
|
if (!fs3.existsSync(domainDir)) continue;
|
|
160
160
|
try {
|
|
161
161
|
const files = fs3.readdirSync(domainDir);
|
|
162
162
|
for (const file of files) {
|
|
163
163
|
if (file.endsWith(".ts") && !file.endsWith(".test.ts") && !file.endsWith(".d.ts")) {
|
|
164
164
|
const name = file.replace(/\.ts$/, "");
|
|
165
|
-
const fullPath =
|
|
165
|
+
const fullPath = path3.join(domainDir, file);
|
|
166
166
|
if (/^I[A-Z]/.test(name)) {
|
|
167
167
|
results.push({
|
|
168
168
|
name,
|
|
@@ -193,7 +193,7 @@ function listDomainEntities(projectRoot, featureName) {
|
|
|
193
193
|
const results = [];
|
|
194
194
|
const features = featureName ? [featureName] : listExistingFeatures(projectRoot);
|
|
195
195
|
for (const feat of features) {
|
|
196
|
-
const domainDir =
|
|
196
|
+
const domainDir = path3.join(resolveFeaturesDir(projectRoot), feat, "domain");
|
|
197
197
|
if (!fs3.existsSync(domainDir)) continue;
|
|
198
198
|
try {
|
|
199
199
|
const files = fs3.readdirSync(domainDir);
|
|
@@ -203,7 +203,7 @@ function listDomainEntities(projectRoot, featureName) {
|
|
|
203
203
|
if (!/^I[A-Z]/.test(name)) {
|
|
204
204
|
results.push({
|
|
205
205
|
name,
|
|
206
|
-
fullPath:
|
|
206
|
+
fullPath: path3.join(domainDir, file),
|
|
207
207
|
feature: feat
|
|
208
208
|
});
|
|
209
209
|
}
|
|
@@ -218,7 +218,7 @@ function listUseCases(projectRoot, featureName) {
|
|
|
218
218
|
const results = [];
|
|
219
219
|
const features = featureName ? [featureName] : listExistingFeatures(projectRoot);
|
|
220
220
|
for (const feat of features) {
|
|
221
|
-
const useCasesDir =
|
|
221
|
+
const useCasesDir = path3.join(resolveFeaturesDir(projectRoot), feat, "useCases");
|
|
222
222
|
if (!fs3.existsSync(useCasesDir)) continue;
|
|
223
223
|
try {
|
|
224
224
|
const files = fs3.readdirSync(useCasesDir);
|
|
@@ -227,7 +227,7 @@ function listUseCases(projectRoot, featureName) {
|
|
|
227
227
|
const name = file.replace(/\.ts$/, "");
|
|
228
228
|
results.push({
|
|
229
229
|
name,
|
|
230
|
-
fullPath:
|
|
230
|
+
fullPath: path3.join(useCasesDir, file),
|
|
231
231
|
feature: feat
|
|
232
232
|
});
|
|
233
233
|
}
|
|
@@ -323,40 +323,105 @@ async function promptProperties(options = {}) {
|
|
|
323
323
|
return properties;
|
|
324
324
|
}
|
|
325
325
|
var DEFAULT_REGISTRY_BASE = "https://raw.githubusercontent.com/solid-stack-digital/mason-registry/main";
|
|
326
|
+
function normalizeRegistryUrl(urlOrPath, baseDir) {
|
|
327
|
+
let trimmed = urlOrPath.trim();
|
|
328
|
+
const gitSshRegex = /^git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/;
|
|
329
|
+
const sshMatch = trimmed.match(gitSshRegex);
|
|
330
|
+
if (sshMatch && sshMatch[1] && sshMatch[2]) {
|
|
331
|
+
return `https://raw.githubusercontent.com/${sshMatch[1]}/${sshMatch[2]}/main`;
|
|
332
|
+
}
|
|
333
|
+
const githubWebRegex = /^https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?(?:\/tree\/([^/]+))?\/?$/;
|
|
334
|
+
const webMatch = trimmed.match(githubWebRegex);
|
|
335
|
+
if (webMatch && webMatch[1] && webMatch[2]) {
|
|
336
|
+
const owner = webMatch[1];
|
|
337
|
+
const repo = webMatch[2];
|
|
338
|
+
const branch = webMatch[3] || "main";
|
|
339
|
+
return `https://raw.githubusercontent.com/${owner}/${repo}/${branch}`;
|
|
340
|
+
}
|
|
341
|
+
if (baseDir && (trimmed.startsWith("./") || trimmed.startsWith("../") || trimmed === "." || trimmed === "..")) {
|
|
342
|
+
return path3.resolve(baseDir, trimmed);
|
|
343
|
+
}
|
|
344
|
+
return trimmed;
|
|
345
|
+
}
|
|
346
|
+
function findLocalRegistry(startDir = process.cwd()) {
|
|
347
|
+
let current = path3.resolve(startDir);
|
|
348
|
+
while (true) {
|
|
349
|
+
const candidate = path3.join(current, "mason-registry");
|
|
350
|
+
if (fs3.existsSync(candidate) && fs3.existsSync(path3.join(candidate, "index.json"))) {
|
|
351
|
+
return candidate;
|
|
352
|
+
}
|
|
353
|
+
const parent = path3.dirname(current);
|
|
354
|
+
if (parent === current) break;
|
|
355
|
+
current = parent;
|
|
356
|
+
}
|
|
357
|
+
return null;
|
|
358
|
+
}
|
|
326
359
|
function getRegistryBase(projectRoot, override) {
|
|
360
|
+
const rootDir = projectRoot ? path3.resolve(projectRoot) : process.cwd();
|
|
327
361
|
if (override && override.trim()) {
|
|
328
|
-
return override.trim();
|
|
362
|
+
return normalizeRegistryUrl(override.trim(), rootDir);
|
|
329
363
|
}
|
|
330
364
|
if (process.env.MASON_REGISTRY_URL && process.env.MASON_REGISTRY_URL.trim()) {
|
|
331
|
-
return process.env.MASON_REGISTRY_URL.trim();
|
|
365
|
+
return normalizeRegistryUrl(process.env.MASON_REGISTRY_URL.trim(), rootDir);
|
|
332
366
|
}
|
|
333
|
-
|
|
334
|
-
|
|
367
|
+
const configLocations = [
|
|
368
|
+
path3.join(rootDir, "mason.config.json"),
|
|
369
|
+
path3.join(process.cwd(), "mason.config.json")
|
|
370
|
+
];
|
|
371
|
+
for (const configPath of configLocations) {
|
|
335
372
|
if (fs3.existsSync(configPath)) {
|
|
336
373
|
try {
|
|
337
374
|
const config = JSON.parse(fs3.readFileSync(configPath, "utf-8"));
|
|
338
375
|
if (config.registry && typeof config.registry === "string") {
|
|
339
|
-
return config.registry.trim();
|
|
376
|
+
return normalizeRegistryUrl(config.registry.trim(), path3.dirname(configPath));
|
|
340
377
|
}
|
|
341
378
|
} catch {
|
|
342
379
|
}
|
|
343
380
|
}
|
|
344
381
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
382
|
+
const pkgLocations = [
|
|
383
|
+
path3.join(rootDir, "package.json"),
|
|
384
|
+
path3.join(process.cwd(), "package.json")
|
|
385
|
+
];
|
|
386
|
+
for (const pkgPath of pkgLocations) {
|
|
387
|
+
if (fs3.existsSync(pkgPath)) {
|
|
388
|
+
try {
|
|
389
|
+
const pkg = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
|
|
390
|
+
if (pkg.mason?.registry && typeof pkg.mason.registry === "string") {
|
|
391
|
+
return normalizeRegistryUrl(pkg.mason.registry.trim(), path3.dirname(pkgPath));
|
|
392
|
+
}
|
|
393
|
+
} catch {
|
|
394
|
+
}
|
|
349
395
|
}
|
|
350
396
|
}
|
|
397
|
+
const localRegistry = findLocalRegistry(rootDir);
|
|
398
|
+
if (localRegistry) {
|
|
399
|
+
return localRegistry;
|
|
400
|
+
}
|
|
351
401
|
return DEFAULT_REGISTRY_BASE;
|
|
352
402
|
}
|
|
353
403
|
async function fetchRegistryFile(registryBase, relPath) {
|
|
354
404
|
const cleanRelPath = relPath.replace(/^\/+/, "");
|
|
355
405
|
if (registryBase.startsWith("http://") || registryBase.startsWith("https://")) {
|
|
356
406
|
const url = `${registryBase.replace(/\/+$/, "")}/${cleanRelPath}`;
|
|
357
|
-
const
|
|
407
|
+
const headers = {};
|
|
408
|
+
const token = process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
|
|
409
|
+
if (token) {
|
|
410
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
411
|
+
}
|
|
412
|
+
const res = await fetch(url, { headers });
|
|
358
413
|
if (!res.ok) {
|
|
359
|
-
|
|
414
|
+
let extraHint = "";
|
|
415
|
+
if (res.status === 404) {
|
|
416
|
+
extraHint = `
|
|
417
|
+
Possible reasons:
|
|
418
|
+
\u2022 If using a private GitHub repository, ensure GITHUB_TOKEN is set in your environment.
|
|
419
|
+
\u2022 If your registry has not yet been pushed to GitHub, point to your local directory:
|
|
420
|
+
- CLI flag: mason import ... --registry /path/to/mason-registry
|
|
421
|
+
- Environment: export MASON_REGISTRY_URL=/path/to/mason-registry
|
|
422
|
+
- Config file: Create mason.config.json with { "registry": "/path/to/mason-registry" }`;
|
|
423
|
+
}
|
|
424
|
+
throw new Error(`Failed to fetch ${cleanRelPath} from ${url} (HTTP ${res.status}: ${res.statusText})${extraHint}`);
|
|
360
425
|
}
|
|
361
426
|
return await res.text();
|
|
362
427
|
}
|
|
@@ -364,7 +429,7 @@ async function fetchRegistryFile(registryBase, relPath) {
|
|
|
364
429
|
if (baseDir.startsWith("file://")) {
|
|
365
430
|
baseDir = fileURLToPath(baseDir);
|
|
366
431
|
}
|
|
367
|
-
const filePath =
|
|
432
|
+
const filePath = path3.resolve(baseDir, cleanRelPath);
|
|
368
433
|
if (!fs3.existsSync(filePath)) {
|
|
369
434
|
throw new Error(`Registry file not found at ${filePath}`);
|
|
370
435
|
}
|
|
@@ -430,14 +495,14 @@ function findClosestMatch(target, candidates) {
|
|
|
430
495
|
return null;
|
|
431
496
|
}
|
|
432
497
|
function detectPackageManager(projectRoot) {
|
|
433
|
-
if (fs3.existsSync(
|
|
434
|
-
if (fs3.existsSync(
|
|
435
|
-
if (fs3.existsSync(
|
|
498
|
+
if (fs3.existsSync(path3.join(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
|
|
499
|
+
if (fs3.existsSync(path3.join(projectRoot, "yarn.lock"))) return "yarn";
|
|
500
|
+
if (fs3.existsSync(path3.join(projectRoot, "bun.lockb")) || fs3.existsSync(path3.join(projectRoot, "bun.lock"))) return "bun";
|
|
436
501
|
return "npm";
|
|
437
502
|
}
|
|
438
503
|
function getMissingNpmPackages(projectRoot, requiredPackages) {
|
|
439
504
|
if (!requiredPackages || requiredPackages.length === 0) return [];
|
|
440
|
-
const pkgJsonPath =
|
|
505
|
+
const pkgJsonPath = path3.join(projectRoot, "package.json");
|
|
441
506
|
if (!fs3.existsSync(pkgJsonPath)) {
|
|
442
507
|
return requiredPackages;
|
|
443
508
|
}
|
|
@@ -499,30 +564,30 @@ function getTemplatesDir() {
|
|
|
499
564
|
if (cachedTemplatesDir && fs3.existsSync(cachedTemplatesDir)) {
|
|
500
565
|
return cachedTemplatesDir;
|
|
501
566
|
}
|
|
502
|
-
const currentDir = typeof __dirname !== "undefined" ? __dirname :
|
|
503
|
-
const cand1 =
|
|
567
|
+
const currentDir = typeof __dirname !== "undefined" ? __dirname : path3.dirname(fileURLToPath(import.meta.url));
|
|
568
|
+
const cand1 = path3.resolve(currentDir, "../../templates");
|
|
504
569
|
if (fs3.existsSync(cand1)) {
|
|
505
570
|
cachedTemplatesDir = cand1;
|
|
506
571
|
return cand1;
|
|
507
572
|
}
|
|
508
|
-
const cand2 =
|
|
573
|
+
const cand2 = path3.resolve(currentDir, "../templates");
|
|
509
574
|
if (fs3.existsSync(cand2)) {
|
|
510
575
|
cachedTemplatesDir = cand2;
|
|
511
576
|
return cand2;
|
|
512
577
|
}
|
|
513
|
-
const cand3 =
|
|
578
|
+
const cand3 = path3.resolve(currentDir, "templates");
|
|
514
579
|
if (fs3.existsSync(cand3)) {
|
|
515
580
|
cachedTemplatesDir = cand3;
|
|
516
581
|
return cand3;
|
|
517
582
|
}
|
|
518
583
|
let curr = currentDir;
|
|
519
584
|
while (true) {
|
|
520
|
-
const candTemplates =
|
|
585
|
+
const candTemplates = path3.join(curr, "templates");
|
|
521
586
|
if (fs3.existsSync(candTemplates)) {
|
|
522
587
|
cachedTemplatesDir = candTemplates;
|
|
523
588
|
return candTemplates;
|
|
524
589
|
}
|
|
525
|
-
const parent =
|
|
590
|
+
const parent = path3.dirname(curr);
|
|
526
591
|
if (parent === curr) break;
|
|
527
592
|
curr = parent;
|
|
528
593
|
}
|
|
@@ -530,7 +595,7 @@ function getTemplatesDir() {
|
|
|
530
595
|
}
|
|
531
596
|
var templateCache = /* @__PURE__ */ new Map();
|
|
532
597
|
function loadTemplate(relativePath) {
|
|
533
|
-
const fullPath =
|
|
598
|
+
const fullPath = path3.isAbsolute(relativePath) ? relativePath : path3.join(getTemplatesDir(), relativePath);
|
|
534
599
|
return fs3.readFileSync(fullPath, "utf-8");
|
|
535
600
|
}
|
|
536
601
|
function renderTemplateFile(relativePath, context) {
|
|
@@ -616,8 +681,8 @@ function generateDomainEntityCode(name, kind = "interface", properties = []) {
|
|
|
616
681
|
function generateDomain(options) {
|
|
617
682
|
const projectRoot = options.projectRoot || findProjectRoot();
|
|
618
683
|
const entityName = toPascalCase(options.name);
|
|
619
|
-
const targetDir = options.targetDir ||
|
|
620
|
-
const filePath =
|
|
684
|
+
const targetDir = options.targetDir || path3.join(resolveFeaturesDir(projectRoot), options.feature, "domain");
|
|
685
|
+
const filePath = path3.join(targetDir, `${entityName}.ts`);
|
|
621
686
|
const code = generateDomainEntityCode(
|
|
622
687
|
entityName,
|
|
623
688
|
options.kind || "interface",
|
|
@@ -666,8 +731,8 @@ function generateInterfaceCode(ifaceName, kind = "abstractClass", entityName, me
|
|
|
666
731
|
function generateInterface(options) {
|
|
667
732
|
const projectRoot = options.projectRoot || findProjectRoot();
|
|
668
733
|
const ifaceName = ensureInterfacePrefix(options.name);
|
|
669
|
-
const targetDir = options.targetDir ||
|
|
670
|
-
const filePath =
|
|
734
|
+
const targetDir = options.targetDir || path3.join(resolveFeaturesDir(projectRoot), options.feature, "domain");
|
|
735
|
+
const filePath = path3.join(targetDir, `${ifaceName}.ts`);
|
|
671
736
|
const code = generateInterfaceCode(
|
|
672
737
|
ifaceName,
|
|
673
738
|
options.kind || "abstractClass",
|
|
@@ -912,21 +977,21 @@ function findInterfaceFile(projectRoot, ifaceName, featureName, customPath) {
|
|
|
912
977
|
];
|
|
913
978
|
const features = featureName ? [featureName, ...listExistingFeatures(projectRoot).filter((f) => f !== featureName)] : listExistingFeatures(projectRoot);
|
|
914
979
|
for (const feat of features) {
|
|
915
|
-
const domainDir =
|
|
980
|
+
const domainDir = path3.join(resolveFeaturesDir(projectRoot), feat, "domain");
|
|
916
981
|
if (!fs3.existsSync(domainDir)) continue;
|
|
917
982
|
for (const cand of candidateNames) {
|
|
918
|
-
const p1 =
|
|
983
|
+
const p1 = path3.join(domainDir, `${cand}.ts`);
|
|
919
984
|
if (fs3.existsSync(p1)) {
|
|
920
985
|
return { filePath: p1, ifaceName: cand, feature: feat };
|
|
921
986
|
}
|
|
922
987
|
}
|
|
923
988
|
}
|
|
924
989
|
for (const cand of candidateNames) {
|
|
925
|
-
const p1 =
|
|
990
|
+
const p1 = path3.join(projectRoot, "domain", `${cand}.ts`);
|
|
926
991
|
if (fs3.existsSync(p1)) return { filePath: p1, ifaceName: cand };
|
|
927
|
-
const p22 =
|
|
992
|
+
const p22 = path3.join(projectRoot, "src", "domain", `${cand}.ts`);
|
|
928
993
|
if (fs3.existsSync(p22)) return { filePath: p22, ifaceName: cand };
|
|
929
|
-
const p32 =
|
|
994
|
+
const p32 = path3.join(projectRoot, "interfaces", `${cand}.ts`);
|
|
930
995
|
if (fs3.existsSync(p32)) return { filePath: p32, ifaceName: cand };
|
|
931
996
|
}
|
|
932
997
|
return null;
|
|
@@ -1026,7 +1091,7 @@ function generateStubCode(stubClassName, ifaceName, entityName, featureName, met
|
|
|
1026
1091
|
const entitiesVar = `${entityVar}s`;
|
|
1027
1092
|
const idKey = `${entityVar}Id`;
|
|
1028
1093
|
const impPath = ifaceImportPath || `../domain/${ifaceName}.js`;
|
|
1029
|
-
const entityImportPath = ifaceImportPath ? `${
|
|
1094
|
+
const entityImportPath = ifaceImportPath ? `${path3.dirname(ifaceImportPath)}/${baseEntity}.js` : `../domain/${baseEntity}.js`;
|
|
1030
1095
|
const importsByFrom = /* @__PURE__ */ new Map();
|
|
1031
1096
|
for (const imp of domainImports) {
|
|
1032
1097
|
if (imp.name === ifaceName || imp.name === baseEntity) continue;
|
|
@@ -1075,7 +1140,7 @@ function generateConcreteInfraCode(className, ifaceName, dependencies = [], meth
|
|
|
1075
1140
|
if (baseEntity) {
|
|
1076
1141
|
finalMethods = synthesizeCrudMethods(baseEntity);
|
|
1077
1142
|
if (!finalDomainImports.some((imp) => imp.name === baseEntity)) {
|
|
1078
|
-
const importPath = ifaceImportPath ? `${
|
|
1143
|
+
const importPath = ifaceImportPath ? `${path3.dirname(ifaceImportPath)}/${baseEntity}.js` : `../domain/${baseEntity}.js`;
|
|
1079
1144
|
finalDomainImports.push({
|
|
1080
1145
|
name: baseEntity,
|
|
1081
1146
|
from: importPath,
|
|
@@ -1120,8 +1185,8 @@ function generateInfrastructure(options) {
|
|
|
1120
1185
|
const projectRoot = options.projectRoot || findProjectRoot();
|
|
1121
1186
|
const className = toPascalCase(options.name);
|
|
1122
1187
|
const isFeatureScope = options.scope !== "global" && Boolean(options.feature);
|
|
1123
|
-
const targetDir = options.targetDir || (isFeatureScope ?
|
|
1124
|
-
const filePath =
|
|
1188
|
+
const targetDir = options.targetDir || (isFeatureScope ? path3.join(resolveFeaturesDir(projectRoot), options.feature, "infrastructure") : path3.join(projectRoot, "infrastructure"));
|
|
1189
|
+
const filePath = path3.join(targetDir, `${className}.ts`);
|
|
1125
1190
|
let code;
|
|
1126
1191
|
if (options.implementsInterface) {
|
|
1127
1192
|
const rawIfaceName = options.implementsInterface;
|
|
@@ -1135,7 +1200,7 @@ function generateInfrastructure(options) {
|
|
|
1135
1200
|
const ifaceFilePath = hierarchy.ifaceFilePath;
|
|
1136
1201
|
let ifaceImportPath;
|
|
1137
1202
|
if (ifaceFilePath) {
|
|
1138
|
-
let rel =
|
|
1203
|
+
let rel = path3.relative(targetDir, ifaceFilePath).replace(/\\/g, "/").replace(/\.ts$/, ".js");
|
|
1139
1204
|
if (!rel.startsWith(".")) rel = "./" + rel;
|
|
1140
1205
|
ifaceImportPath = rel;
|
|
1141
1206
|
} else if (isFeatureScope) {
|
|
@@ -1148,8 +1213,8 @@ function generateInfrastructure(options) {
|
|
|
1148
1213
|
if (new RegExp(`\\b${item.name}\\b`).test(allSignatures)) {
|
|
1149
1214
|
let fromPath;
|
|
1150
1215
|
if (imp.specifier.startsWith(".") && ifaceFilePath) {
|
|
1151
|
-
const absTarget =
|
|
1152
|
-
let rel =
|
|
1216
|
+
const absTarget = path3.resolve(path3.dirname(ifaceFilePath), imp.specifier);
|
|
1217
|
+
let rel = path3.relative(targetDir, absTarget).replace(/\\/g, "/");
|
|
1153
1218
|
if (!rel.startsWith(".")) rel = "./" + rel;
|
|
1154
1219
|
fromPath = rel;
|
|
1155
1220
|
} else {
|
|
@@ -1336,8 +1401,8 @@ function generateUseCase(options) {
|
|
|
1336
1401
|
const files = [];
|
|
1337
1402
|
const projectRoot = options.projectRoot || findProjectRoot();
|
|
1338
1403
|
const ucName = toPascalCase(options.name);
|
|
1339
|
-
const targetDir = options.targetDir ||
|
|
1340
|
-
const filePath =
|
|
1404
|
+
const targetDir = options.targetDir || path3.join(resolveFeaturesDir(projectRoot), options.feature, "useCases");
|
|
1405
|
+
const filePath = path3.join(targetDir, `${ucName}.ts`);
|
|
1341
1406
|
const code = generateUseCaseCode(
|
|
1342
1407
|
ucName,
|
|
1343
1408
|
options.dependencies || [],
|
|
@@ -1353,7 +1418,7 @@ function generateUseCase(options) {
|
|
|
1353
1418
|
})
|
|
1354
1419
|
);
|
|
1355
1420
|
if (options.includeTest) {
|
|
1356
|
-
const testPath =
|
|
1421
|
+
const testPath = path3.join(targetDir, `${ucName}.test.ts`);
|
|
1357
1422
|
const testCode = generateUseCaseTestCode(ucName, options.dependencies || []);
|
|
1358
1423
|
files.push(
|
|
1359
1424
|
writeFileSafely(testPath, testCode, {
|
|
@@ -1421,9 +1486,9 @@ function generateHttpHandler(options) {
|
|
|
1421
1486
|
const files = [];
|
|
1422
1487
|
const projectRoot = options.projectRoot || findProjectRoot();
|
|
1423
1488
|
const className = toPascalCase(options.name);
|
|
1424
|
-
const pxDir =
|
|
1425
|
-
const handlersDir =
|
|
1426
|
-
const pxIndexPath =
|
|
1489
|
+
const pxDir = path3.join(resolveFeaturesDir(projectRoot), options.feature, "pxExpress");
|
|
1490
|
+
const handlersDir = path3.join(pxDir, "handlers");
|
|
1491
|
+
const pxIndexPath = path3.join(pxDir, "index.ts");
|
|
1427
1492
|
if (!fs3.existsSync(pxIndexPath)) {
|
|
1428
1493
|
const featurePath = options.routePrefix || `/${options.feature.toLowerCase()}`;
|
|
1429
1494
|
const pxIndexContent = renderTemplate(expressIndexTemplate, {
|
|
@@ -1437,7 +1502,7 @@ function generateHttpHandler(options) {
|
|
|
1437
1502
|
})
|
|
1438
1503
|
);
|
|
1439
1504
|
}
|
|
1440
|
-
const handlerFilePath =
|
|
1505
|
+
const handlerFilePath = path3.join(handlersDir, `${className}.ts`);
|
|
1441
1506
|
const code = generateHttpHandlerCode(
|
|
1442
1507
|
className,
|
|
1443
1508
|
options.method || "get",
|
|
@@ -1458,7 +1523,7 @@ function generateHttpHandler(options) {
|
|
|
1458
1523
|
return files;
|
|
1459
1524
|
}
|
|
1460
1525
|
function updateOrGenerateDiProvider(featureDir, featureName, bindings = [], options = {}) {
|
|
1461
|
-
const providerPath =
|
|
1526
|
+
const providerPath = path3.join(featureDir, "diProvider.ts");
|
|
1462
1527
|
const pascalFeature = toPascalCase(featureName);
|
|
1463
1528
|
const providerModuleName = `${pascalFeature}Provider`;
|
|
1464
1529
|
if (fs3.existsSync(providerPath) && !options.overwrite) {
|
|
@@ -1521,7 +1586,7 @@ function generateFeature(options) {
|
|
|
1521
1586
|
const projectRoot = options.projectRoot || findProjectRoot();
|
|
1522
1587
|
const rawName = options.name.trim();
|
|
1523
1588
|
const featureName = toCamelCase(rawName);
|
|
1524
|
-
const targetDir = options.targetDir ||
|
|
1589
|
+
const targetDir = options.targetDir || path3.join(resolveFeaturesDir(projectRoot), featureName);
|
|
1525
1590
|
const routePath = options.routePath || `/${featureName}`;
|
|
1526
1591
|
const rawEntities = [];
|
|
1527
1592
|
if (options.entityNames && options.entityNames.length > 0) {
|
|
@@ -1542,7 +1607,7 @@ function generateFeature(options) {
|
|
|
1542
1607
|
const domainFile = generateDomain({
|
|
1543
1608
|
name: ent,
|
|
1544
1609
|
feature: featureName,
|
|
1545
|
-
targetDir:
|
|
1610
|
+
targetDir: path3.join(targetDir, "domain"),
|
|
1546
1611
|
projectRoot,
|
|
1547
1612
|
dryRun: options.dryRun,
|
|
1548
1613
|
overwrite: options.overwrite,
|
|
@@ -1562,7 +1627,7 @@ function generateFeature(options) {
|
|
|
1562
1627
|
const ifaceFile = generateInterface({
|
|
1563
1628
|
name: ifaceName,
|
|
1564
1629
|
feature: featureName,
|
|
1565
|
-
targetDir:
|
|
1630
|
+
targetDir: path3.join(targetDir, "domain"),
|
|
1566
1631
|
entityName: ent,
|
|
1567
1632
|
projectRoot,
|
|
1568
1633
|
dryRun: options.dryRun,
|
|
@@ -1579,7 +1644,7 @@ function generateFeature(options) {
|
|
|
1579
1644
|
const stubFile = generateInfrastructure({
|
|
1580
1645
|
name: stubName,
|
|
1581
1646
|
feature: featureName,
|
|
1582
|
-
targetDir:
|
|
1647
|
+
targetDir: path3.join(targetDir, "infrastructure"),
|
|
1583
1648
|
kind: "stub",
|
|
1584
1649
|
implementsInterface: ifaceName,
|
|
1585
1650
|
entityName: ent,
|
|
@@ -1621,7 +1686,7 @@ function generateFeature(options) {
|
|
|
1621
1686
|
const ucFiles = generateUseCase({
|
|
1622
1687
|
name: ucName,
|
|
1623
1688
|
feature: featureName,
|
|
1624
|
-
targetDir:
|
|
1689
|
+
targetDir: path3.join(targetDir, "useCases"),
|
|
1625
1690
|
dependencies: options.includeInterface !== false ? [ifaceName] : [],
|
|
1626
1691
|
inputProperties: [{ name: idParam, type: "string" }],
|
|
1627
1692
|
outputProperties: [{ name: entVar, type: primaryEntity }],
|
|
@@ -1666,7 +1731,7 @@ function generateFeature(options) {
|
|
|
1666
1731
|
const ucFiles = generateUseCase({
|
|
1667
1732
|
name: ucName,
|
|
1668
1733
|
feature: featureName,
|
|
1669
|
-
targetDir:
|
|
1734
|
+
targetDir: path3.join(targetDir, "useCases"),
|
|
1670
1735
|
dependencies: deps,
|
|
1671
1736
|
inputProperties: [{ name: entVar, type: ent }],
|
|
1672
1737
|
outputProperties: [{ name: entVar, type: ent }],
|
|
@@ -1699,7 +1764,7 @@ function generateFeature(options) {
|
|
|
1699
1764
|
const ucFiles = generateUseCase({
|
|
1700
1765
|
name: ucName,
|
|
1701
1766
|
feature: featureName,
|
|
1702
|
-
targetDir:
|
|
1767
|
+
targetDir: path3.join(targetDir, "useCases"),
|
|
1703
1768
|
dependencies: deps,
|
|
1704
1769
|
inputProperties: [{ name: idParam, type: "string" }],
|
|
1705
1770
|
outputProperties: [{ name: entVar, type: ent }],
|
|
@@ -1732,7 +1797,7 @@ function generateFeature(options) {
|
|
|
1732
1797
|
const ucFiles = generateUseCase({
|
|
1733
1798
|
name: ucName,
|
|
1734
1799
|
feature: featureName,
|
|
1735
|
-
targetDir:
|
|
1800
|
+
targetDir: path3.join(targetDir, "useCases"),
|
|
1736
1801
|
dependencies: deps,
|
|
1737
1802
|
inputProperties: [
|
|
1738
1803
|
{ name: "page", type: "number", optional: true },
|
|
@@ -1776,7 +1841,7 @@ function generateFeature(options) {
|
|
|
1776
1841
|
const ucFiles = generateUseCase({
|
|
1777
1842
|
name: ucName,
|
|
1778
1843
|
feature: featureName,
|
|
1779
|
-
targetDir:
|
|
1844
|
+
targetDir: path3.join(targetDir, "useCases"),
|
|
1780
1845
|
dependencies: deps,
|
|
1781
1846
|
inputProperties: [{ name: entVar, type: ent }],
|
|
1782
1847
|
outputProperties: [{ name: entVar, type: ent }],
|
|
@@ -1809,7 +1874,7 @@ function generateFeature(options) {
|
|
|
1809
1874
|
const ucFiles = generateUseCase({
|
|
1810
1875
|
name: ucName,
|
|
1811
1876
|
feature: featureName,
|
|
1812
|
-
targetDir:
|
|
1877
|
+
targetDir: path3.join(targetDir, "useCases"),
|
|
1813
1878
|
dependencies: deps,
|
|
1814
1879
|
inputProperties: [{ name: idParam, type: "string" }],
|
|
1815
1880
|
outputProperties: [{ name: "success", type: "boolean" }],
|
|
@@ -1846,7 +1911,7 @@ function generateFeature(options) {
|
|
|
1846
1911
|
const ucFiles = generateUseCase({
|
|
1847
1912
|
name: ucName,
|
|
1848
1913
|
feature: featureName,
|
|
1849
|
-
targetDir:
|
|
1914
|
+
targetDir: path3.join(targetDir, "useCases"),
|
|
1850
1915
|
dependencies: customUc.dependencies || [],
|
|
1851
1916
|
inputProperties: customUc.inputProperties || [],
|
|
1852
1917
|
outputProperties: customUc.outputProperties || [],
|
|
@@ -1878,8 +1943,8 @@ function generateFeature(options) {
|
|
|
1878
1943
|
}
|
|
1879
1944
|
}
|
|
1880
1945
|
if (options.includeExpress !== false) {
|
|
1881
|
-
const pxDir =
|
|
1882
|
-
const pxIndexPath =
|
|
1946
|
+
const pxDir = path3.join(targetDir, "pxExpress");
|
|
1947
|
+
const pxIndexPath = path3.join(pxDir, "index.ts");
|
|
1883
1948
|
if (!files.some((f) => f.absolutePath === pxIndexPath)) {
|
|
1884
1949
|
const pxIndexContent = renderTemplate(expressIndexTemplate, { routePath });
|
|
1885
1950
|
files.push(
|
|
@@ -1922,7 +1987,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
1922
1987
|
).trim();
|
|
1923
1988
|
}
|
|
1924
1989
|
const normalizedName = toCamelCase(name);
|
|
1925
|
-
const defaultDir =
|
|
1990
|
+
const defaultDir = path3.relative(projectRoot, path3.join(resolveFeaturesDir(projectRoot), normalizedName));
|
|
1926
1991
|
let targetDirRel = defaultDir;
|
|
1927
1992
|
if (!flags.yes && !flags.target) {
|
|
1928
1993
|
targetDirRel = handleCancel(
|
|
@@ -1933,7 +1998,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
1933
1998
|
})
|
|
1934
1999
|
).trim();
|
|
1935
2000
|
}
|
|
1936
|
-
const targetDir = flags.target ?
|
|
2001
|
+
const targetDir = flags.target ? path3.resolve(projectRoot, flags.target) : path3.resolve(projectRoot, targetDirRel);
|
|
1937
2002
|
let includeExpress = flags.express !== void 0 ? Boolean(flags.express) : true;
|
|
1938
2003
|
let routePath = `/${normalizedName}`;
|
|
1939
2004
|
let includeDomain = true;
|
|
@@ -2601,7 +2666,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2601
2666
|
const infraFile = generateInfrastructure(options);
|
|
2602
2667
|
files.push(infraFile);
|
|
2603
2668
|
if (registerInProvider && scope === "feature" && feature && implementsInterface) {
|
|
2604
|
-
const featureDir =
|
|
2669
|
+
const featureDir = path3.join(resolveFeaturesDir(projectRoot), feature);
|
|
2605
2670
|
const providerFile = updateOrGenerateDiProvider(
|
|
2606
2671
|
featureDir,
|
|
2607
2672
|
feature,
|
|
@@ -2763,7 +2828,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
|
2763
2828
|
files.push(stubFile);
|
|
2764
2829
|
}
|
|
2765
2830
|
if (registerInProvider && generateStub) {
|
|
2766
|
-
const featureDir =
|
|
2831
|
+
const featureDir = path3.join(resolveFeaturesDir(projectRoot), feature);
|
|
2767
2832
|
const providerFile = updateOrGenerateDiProvider(
|
|
2768
2833
|
featureDir,
|
|
2769
2834
|
feature,
|
|
@@ -2951,21 +3016,21 @@ function generateInjectable(options) {
|
|
|
2951
3016
|
const className = toPascalCase(options.name);
|
|
2952
3017
|
let targetDir = "";
|
|
2953
3018
|
if (options.customPath) {
|
|
2954
|
-
targetDir =
|
|
3019
|
+
targetDir = path3.isAbsolute(options.customPath) ? options.customPath : path3.join(projectRoot, options.customPath);
|
|
2955
3020
|
} else if (options.location === "feature-service" && options.feature) {
|
|
2956
|
-
targetDir =
|
|
3021
|
+
targetDir = path3.join(resolveFeaturesDir(projectRoot), options.feature, "services");
|
|
2957
3022
|
} else if (options.location === "feature-transformer" && options.feature) {
|
|
2958
|
-
targetDir =
|
|
3023
|
+
targetDir = path3.join(resolveFeaturesDir(projectRoot), options.feature, "pxExpress", "transformers");
|
|
2959
3024
|
} else if (options.location === "module") {
|
|
2960
|
-
targetDir =
|
|
3025
|
+
targetDir = path3.join(projectRoot, "modules", className);
|
|
2961
3026
|
} else {
|
|
2962
|
-
targetDir = options.feature ?
|
|
3027
|
+
targetDir = options.feature ? path3.join(resolveFeaturesDir(projectRoot), options.feature, "services") : path3.join(projectRoot, "shared", className.toLowerCase());
|
|
2963
3028
|
}
|
|
2964
|
-
const filePath =
|
|
3029
|
+
const filePath = path3.join(targetDir, `${className}.ts`);
|
|
2965
3030
|
let ifaceName;
|
|
2966
3031
|
if (options.generateInterface) {
|
|
2967
3032
|
ifaceName = `I${className}`;
|
|
2968
|
-
const ifacePath =
|
|
3033
|
+
const ifacePath = path3.join(targetDir, `${ifaceName}.ts`);
|
|
2969
3034
|
const ifaceContent = renderTemplate(injectableInterfaceTemplate, { ifaceName });
|
|
2970
3035
|
files.push(
|
|
2971
3036
|
writeFileSafely(ifacePath, ifaceContent, {
|
|
@@ -3280,7 +3345,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3280
3345
|
}
|
|
3281
3346
|
const sharedDeps = manifest.dependencies?.shared || [];
|
|
3282
3347
|
for (const dep of sharedDeps) {
|
|
3283
|
-
const depPath =
|
|
3348
|
+
const depPath = path3.join(projectRoot, "src", "shared", dep);
|
|
3284
3349
|
if (!fs3.existsSync(depPath) && !importedModules.has(`shared:${dep}`)) {
|
|
3285
3350
|
p4.log.info(` \u21B3 Resolving required shared dependency: ${pc13.cyan(dep)}`);
|
|
3286
3351
|
await importModuleRecursive("shared", dep);
|
|
@@ -3288,7 +3353,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3288
3353
|
}
|
|
3289
3354
|
const featureDeps = manifest.dependencies?.features || [];
|
|
3290
3355
|
for (const dep of featureDeps) {
|
|
3291
|
-
const depPath =
|
|
3356
|
+
const depPath = path3.join(projectRoot, "src", "features", dep);
|
|
3292
3357
|
if (!fs3.existsSync(depPath) && !importedModules.has(`feature:${dep}`)) {
|
|
3293
3358
|
p4.log.info(` \u21B3 Resolving required feature dependency: ${pc13.cyan(dep)}`);
|
|
3294
3359
|
await importModuleRecursive("feature", dep);
|
|
@@ -3298,21 +3363,21 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3298
3363
|
requiredNpmPackages.add(pkg);
|
|
3299
3364
|
}
|
|
3300
3365
|
const folder = modType === "shared" ? "shared" : "features";
|
|
3301
|
-
const targetDir =
|
|
3366
|
+
const targetDir = path3.join(projectRoot, "src", folder, modName);
|
|
3302
3367
|
for (const file of manifest.files || []) {
|
|
3303
3368
|
if (file === "registry.json") continue;
|
|
3304
3369
|
const remoteFilePath = `${folder}/${modName}/${file}`;
|
|
3305
|
-
const localFilePath =
|
|
3370
|
+
const localFilePath = path3.join(targetDir, file);
|
|
3306
3371
|
if (fs3.existsSync(localFilePath) && !flags.overwrite) {
|
|
3307
|
-
p4.log.warn(` \u21B3 Skipping existing file: ${pc13.dim(
|
|
3372
|
+
p4.log.warn(` \u21B3 Skipping existing file: ${pc13.dim(path3.relative(projectRoot, localFilePath))} (use --overwrite to replace)`);
|
|
3308
3373
|
continue;
|
|
3309
3374
|
}
|
|
3310
3375
|
const content = await fetchRegistryFile(registryBase, remoteFilePath);
|
|
3311
3376
|
if (!flags.dryRun) {
|
|
3312
|
-
fs3.mkdirSync(
|
|
3377
|
+
fs3.mkdirSync(path3.dirname(localFilePath), { recursive: true });
|
|
3313
3378
|
fs3.writeFileSync(localFilePath, content, "utf-8");
|
|
3314
3379
|
}
|
|
3315
|
-
const displayPath =
|
|
3380
|
+
const displayPath = path3.relative(projectRoot, localFilePath);
|
|
3316
3381
|
totalWrittenFiles.push(displayPath);
|
|
3317
3382
|
p4.log.message(` ${pc13.green("+")} ${displayPath}`);
|
|
3318
3383
|
}
|
|
@@ -3439,6 +3504,6 @@ async function runCli(argv = process.argv) {
|
|
|
3439
3504
|
cli.parse(argv, { run: true });
|
|
3440
3505
|
}
|
|
3441
3506
|
|
|
3442
|
-
export { DEFAULT_REGISTRY_BASE, PromptCancelledError, concreteInfraTemplate, createCli, detectPackageManager, diProviderTemplate, domainClassTemplate, domainInterfaceTemplate, domainValueObjectTemplate, ensureInterfacePrefix, expressIndexTemplate, fetchModuleManifest, fetchRegistryFile, fetchRegistryIndex, findClosestMatch, findInterfaceFile, findProjectRoot, generateConcreteInfraCode, generateDomain, generateDomainEntityCode, generateFeature, generateHttpHandler, generateHttpHandlerCode, generateInfrastructure, generateInjectable, generateInjectableCode, generateInterface, generateInterfaceCode, generateStubCode, generateUseCase, generateUseCaseCode, generateUseCaseTestCode, getMissingNpmPackages, getRegistryBase, getTemplatesDir, handleCancel, handleCreate, handleImport, hbs, httpHandlerTemplate, injectableInterfaceTemplate, injectableTemplate, installNpmPackages, interfaceTemplate, isValidIdentifier, levenshteinDistance, listDomainEntities, listDomainInterfaces, listExistingFeatures, listUseCases, loadInterfaceHierarchy, loadTemplate, parseInterfaceMethodsAndImports, printBanner, printGeneratedFiles, promptProperties, removeInterfacePrefix, renderTemplate, renderTemplateFile, resolveFeaturesDir, runCli, stubInfraTemplate, synthesizeCrudMethods, toCamelCase, toKebabCase, toPascalCase, toPlural, toSingular, toStubName, updateOrGenerateDiProvider, useCaseTemplate, useCaseTestTemplate, writeFileSafely };
|
|
3507
|
+
export { DEFAULT_REGISTRY_BASE, PromptCancelledError, concreteInfraTemplate, createCli, detectPackageManager, diProviderTemplate, domainClassTemplate, domainInterfaceTemplate, domainValueObjectTemplate, ensureInterfacePrefix, expressIndexTemplate, fetchModuleManifest, fetchRegistryFile, fetchRegistryIndex, findClosestMatch, findInterfaceFile, findLocalRegistry, findProjectRoot, generateConcreteInfraCode, generateDomain, generateDomainEntityCode, generateFeature, generateHttpHandler, generateHttpHandlerCode, generateInfrastructure, generateInjectable, generateInjectableCode, generateInterface, generateInterfaceCode, generateStubCode, generateUseCase, generateUseCaseCode, generateUseCaseTestCode, getMissingNpmPackages, getRegistryBase, getTemplatesDir, handleCancel, handleCreate, handleImport, hbs, httpHandlerTemplate, injectableInterfaceTemplate, injectableTemplate, installNpmPackages, interfaceTemplate, isValidIdentifier, levenshteinDistance, listDomainEntities, listDomainInterfaces, listExistingFeatures, listUseCases, loadInterfaceHierarchy, loadTemplate, normalizeRegistryUrl, parseInterfaceMethodsAndImports, printBanner, printGeneratedFiles, promptProperties, removeInterfacePrefix, renderTemplate, renderTemplateFile, resolveFeaturesDir, runCli, stubInfraTemplate, synthesizeCrudMethods, toCamelCase, toKebabCase, toPascalCase, toPlural, toSingular, toStubName, updateOrGenerateDiProvider, useCaseTemplate, useCaseTestTemplate, writeFileSafely };
|
|
3443
3508
|
//# sourceMappingURL=index.js.map
|
|
3444
3509
|
//# sourceMappingURL=index.js.map
|