@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/bin.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { cac } from 'cac';
|
|
3
3
|
import * as p3 from '@clack/prompts';
|
|
4
4
|
import pc13 from 'picocolors';
|
|
5
|
-
import
|
|
5
|
+
import path15 from 'path';
|
|
6
6
|
import fs7 from 'fs';
|
|
7
7
|
import { fileURLToPath } from 'url';
|
|
8
8
|
import Handlebars from 'handlebars';
|
|
@@ -10,7 +10,7 @@ import { execSync } from 'child_process';
|
|
|
10
10
|
|
|
11
11
|
function writeFileSafely(absolutePath, content, options = {}) {
|
|
12
12
|
const projectRoot = options.projectRoot || process.cwd();
|
|
13
|
-
const relPath =
|
|
13
|
+
const relPath = path15.relative(projectRoot, absolutePath).replace(/\\/g, "/");
|
|
14
14
|
const existedBefore = fs7.existsSync(absolutePath);
|
|
15
15
|
if (options.dryRun) {
|
|
16
16
|
return {
|
|
@@ -30,7 +30,7 @@ function writeFileSafely(absolutePath, content, options = {}) {
|
|
|
30
30
|
existedBefore: true
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
|
-
const dir =
|
|
33
|
+
const dir = path15.dirname(absolutePath);
|
|
34
34
|
if (!fs7.existsSync(dir)) {
|
|
35
35
|
fs7.mkdirSync(dir, { recursive: true });
|
|
36
36
|
}
|
|
@@ -125,20 +125,20 @@ function toStubName(ifaceName) {
|
|
|
125
125
|
return `Stub${base}`;
|
|
126
126
|
}
|
|
127
127
|
function findProjectRoot(startDir = process.cwd()) {
|
|
128
|
-
let current =
|
|
128
|
+
let current = path15.resolve(startDir);
|
|
129
129
|
while (true) {
|
|
130
|
-
if (fs7.existsSync(
|
|
130
|
+
if (fs7.existsSync(path15.join(current, "package.json"))) {
|
|
131
131
|
return current;
|
|
132
132
|
}
|
|
133
|
-
const parent =
|
|
133
|
+
const parent = path15.dirname(current);
|
|
134
134
|
if (parent === current) {
|
|
135
|
-
return
|
|
135
|
+
return path15.resolve(startDir);
|
|
136
136
|
}
|
|
137
137
|
current = parent;
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
function resolveFeaturesDir(projectRoot) {
|
|
141
|
-
return
|
|
141
|
+
return path15.join(projectRoot, "features");
|
|
142
142
|
}
|
|
143
143
|
function listExistingFeatures(projectRoot) {
|
|
144
144
|
const featuresDir = resolveFeaturesDir(projectRoot);
|
|
@@ -154,14 +154,14 @@ function listDomainInterfaces(projectRoot, featureName) {
|
|
|
154
154
|
const results = [];
|
|
155
155
|
const features = featureName ? [featureName] : listExistingFeatures(projectRoot);
|
|
156
156
|
for (const feat of features) {
|
|
157
|
-
const domainDir =
|
|
157
|
+
const domainDir = path15.join(resolveFeaturesDir(projectRoot), feat, "domain");
|
|
158
158
|
if (!fs7.existsSync(domainDir)) continue;
|
|
159
159
|
try {
|
|
160
160
|
const files = fs7.readdirSync(domainDir);
|
|
161
161
|
for (const file of files) {
|
|
162
162
|
if (file.endsWith(".ts") && !file.endsWith(".test.ts") && !file.endsWith(".d.ts")) {
|
|
163
163
|
const name = file.replace(/\.ts$/, "");
|
|
164
|
-
const fullPath =
|
|
164
|
+
const fullPath = path15.join(domainDir, file);
|
|
165
165
|
if (/^I[A-Z]/.test(name)) {
|
|
166
166
|
results.push({
|
|
167
167
|
name,
|
|
@@ -192,7 +192,7 @@ function listDomainEntities(projectRoot, featureName) {
|
|
|
192
192
|
const results = [];
|
|
193
193
|
const features = featureName ? [featureName] : listExistingFeatures(projectRoot);
|
|
194
194
|
for (const feat of features) {
|
|
195
|
-
const domainDir =
|
|
195
|
+
const domainDir = path15.join(resolveFeaturesDir(projectRoot), feat, "domain");
|
|
196
196
|
if (!fs7.existsSync(domainDir)) continue;
|
|
197
197
|
try {
|
|
198
198
|
const files = fs7.readdirSync(domainDir);
|
|
@@ -202,7 +202,7 @@ function listDomainEntities(projectRoot, featureName) {
|
|
|
202
202
|
if (!/^I[A-Z]/.test(name)) {
|
|
203
203
|
results.push({
|
|
204
204
|
name,
|
|
205
|
-
fullPath:
|
|
205
|
+
fullPath: path15.join(domainDir, file),
|
|
206
206
|
feature: feat
|
|
207
207
|
});
|
|
208
208
|
}
|
|
@@ -217,7 +217,7 @@ function listUseCases(projectRoot, featureName) {
|
|
|
217
217
|
const results = [];
|
|
218
218
|
const features = featureName ? [featureName] : listExistingFeatures(projectRoot);
|
|
219
219
|
for (const feat of features) {
|
|
220
|
-
const useCasesDir =
|
|
220
|
+
const useCasesDir = path15.join(resolveFeaturesDir(projectRoot), feat, "useCases");
|
|
221
221
|
if (!fs7.existsSync(useCasesDir)) continue;
|
|
222
222
|
try {
|
|
223
223
|
const files = fs7.readdirSync(useCasesDir);
|
|
@@ -226,7 +226,7 @@ function listUseCases(projectRoot, featureName) {
|
|
|
226
226
|
const name = file.replace(/\.ts$/, "");
|
|
227
227
|
results.push({
|
|
228
228
|
name,
|
|
229
|
-
fullPath:
|
|
229
|
+
fullPath: path15.join(useCasesDir, file),
|
|
230
230
|
feature: feat
|
|
231
231
|
});
|
|
232
232
|
}
|
|
@@ -255,30 +255,30 @@ function getTemplatesDir() {
|
|
|
255
255
|
if (cachedTemplatesDir && fs7.existsSync(cachedTemplatesDir)) {
|
|
256
256
|
return cachedTemplatesDir;
|
|
257
257
|
}
|
|
258
|
-
const currentDir = typeof __dirname !== "undefined" ? __dirname :
|
|
259
|
-
const cand1 =
|
|
258
|
+
const currentDir = typeof __dirname !== "undefined" ? __dirname : path15.dirname(fileURLToPath(import.meta.url));
|
|
259
|
+
const cand1 = path15.resolve(currentDir, "../../templates");
|
|
260
260
|
if (fs7.existsSync(cand1)) {
|
|
261
261
|
cachedTemplatesDir = cand1;
|
|
262
262
|
return cand1;
|
|
263
263
|
}
|
|
264
|
-
const cand2 =
|
|
264
|
+
const cand2 = path15.resolve(currentDir, "../templates");
|
|
265
265
|
if (fs7.existsSync(cand2)) {
|
|
266
266
|
cachedTemplatesDir = cand2;
|
|
267
267
|
return cand2;
|
|
268
268
|
}
|
|
269
|
-
const cand3 =
|
|
269
|
+
const cand3 = path15.resolve(currentDir, "templates");
|
|
270
270
|
if (fs7.existsSync(cand3)) {
|
|
271
271
|
cachedTemplatesDir = cand3;
|
|
272
272
|
return cand3;
|
|
273
273
|
}
|
|
274
274
|
let curr = currentDir;
|
|
275
275
|
while (true) {
|
|
276
|
-
const candTemplates =
|
|
276
|
+
const candTemplates = path15.join(curr, "templates");
|
|
277
277
|
if (fs7.existsSync(candTemplates)) {
|
|
278
278
|
cachedTemplatesDir = candTemplates;
|
|
279
279
|
return candTemplates;
|
|
280
280
|
}
|
|
281
|
-
const parent =
|
|
281
|
+
const parent = path15.dirname(curr);
|
|
282
282
|
if (parent === curr) break;
|
|
283
283
|
curr = parent;
|
|
284
284
|
}
|
|
@@ -286,7 +286,7 @@ function getTemplatesDir() {
|
|
|
286
286
|
}
|
|
287
287
|
var templateCache = /* @__PURE__ */ new Map();
|
|
288
288
|
function loadTemplate(relativePath) {
|
|
289
|
-
const fullPath =
|
|
289
|
+
const fullPath = path15.isAbsolute(relativePath) ? relativePath : path15.join(getTemplatesDir(), relativePath);
|
|
290
290
|
return fs7.readFileSync(fullPath, "utf-8");
|
|
291
291
|
}
|
|
292
292
|
function renderTemplateFile(relativePath, context) {
|
|
@@ -374,8 +374,8 @@ function generateDomainEntityCode(name, kind = "interface", properties = []) {
|
|
|
374
374
|
function generateDomain(options) {
|
|
375
375
|
const projectRoot = options.projectRoot || findProjectRoot();
|
|
376
376
|
const entityName = toPascalCase(options.name);
|
|
377
|
-
const targetDir = options.targetDir ||
|
|
378
|
-
const filePath =
|
|
377
|
+
const targetDir = options.targetDir || path15.join(resolveFeaturesDir(projectRoot), options.feature, "domain");
|
|
378
|
+
const filePath = path15.join(targetDir, `${entityName}.ts`);
|
|
379
379
|
const code = generateDomainEntityCode(
|
|
380
380
|
entityName,
|
|
381
381
|
options.kind || "interface",
|
|
@@ -424,8 +424,8 @@ function generateInterfaceCode(ifaceName, kind = "abstractClass", entityName, me
|
|
|
424
424
|
function generateInterface(options) {
|
|
425
425
|
const projectRoot = options.projectRoot || findProjectRoot();
|
|
426
426
|
const ifaceName = ensureInterfacePrefix(options.name);
|
|
427
|
-
const targetDir = options.targetDir ||
|
|
428
|
-
const filePath =
|
|
427
|
+
const targetDir = options.targetDir || path15.join(resolveFeaturesDir(projectRoot), options.feature, "domain");
|
|
428
|
+
const filePath = path15.join(targetDir, `${ifaceName}.ts`);
|
|
429
429
|
const code = generateInterfaceCode(
|
|
430
430
|
ifaceName,
|
|
431
431
|
options.kind || "abstractClass",
|
|
@@ -670,21 +670,21 @@ function findInterfaceFile(projectRoot, ifaceName, featureName, customPath) {
|
|
|
670
670
|
];
|
|
671
671
|
const features = featureName ? [featureName, ...listExistingFeatures(projectRoot).filter((f) => f !== featureName)] : listExistingFeatures(projectRoot);
|
|
672
672
|
for (const feat of features) {
|
|
673
|
-
const domainDir =
|
|
673
|
+
const domainDir = path15.join(resolveFeaturesDir(projectRoot), feat, "domain");
|
|
674
674
|
if (!fs7.existsSync(domainDir)) continue;
|
|
675
675
|
for (const cand of candidateNames) {
|
|
676
|
-
const p1 =
|
|
676
|
+
const p1 = path15.join(domainDir, `${cand}.ts`);
|
|
677
677
|
if (fs7.existsSync(p1)) {
|
|
678
678
|
return { filePath: p1, ifaceName: cand, feature: feat };
|
|
679
679
|
}
|
|
680
680
|
}
|
|
681
681
|
}
|
|
682
682
|
for (const cand of candidateNames) {
|
|
683
|
-
const p1 =
|
|
683
|
+
const p1 = path15.join(projectRoot, "domain", `${cand}.ts`);
|
|
684
684
|
if (fs7.existsSync(p1)) return { filePath: p1, ifaceName: cand };
|
|
685
|
-
const p22 =
|
|
685
|
+
const p22 = path15.join(projectRoot, "src", "domain", `${cand}.ts`);
|
|
686
686
|
if (fs7.existsSync(p22)) return { filePath: p22, ifaceName: cand };
|
|
687
|
-
const p32 =
|
|
687
|
+
const p32 = path15.join(projectRoot, "interfaces", `${cand}.ts`);
|
|
688
688
|
if (fs7.existsSync(p32)) return { filePath: p32, ifaceName: cand };
|
|
689
689
|
}
|
|
690
690
|
return null;
|
|
@@ -784,7 +784,7 @@ function generateStubCode(stubClassName, ifaceName, entityName, featureName, met
|
|
|
784
784
|
const entitiesVar = `${entityVar}s`;
|
|
785
785
|
const idKey = `${entityVar}Id`;
|
|
786
786
|
const impPath = ifaceImportPath || `../domain/${ifaceName}.js`;
|
|
787
|
-
const entityImportPath = ifaceImportPath ? `${
|
|
787
|
+
const entityImportPath = ifaceImportPath ? `${path15.dirname(ifaceImportPath)}/${baseEntity}.js` : `../domain/${baseEntity}.js`;
|
|
788
788
|
const importsByFrom = /* @__PURE__ */ new Map();
|
|
789
789
|
for (const imp of domainImports) {
|
|
790
790
|
if (imp.name === ifaceName || imp.name === baseEntity) continue;
|
|
@@ -833,7 +833,7 @@ function generateConcreteInfraCode(className, ifaceName, dependencies = [], meth
|
|
|
833
833
|
if (baseEntity) {
|
|
834
834
|
finalMethods = synthesizeCrudMethods(baseEntity);
|
|
835
835
|
if (!finalDomainImports.some((imp) => imp.name === baseEntity)) {
|
|
836
|
-
const importPath = ifaceImportPath ? `${
|
|
836
|
+
const importPath = ifaceImportPath ? `${path15.dirname(ifaceImportPath)}/${baseEntity}.js` : `../domain/${baseEntity}.js`;
|
|
837
837
|
finalDomainImports.push({
|
|
838
838
|
name: baseEntity,
|
|
839
839
|
from: importPath,
|
|
@@ -878,8 +878,8 @@ function generateInfrastructure(options) {
|
|
|
878
878
|
const projectRoot = options.projectRoot || findProjectRoot();
|
|
879
879
|
const className = toPascalCase(options.name);
|
|
880
880
|
const isFeatureScope = options.scope !== "global" && Boolean(options.feature);
|
|
881
|
-
const targetDir = options.targetDir || (isFeatureScope ?
|
|
882
|
-
const filePath =
|
|
881
|
+
const targetDir = options.targetDir || (isFeatureScope ? path15.join(resolveFeaturesDir(projectRoot), options.feature, "infrastructure") : path15.join(projectRoot, "infrastructure"));
|
|
882
|
+
const filePath = path15.join(targetDir, `${className}.ts`);
|
|
883
883
|
let code;
|
|
884
884
|
if (options.implementsInterface) {
|
|
885
885
|
const rawIfaceName = options.implementsInterface;
|
|
@@ -893,7 +893,7 @@ function generateInfrastructure(options) {
|
|
|
893
893
|
const ifaceFilePath = hierarchy.ifaceFilePath;
|
|
894
894
|
let ifaceImportPath;
|
|
895
895
|
if (ifaceFilePath) {
|
|
896
|
-
let rel =
|
|
896
|
+
let rel = path15.relative(targetDir, ifaceFilePath).replace(/\\/g, "/").replace(/\.ts$/, ".js");
|
|
897
897
|
if (!rel.startsWith(".")) rel = "./" + rel;
|
|
898
898
|
ifaceImportPath = rel;
|
|
899
899
|
} else if (isFeatureScope) {
|
|
@@ -906,8 +906,8 @@ function generateInfrastructure(options) {
|
|
|
906
906
|
if (new RegExp(`\\b${item.name}\\b`).test(allSignatures)) {
|
|
907
907
|
let fromPath;
|
|
908
908
|
if (imp.specifier.startsWith(".") && ifaceFilePath) {
|
|
909
|
-
const absTarget =
|
|
910
|
-
let rel =
|
|
909
|
+
const absTarget = path15.resolve(path15.dirname(ifaceFilePath), imp.specifier);
|
|
910
|
+
let rel = path15.relative(targetDir, absTarget).replace(/\\/g, "/");
|
|
911
911
|
if (!rel.startsWith(".")) rel = "./" + rel;
|
|
912
912
|
fromPath = rel;
|
|
913
913
|
} else {
|
|
@@ -1094,8 +1094,8 @@ function generateUseCase(options) {
|
|
|
1094
1094
|
const files = [];
|
|
1095
1095
|
const projectRoot = options.projectRoot || findProjectRoot();
|
|
1096
1096
|
const ucName = toPascalCase(options.name);
|
|
1097
|
-
const targetDir = options.targetDir ||
|
|
1098
|
-
const filePath =
|
|
1097
|
+
const targetDir = options.targetDir || path15.join(resolveFeaturesDir(projectRoot), options.feature, "useCases");
|
|
1098
|
+
const filePath = path15.join(targetDir, `${ucName}.ts`);
|
|
1099
1099
|
const code = generateUseCaseCode(
|
|
1100
1100
|
ucName,
|
|
1101
1101
|
options.dependencies || [],
|
|
@@ -1111,7 +1111,7 @@ function generateUseCase(options) {
|
|
|
1111
1111
|
})
|
|
1112
1112
|
);
|
|
1113
1113
|
if (options.includeTest) {
|
|
1114
|
-
const testPath =
|
|
1114
|
+
const testPath = path15.join(targetDir, `${ucName}.test.ts`);
|
|
1115
1115
|
const testCode = generateUseCaseTestCode(ucName, options.dependencies || []);
|
|
1116
1116
|
files.push(
|
|
1117
1117
|
writeFileSafely(testPath, testCode, {
|
|
@@ -1179,9 +1179,9 @@ function generateHttpHandler(options) {
|
|
|
1179
1179
|
const files = [];
|
|
1180
1180
|
const projectRoot = options.projectRoot || findProjectRoot();
|
|
1181
1181
|
const className = toPascalCase(options.name);
|
|
1182
|
-
const pxDir =
|
|
1183
|
-
const handlersDir =
|
|
1184
|
-
const pxIndexPath =
|
|
1182
|
+
const pxDir = path15.join(resolveFeaturesDir(projectRoot), options.feature, "pxExpress");
|
|
1183
|
+
const handlersDir = path15.join(pxDir, "handlers");
|
|
1184
|
+
const pxIndexPath = path15.join(pxDir, "index.ts");
|
|
1185
1185
|
if (!fs7.existsSync(pxIndexPath)) {
|
|
1186
1186
|
const featurePath = options.routePrefix || `/${options.feature.toLowerCase()}`;
|
|
1187
1187
|
const pxIndexContent = renderTemplate(expressIndexTemplate, {
|
|
@@ -1195,7 +1195,7 @@ function generateHttpHandler(options) {
|
|
|
1195
1195
|
})
|
|
1196
1196
|
);
|
|
1197
1197
|
}
|
|
1198
|
-
const handlerFilePath =
|
|
1198
|
+
const handlerFilePath = path15.join(handlersDir, `${className}.ts`);
|
|
1199
1199
|
const code = generateHttpHandlerCode(
|
|
1200
1200
|
className,
|
|
1201
1201
|
options.method || "get",
|
|
@@ -1216,7 +1216,7 @@ function generateHttpHandler(options) {
|
|
|
1216
1216
|
return files;
|
|
1217
1217
|
}
|
|
1218
1218
|
function updateOrGenerateDiProvider(featureDir, featureName, bindings = [], options = {}) {
|
|
1219
|
-
const providerPath =
|
|
1219
|
+
const providerPath = path15.join(featureDir, "diProvider.ts");
|
|
1220
1220
|
const pascalFeature = toPascalCase(featureName);
|
|
1221
1221
|
const providerModuleName = `${pascalFeature}Provider`;
|
|
1222
1222
|
if (fs7.existsSync(providerPath) && !options.overwrite) {
|
|
@@ -1279,7 +1279,7 @@ function generateFeature(options) {
|
|
|
1279
1279
|
const projectRoot = options.projectRoot || findProjectRoot();
|
|
1280
1280
|
const rawName = options.name.trim();
|
|
1281
1281
|
const featureName = toCamelCase(rawName);
|
|
1282
|
-
const targetDir = options.targetDir ||
|
|
1282
|
+
const targetDir = options.targetDir || path15.join(resolveFeaturesDir(projectRoot), featureName);
|
|
1283
1283
|
const routePath = options.routePath || `/${featureName}`;
|
|
1284
1284
|
const rawEntities = [];
|
|
1285
1285
|
if (options.entityNames && options.entityNames.length > 0) {
|
|
@@ -1300,7 +1300,7 @@ function generateFeature(options) {
|
|
|
1300
1300
|
const domainFile = generateDomain({
|
|
1301
1301
|
name: ent,
|
|
1302
1302
|
feature: featureName,
|
|
1303
|
-
targetDir:
|
|
1303
|
+
targetDir: path15.join(targetDir, "domain"),
|
|
1304
1304
|
projectRoot,
|
|
1305
1305
|
dryRun: options.dryRun,
|
|
1306
1306
|
overwrite: options.overwrite,
|
|
@@ -1320,7 +1320,7 @@ function generateFeature(options) {
|
|
|
1320
1320
|
const ifaceFile = generateInterface({
|
|
1321
1321
|
name: ifaceName,
|
|
1322
1322
|
feature: featureName,
|
|
1323
|
-
targetDir:
|
|
1323
|
+
targetDir: path15.join(targetDir, "domain"),
|
|
1324
1324
|
entityName: ent,
|
|
1325
1325
|
projectRoot,
|
|
1326
1326
|
dryRun: options.dryRun,
|
|
@@ -1337,7 +1337,7 @@ function generateFeature(options) {
|
|
|
1337
1337
|
const stubFile = generateInfrastructure({
|
|
1338
1338
|
name: stubName,
|
|
1339
1339
|
feature: featureName,
|
|
1340
|
-
targetDir:
|
|
1340
|
+
targetDir: path15.join(targetDir, "infrastructure"),
|
|
1341
1341
|
kind: "stub",
|
|
1342
1342
|
implementsInterface: ifaceName,
|
|
1343
1343
|
entityName: ent,
|
|
@@ -1379,7 +1379,7 @@ function generateFeature(options) {
|
|
|
1379
1379
|
const ucFiles = generateUseCase({
|
|
1380
1380
|
name: ucName,
|
|
1381
1381
|
feature: featureName,
|
|
1382
|
-
targetDir:
|
|
1382
|
+
targetDir: path15.join(targetDir, "useCases"),
|
|
1383
1383
|
dependencies: options.includeInterface !== false ? [ifaceName] : [],
|
|
1384
1384
|
inputProperties: [{ name: idParam, type: "string" }],
|
|
1385
1385
|
outputProperties: [{ name: entVar, type: primaryEntity }],
|
|
@@ -1424,7 +1424,7 @@ function generateFeature(options) {
|
|
|
1424
1424
|
const ucFiles = generateUseCase({
|
|
1425
1425
|
name: ucName,
|
|
1426
1426
|
feature: featureName,
|
|
1427
|
-
targetDir:
|
|
1427
|
+
targetDir: path15.join(targetDir, "useCases"),
|
|
1428
1428
|
dependencies: deps,
|
|
1429
1429
|
inputProperties: [{ name: entVar, type: ent }],
|
|
1430
1430
|
outputProperties: [{ name: entVar, type: ent }],
|
|
@@ -1457,7 +1457,7 @@ function generateFeature(options) {
|
|
|
1457
1457
|
const ucFiles = generateUseCase({
|
|
1458
1458
|
name: ucName,
|
|
1459
1459
|
feature: featureName,
|
|
1460
|
-
targetDir:
|
|
1460
|
+
targetDir: path15.join(targetDir, "useCases"),
|
|
1461
1461
|
dependencies: deps,
|
|
1462
1462
|
inputProperties: [{ name: idParam, type: "string" }],
|
|
1463
1463
|
outputProperties: [{ name: entVar, type: ent }],
|
|
@@ -1490,7 +1490,7 @@ function generateFeature(options) {
|
|
|
1490
1490
|
const ucFiles = generateUseCase({
|
|
1491
1491
|
name: ucName,
|
|
1492
1492
|
feature: featureName,
|
|
1493
|
-
targetDir:
|
|
1493
|
+
targetDir: path15.join(targetDir, "useCases"),
|
|
1494
1494
|
dependencies: deps,
|
|
1495
1495
|
inputProperties: [
|
|
1496
1496
|
{ name: "page", type: "number", optional: true },
|
|
@@ -1534,7 +1534,7 @@ function generateFeature(options) {
|
|
|
1534
1534
|
const ucFiles = generateUseCase({
|
|
1535
1535
|
name: ucName,
|
|
1536
1536
|
feature: featureName,
|
|
1537
|
-
targetDir:
|
|
1537
|
+
targetDir: path15.join(targetDir, "useCases"),
|
|
1538
1538
|
dependencies: deps,
|
|
1539
1539
|
inputProperties: [{ name: entVar, type: ent }],
|
|
1540
1540
|
outputProperties: [{ name: entVar, type: ent }],
|
|
@@ -1567,7 +1567,7 @@ function generateFeature(options) {
|
|
|
1567
1567
|
const ucFiles = generateUseCase({
|
|
1568
1568
|
name: ucName,
|
|
1569
1569
|
feature: featureName,
|
|
1570
|
-
targetDir:
|
|
1570
|
+
targetDir: path15.join(targetDir, "useCases"),
|
|
1571
1571
|
dependencies: deps,
|
|
1572
1572
|
inputProperties: [{ name: idParam, type: "string" }],
|
|
1573
1573
|
outputProperties: [{ name: "success", type: "boolean" }],
|
|
@@ -1604,7 +1604,7 @@ function generateFeature(options) {
|
|
|
1604
1604
|
const ucFiles = generateUseCase({
|
|
1605
1605
|
name: ucName,
|
|
1606
1606
|
feature: featureName,
|
|
1607
|
-
targetDir:
|
|
1607
|
+
targetDir: path15.join(targetDir, "useCases"),
|
|
1608
1608
|
dependencies: customUc.dependencies || [],
|
|
1609
1609
|
inputProperties: customUc.inputProperties || [],
|
|
1610
1610
|
outputProperties: customUc.outputProperties || [],
|
|
@@ -1636,8 +1636,8 @@ function generateFeature(options) {
|
|
|
1636
1636
|
}
|
|
1637
1637
|
}
|
|
1638
1638
|
if (options.includeExpress !== false) {
|
|
1639
|
-
const pxDir =
|
|
1640
|
-
const pxIndexPath =
|
|
1639
|
+
const pxDir = path15.join(targetDir, "pxExpress");
|
|
1640
|
+
const pxIndexPath = path15.join(pxDir, "index.ts");
|
|
1641
1641
|
if (!files.some((f) => f.absolutePath === pxIndexPath)) {
|
|
1642
1642
|
const pxIndexContent = renderTemplate(expressIndexTemplate, { routePath });
|
|
1643
1643
|
files.push(
|
|
@@ -1765,7 +1765,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
1765
1765
|
).trim();
|
|
1766
1766
|
}
|
|
1767
1767
|
const normalizedName = toCamelCase(name);
|
|
1768
|
-
const defaultDir =
|
|
1768
|
+
const defaultDir = path15.relative(projectRoot, path15.join(resolveFeaturesDir(projectRoot), normalizedName));
|
|
1769
1769
|
let targetDirRel = defaultDir;
|
|
1770
1770
|
if (!flags.yes && !flags.target) {
|
|
1771
1771
|
targetDirRel = handleCancel(
|
|
@@ -1776,7 +1776,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
1776
1776
|
})
|
|
1777
1777
|
).trim();
|
|
1778
1778
|
}
|
|
1779
|
-
const targetDir = flags.target ?
|
|
1779
|
+
const targetDir = flags.target ? path15.resolve(projectRoot, flags.target) : path15.resolve(projectRoot, targetDirRel);
|
|
1780
1780
|
let includeExpress = flags.express !== void 0 ? Boolean(flags.express) : true;
|
|
1781
1781
|
let routePath = `/${normalizedName}`;
|
|
1782
1782
|
let includeDomain = true;
|
|
@@ -2444,7 +2444,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2444
2444
|
const infraFile = generateInfrastructure(options);
|
|
2445
2445
|
files.push(infraFile);
|
|
2446
2446
|
if (registerInProvider && scope === "feature" && feature && implementsInterface) {
|
|
2447
|
-
const featureDir =
|
|
2447
|
+
const featureDir = path15.join(resolveFeaturesDir(projectRoot), feature);
|
|
2448
2448
|
const providerFile = updateOrGenerateDiProvider(
|
|
2449
2449
|
featureDir,
|
|
2450
2450
|
feature,
|
|
@@ -2606,7 +2606,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
|
2606
2606
|
files.push(stubFile);
|
|
2607
2607
|
}
|
|
2608
2608
|
if (registerInProvider && generateStub) {
|
|
2609
|
-
const featureDir =
|
|
2609
|
+
const featureDir = path15.join(resolveFeaturesDir(projectRoot), feature);
|
|
2610
2610
|
const providerFile = updateOrGenerateDiProvider(
|
|
2611
2611
|
featureDir,
|
|
2612
2612
|
feature,
|
|
@@ -2794,21 +2794,21 @@ function generateInjectable(options) {
|
|
|
2794
2794
|
const className = toPascalCase(options.name);
|
|
2795
2795
|
let targetDir = "";
|
|
2796
2796
|
if (options.customPath) {
|
|
2797
|
-
targetDir =
|
|
2797
|
+
targetDir = path15.isAbsolute(options.customPath) ? options.customPath : path15.join(projectRoot, options.customPath);
|
|
2798
2798
|
} else if (options.location === "feature-service" && options.feature) {
|
|
2799
|
-
targetDir =
|
|
2799
|
+
targetDir = path15.join(resolveFeaturesDir(projectRoot), options.feature, "services");
|
|
2800
2800
|
} else if (options.location === "feature-transformer" && options.feature) {
|
|
2801
|
-
targetDir =
|
|
2801
|
+
targetDir = path15.join(resolveFeaturesDir(projectRoot), options.feature, "pxExpress", "transformers");
|
|
2802
2802
|
} else if (options.location === "module") {
|
|
2803
|
-
targetDir =
|
|
2803
|
+
targetDir = path15.join(projectRoot, "modules", className);
|
|
2804
2804
|
} else {
|
|
2805
|
-
targetDir = options.feature ?
|
|
2805
|
+
targetDir = options.feature ? path15.join(resolveFeaturesDir(projectRoot), options.feature, "services") : path15.join(projectRoot, "shared", className.toLowerCase());
|
|
2806
2806
|
}
|
|
2807
|
-
const filePath =
|
|
2807
|
+
const filePath = path15.join(targetDir, `${className}.ts`);
|
|
2808
2808
|
let ifaceName;
|
|
2809
2809
|
if (options.generateInterface) {
|
|
2810
2810
|
ifaceName = `I${className}`;
|
|
2811
|
-
const ifacePath =
|
|
2811
|
+
const ifacePath = path15.join(targetDir, `${ifaceName}.ts`);
|
|
2812
2812
|
const ifaceContent = renderTemplate(injectableInterfaceTemplate, { ifaceName });
|
|
2813
2813
|
files.push(
|
|
2814
2814
|
writeFileSafely(ifacePath, ifaceContent, {
|
|
@@ -3042,40 +3042,105 @@ async function handleCreate(type, name, flags = {}) {
|
|
|
3042
3042
|
}
|
|
3043
3043
|
}
|
|
3044
3044
|
var DEFAULT_REGISTRY_BASE = "https://raw.githubusercontent.com/solid-stack-digital/mason-registry/main";
|
|
3045
|
+
function normalizeRegistryUrl(urlOrPath, baseDir) {
|
|
3046
|
+
let trimmed = urlOrPath.trim();
|
|
3047
|
+
const gitSshRegex = /^git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/;
|
|
3048
|
+
const sshMatch = trimmed.match(gitSshRegex);
|
|
3049
|
+
if (sshMatch && sshMatch[1] && sshMatch[2]) {
|
|
3050
|
+
return `https://raw.githubusercontent.com/${sshMatch[1]}/${sshMatch[2]}/main`;
|
|
3051
|
+
}
|
|
3052
|
+
const githubWebRegex = /^https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?(?:\/tree\/([^/]+))?\/?$/;
|
|
3053
|
+
const webMatch = trimmed.match(githubWebRegex);
|
|
3054
|
+
if (webMatch && webMatch[1] && webMatch[2]) {
|
|
3055
|
+
const owner = webMatch[1];
|
|
3056
|
+
const repo = webMatch[2];
|
|
3057
|
+
const branch = webMatch[3] || "main";
|
|
3058
|
+
return `https://raw.githubusercontent.com/${owner}/${repo}/${branch}`;
|
|
3059
|
+
}
|
|
3060
|
+
if (baseDir && (trimmed.startsWith("./") || trimmed.startsWith("../") || trimmed === "." || trimmed === "..")) {
|
|
3061
|
+
return path15.resolve(baseDir, trimmed);
|
|
3062
|
+
}
|
|
3063
|
+
return trimmed;
|
|
3064
|
+
}
|
|
3065
|
+
function findLocalRegistry(startDir = process.cwd()) {
|
|
3066
|
+
let current = path15.resolve(startDir);
|
|
3067
|
+
while (true) {
|
|
3068
|
+
const candidate = path15.join(current, "mason-registry");
|
|
3069
|
+
if (fs7.existsSync(candidate) && fs7.existsSync(path15.join(candidate, "index.json"))) {
|
|
3070
|
+
return candidate;
|
|
3071
|
+
}
|
|
3072
|
+
const parent = path15.dirname(current);
|
|
3073
|
+
if (parent === current) break;
|
|
3074
|
+
current = parent;
|
|
3075
|
+
}
|
|
3076
|
+
return null;
|
|
3077
|
+
}
|
|
3045
3078
|
function getRegistryBase(projectRoot, override) {
|
|
3079
|
+
const rootDir = projectRoot ? path15.resolve(projectRoot) : process.cwd();
|
|
3046
3080
|
if (override && override.trim()) {
|
|
3047
|
-
return override.trim();
|
|
3081
|
+
return normalizeRegistryUrl(override.trim(), rootDir);
|
|
3048
3082
|
}
|
|
3049
3083
|
if (process.env.MASON_REGISTRY_URL && process.env.MASON_REGISTRY_URL.trim()) {
|
|
3050
|
-
return process.env.MASON_REGISTRY_URL.trim();
|
|
3084
|
+
return normalizeRegistryUrl(process.env.MASON_REGISTRY_URL.trim(), rootDir);
|
|
3051
3085
|
}
|
|
3052
|
-
|
|
3053
|
-
|
|
3086
|
+
const configLocations = [
|
|
3087
|
+
path15.join(rootDir, "mason.config.json"),
|
|
3088
|
+
path15.join(process.cwd(), "mason.config.json")
|
|
3089
|
+
];
|
|
3090
|
+
for (const configPath of configLocations) {
|
|
3054
3091
|
if (fs7.existsSync(configPath)) {
|
|
3055
3092
|
try {
|
|
3056
3093
|
const config = JSON.parse(fs7.readFileSync(configPath, "utf-8"));
|
|
3057
3094
|
if (config.registry && typeof config.registry === "string") {
|
|
3058
|
-
return config.registry.trim();
|
|
3095
|
+
return normalizeRegistryUrl(config.registry.trim(), path15.dirname(configPath));
|
|
3059
3096
|
}
|
|
3060
3097
|
} catch {
|
|
3061
3098
|
}
|
|
3062
3099
|
}
|
|
3063
3100
|
}
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3101
|
+
const pkgLocations = [
|
|
3102
|
+
path15.join(rootDir, "package.json"),
|
|
3103
|
+
path15.join(process.cwd(), "package.json")
|
|
3104
|
+
];
|
|
3105
|
+
for (const pkgPath of pkgLocations) {
|
|
3106
|
+
if (fs7.existsSync(pkgPath)) {
|
|
3107
|
+
try {
|
|
3108
|
+
const pkg = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
|
|
3109
|
+
if (pkg.mason?.registry && typeof pkg.mason.registry === "string") {
|
|
3110
|
+
return normalizeRegistryUrl(pkg.mason.registry.trim(), path15.dirname(pkgPath));
|
|
3111
|
+
}
|
|
3112
|
+
} catch {
|
|
3113
|
+
}
|
|
3068
3114
|
}
|
|
3069
3115
|
}
|
|
3116
|
+
const localRegistry = findLocalRegistry(rootDir);
|
|
3117
|
+
if (localRegistry) {
|
|
3118
|
+
return localRegistry;
|
|
3119
|
+
}
|
|
3070
3120
|
return DEFAULT_REGISTRY_BASE;
|
|
3071
3121
|
}
|
|
3072
3122
|
async function fetchRegistryFile(registryBase, relPath) {
|
|
3073
3123
|
const cleanRelPath = relPath.replace(/^\/+/, "");
|
|
3074
3124
|
if (registryBase.startsWith("http://") || registryBase.startsWith("https://")) {
|
|
3075
3125
|
const url = `${registryBase.replace(/\/+$/, "")}/${cleanRelPath}`;
|
|
3076
|
-
const
|
|
3126
|
+
const headers = {};
|
|
3127
|
+
const token = process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
|
|
3128
|
+
if (token) {
|
|
3129
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
3130
|
+
}
|
|
3131
|
+
const res = await fetch(url, { headers });
|
|
3077
3132
|
if (!res.ok) {
|
|
3078
|
-
|
|
3133
|
+
let extraHint = "";
|
|
3134
|
+
if (res.status === 404) {
|
|
3135
|
+
extraHint = `
|
|
3136
|
+
Possible reasons:
|
|
3137
|
+
\u2022 If using a private GitHub repository, ensure GITHUB_TOKEN is set in your environment.
|
|
3138
|
+
\u2022 If your registry has not yet been pushed to GitHub, point to your local directory:
|
|
3139
|
+
- CLI flag: mason import ... --registry /path/to/mason-registry
|
|
3140
|
+
- Environment: export MASON_REGISTRY_URL=/path/to/mason-registry
|
|
3141
|
+
- Config file: Create mason.config.json with { "registry": "/path/to/mason-registry" }`;
|
|
3142
|
+
}
|
|
3143
|
+
throw new Error(`Failed to fetch ${cleanRelPath} from ${url} (HTTP ${res.status}: ${res.statusText})${extraHint}`);
|
|
3079
3144
|
}
|
|
3080
3145
|
return await res.text();
|
|
3081
3146
|
}
|
|
@@ -3083,7 +3148,7 @@ async function fetchRegistryFile(registryBase, relPath) {
|
|
|
3083
3148
|
if (baseDir.startsWith("file://")) {
|
|
3084
3149
|
baseDir = fileURLToPath(baseDir);
|
|
3085
3150
|
}
|
|
3086
|
-
const filePath =
|
|
3151
|
+
const filePath = path15.resolve(baseDir, cleanRelPath);
|
|
3087
3152
|
if (!fs7.existsSync(filePath)) {
|
|
3088
3153
|
throw new Error(`Registry file not found at ${filePath}`);
|
|
3089
3154
|
}
|
|
@@ -3149,14 +3214,14 @@ function findClosestMatch(target, candidates) {
|
|
|
3149
3214
|
return null;
|
|
3150
3215
|
}
|
|
3151
3216
|
function detectPackageManager(projectRoot) {
|
|
3152
|
-
if (fs7.existsSync(
|
|
3153
|
-
if (fs7.existsSync(
|
|
3154
|
-
if (fs7.existsSync(
|
|
3217
|
+
if (fs7.existsSync(path15.join(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
|
|
3218
|
+
if (fs7.existsSync(path15.join(projectRoot, "yarn.lock"))) return "yarn";
|
|
3219
|
+
if (fs7.existsSync(path15.join(projectRoot, "bun.lockb")) || fs7.existsSync(path15.join(projectRoot, "bun.lock"))) return "bun";
|
|
3155
3220
|
return "npm";
|
|
3156
3221
|
}
|
|
3157
3222
|
function getMissingNpmPackages(projectRoot, requiredPackages) {
|
|
3158
3223
|
if (!requiredPackages || requiredPackages.length === 0) return [];
|
|
3159
|
-
const pkgJsonPath =
|
|
3224
|
+
const pkgJsonPath = path15.join(projectRoot, "package.json");
|
|
3160
3225
|
if (!fs7.existsSync(pkgJsonPath)) {
|
|
3161
3226
|
return requiredPackages;
|
|
3162
3227
|
}
|
|
@@ -3283,7 +3348,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3283
3348
|
}
|
|
3284
3349
|
const sharedDeps = manifest.dependencies?.shared || [];
|
|
3285
3350
|
for (const dep of sharedDeps) {
|
|
3286
|
-
const depPath =
|
|
3351
|
+
const depPath = path15.join(projectRoot, "src", "shared", dep);
|
|
3287
3352
|
if (!fs7.existsSync(depPath) && !importedModules.has(`shared:${dep}`)) {
|
|
3288
3353
|
p3.log.info(` \u21B3 Resolving required shared dependency: ${pc13.cyan(dep)}`);
|
|
3289
3354
|
await importModuleRecursive("shared", dep);
|
|
@@ -3291,7 +3356,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3291
3356
|
}
|
|
3292
3357
|
const featureDeps = manifest.dependencies?.features || [];
|
|
3293
3358
|
for (const dep of featureDeps) {
|
|
3294
|
-
const depPath =
|
|
3359
|
+
const depPath = path15.join(projectRoot, "src", "features", dep);
|
|
3295
3360
|
if (!fs7.existsSync(depPath) && !importedModules.has(`feature:${dep}`)) {
|
|
3296
3361
|
p3.log.info(` \u21B3 Resolving required feature dependency: ${pc13.cyan(dep)}`);
|
|
3297
3362
|
await importModuleRecursive("feature", dep);
|
|
@@ -3301,21 +3366,21 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
3301
3366
|
requiredNpmPackages.add(pkg);
|
|
3302
3367
|
}
|
|
3303
3368
|
const folder = modType === "shared" ? "shared" : "features";
|
|
3304
|
-
const targetDir =
|
|
3369
|
+
const targetDir = path15.join(projectRoot, "src", folder, modName);
|
|
3305
3370
|
for (const file of manifest.files || []) {
|
|
3306
3371
|
if (file === "registry.json") continue;
|
|
3307
3372
|
const remoteFilePath = `${folder}/${modName}/${file}`;
|
|
3308
|
-
const localFilePath =
|
|
3373
|
+
const localFilePath = path15.join(targetDir, file);
|
|
3309
3374
|
if (fs7.existsSync(localFilePath) && !flags.overwrite) {
|
|
3310
|
-
p3.log.warn(` \u21B3 Skipping existing file: ${pc13.dim(
|
|
3375
|
+
p3.log.warn(` \u21B3 Skipping existing file: ${pc13.dim(path15.relative(projectRoot, localFilePath))} (use --overwrite to replace)`);
|
|
3311
3376
|
continue;
|
|
3312
3377
|
}
|
|
3313
3378
|
const content = await fetchRegistryFile(registryBase, remoteFilePath);
|
|
3314
3379
|
if (!flags.dryRun) {
|
|
3315
|
-
fs7.mkdirSync(
|
|
3380
|
+
fs7.mkdirSync(path15.dirname(localFilePath), { recursive: true });
|
|
3316
3381
|
fs7.writeFileSync(localFilePath, content, "utf-8");
|
|
3317
3382
|
}
|
|
3318
|
-
const displayPath =
|
|
3383
|
+
const displayPath = path15.relative(projectRoot, localFilePath);
|
|
3319
3384
|
totalWrittenFiles.push(displayPath);
|
|
3320
3385
|
p3.log.message(` ${pc13.green("+")} ${displayPath}`);
|
|
3321
3386
|
}
|