@solid-stack/mason 1.0.32 → 1.0.34
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 +648 -356
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +646 -354
- package/dist/bin.js.map +1 -1
- package/dist/core/lintEngine.d.ts +5 -4
- package/dist/core/lintEngine.d.ts.map +1 -1
- package/dist/index.cjs +652 -358
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +649 -357
- package/dist/index.js.map +1 -1
- package/dist/types/lint.d.ts +10 -2
- package/dist/types/lint.d.ts.map +1 -1
- package/dist/utils/config.d.ts +13 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import fs17 from 'fs';
|
|
2
|
+
import path26 from 'path';
|
|
3
3
|
import * as p19 from '@clack/prompts';
|
|
4
4
|
import pc14 from 'picocolors';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
@@ -76,8 +76,8 @@ function isValidIdentifier(str) {
|
|
|
76
76
|
}
|
|
77
77
|
function writeFileSafely(absolutePath, content, options = {}) {
|
|
78
78
|
const projectRoot = options.projectRoot || process.cwd();
|
|
79
|
-
const relPath =
|
|
80
|
-
const existedBefore =
|
|
79
|
+
const relPath = path26.relative(projectRoot, absolutePath).replace(/\\/g, "/");
|
|
80
|
+
const existedBefore = fs17.existsSync(absolutePath);
|
|
81
81
|
if (options.dryRun) {
|
|
82
82
|
return {
|
|
83
83
|
relativePath: relPath,
|
|
@@ -96,11 +96,11 @@ function writeFileSafely(absolutePath, content, options = {}) {
|
|
|
96
96
|
existedBefore: true
|
|
97
97
|
};
|
|
98
98
|
}
|
|
99
|
-
const dir =
|
|
100
|
-
if (!
|
|
101
|
-
|
|
99
|
+
const dir = path26.dirname(absolutePath);
|
|
100
|
+
if (!fs17.existsSync(dir)) {
|
|
101
|
+
fs17.mkdirSync(dir, { recursive: true });
|
|
102
102
|
}
|
|
103
|
-
|
|
103
|
+
fs17.writeFileSync(absolutePath, content, "utf-8");
|
|
104
104
|
return {
|
|
105
105
|
relativePath: relPath,
|
|
106
106
|
absolutePath,
|
|
@@ -127,17 +127,17 @@ function printGeneratedFiles(files, isDryRun = false) {
|
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
129
|
function loadMasonConfig(startDir = process.cwd()) {
|
|
130
|
-
let current =
|
|
130
|
+
let current = path26.resolve(startDir);
|
|
131
131
|
while (true) {
|
|
132
|
-
const configPath =
|
|
133
|
-
if (
|
|
132
|
+
const configPath = path26.join(current, "mason.config.json");
|
|
133
|
+
if (fs17.existsSync(configPath)) {
|
|
134
134
|
try {
|
|
135
|
-
return JSON.parse(
|
|
135
|
+
return JSON.parse(fs17.readFileSync(configPath, "utf-8"));
|
|
136
136
|
} catch {
|
|
137
137
|
return null;
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
|
-
const parent =
|
|
140
|
+
const parent = path26.dirname(current);
|
|
141
141
|
if (parent === current) break;
|
|
142
142
|
current = parent;
|
|
143
143
|
}
|
|
@@ -147,60 +147,91 @@ function getEffectiveMode(projectRoot, flags) {
|
|
|
147
147
|
if (flags?.registry) return "registry";
|
|
148
148
|
const config = loadMasonConfig(projectRoot);
|
|
149
149
|
if (config?.mode) return config.mode;
|
|
150
|
-
if (
|
|
150
|
+
if (fs17.existsSync(path26.join(projectRoot, "index.json")) && (fs17.existsSync(path26.join(projectRoot, "features")) || fs17.existsSync(path26.join(projectRoot, "shared")) || fs17.existsSync(path26.join(projectRoot, "src/features")) || fs17.existsSync(path26.join(projectRoot, "src/shared")))) {
|
|
151
151
|
return "registry";
|
|
152
152
|
}
|
|
153
153
|
return "app";
|
|
154
154
|
}
|
|
155
155
|
function getConfiguredFeaturesDir(projectRoot, flags) {
|
|
156
|
-
if (flags?.target) return
|
|
157
|
-
if (flags?.dest) return
|
|
156
|
+
if (flags?.target) return path26.resolve(projectRoot, flags.target);
|
|
157
|
+
if (flags?.dest) return path26.resolve(projectRoot, flags.dest);
|
|
158
158
|
const config = loadMasonConfig(projectRoot);
|
|
159
159
|
if (config?.paths?.features) {
|
|
160
|
-
return
|
|
160
|
+
return path26.resolve(projectRoot, config.paths.features);
|
|
161
161
|
}
|
|
162
162
|
const mode = getEffectiveMode(projectRoot, flags);
|
|
163
163
|
if (mode === "registry") {
|
|
164
|
-
if (
|
|
165
|
-
return
|
|
164
|
+
if (fs17.existsSync(path26.join(projectRoot, "src/features"))) {
|
|
165
|
+
return path26.join(projectRoot, "src/features");
|
|
166
166
|
}
|
|
167
|
-
return
|
|
167
|
+
return path26.join(projectRoot, "features");
|
|
168
168
|
}
|
|
169
|
-
if (
|
|
170
|
-
return
|
|
169
|
+
if (fs17.existsSync(path26.join(projectRoot, "src/features"))) {
|
|
170
|
+
return path26.join(projectRoot, "src/features");
|
|
171
171
|
}
|
|
172
|
-
return
|
|
172
|
+
return path26.join(projectRoot, "features");
|
|
173
173
|
}
|
|
174
174
|
function getConfiguredSharedDir(projectRoot, flags) {
|
|
175
|
-
if (flags?.target) return
|
|
176
|
-
if (flags?.dest) return
|
|
175
|
+
if (flags?.target) return path26.resolve(projectRoot, flags.target);
|
|
176
|
+
if (flags?.dest) return path26.resolve(projectRoot, flags.dest);
|
|
177
177
|
const config = loadMasonConfig(projectRoot);
|
|
178
178
|
if (config?.paths?.shared) {
|
|
179
|
-
return
|
|
179
|
+
return path26.resolve(projectRoot, config.paths.shared);
|
|
180
180
|
}
|
|
181
181
|
const mode = getEffectiveMode(projectRoot, flags);
|
|
182
182
|
if (mode === "registry") {
|
|
183
|
-
if (
|
|
184
|
-
return
|
|
183
|
+
if (fs17.existsSync(path26.join(projectRoot, "src/shared"))) {
|
|
184
|
+
return path26.join(projectRoot, "src/shared");
|
|
185
185
|
}
|
|
186
|
-
return
|
|
186
|
+
return path26.join(projectRoot, "shared");
|
|
187
187
|
}
|
|
188
|
-
if (
|
|
189
|
-
return
|
|
188
|
+
if (fs17.existsSync(path26.join(projectRoot, "src/shared"))) {
|
|
189
|
+
return path26.join(projectRoot, "src/shared");
|
|
190
190
|
}
|
|
191
|
-
return
|
|
191
|
+
return path26.join(projectRoot, "shared");
|
|
192
|
+
}
|
|
193
|
+
function loadLintConfig(projectRoot) {
|
|
194
|
+
const configPath = path26.join(projectRoot, "mason-lint.config.json");
|
|
195
|
+
if (fs17.existsSync(configPath)) {
|
|
196
|
+
try {
|
|
197
|
+
return JSON.parse(fs17.readFileSync(configPath, "utf-8"));
|
|
198
|
+
} catch {
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return {};
|
|
202
|
+
}
|
|
203
|
+
function getResolvedLintPaths(projectRoot, config) {
|
|
204
|
+
const masonConfig = loadMasonConfig(projectRoot);
|
|
205
|
+
const configuredFeatures = config.paths?.features ?? masonConfig?.paths?.features;
|
|
206
|
+
const configuredShared = config.paths?.shared ?? masonConfig?.paths?.shared;
|
|
207
|
+
const configuredErrors = config.paths?.errors;
|
|
208
|
+
const resolveBase = (configuredPath, defaultSrc, defaultRoot) => {
|
|
209
|
+
if (configuredPath !== void 0) {
|
|
210
|
+
return path26.resolve(projectRoot, configuredPath);
|
|
211
|
+
}
|
|
212
|
+
const srcPath = path26.join(projectRoot, defaultSrc);
|
|
213
|
+
if (fs17.existsSync(srcPath)) return srcPath;
|
|
214
|
+
const rootPath = path26.join(projectRoot, defaultRoot);
|
|
215
|
+
if (fs17.existsSync(rootPath)) return rootPath;
|
|
216
|
+
return srcPath;
|
|
217
|
+
};
|
|
218
|
+
return {
|
|
219
|
+
featuresBase: resolveBase(configuredFeatures, "src/features", "features"),
|
|
220
|
+
sharedBase: resolveBase(configuredShared, "src/shared", "shared"),
|
|
221
|
+
errorsBase: resolveBase(configuredErrors, "src/errors", "errors")
|
|
222
|
+
};
|
|
192
223
|
}
|
|
193
224
|
|
|
194
225
|
// src/utils/project.ts
|
|
195
226
|
function findProjectRoot(startDir = process.cwd()) {
|
|
196
|
-
let current =
|
|
227
|
+
let current = path26.resolve(startDir);
|
|
197
228
|
while (true) {
|
|
198
|
-
if (
|
|
229
|
+
if (fs17.existsSync(path26.join(current, "package.json"))) {
|
|
199
230
|
return current;
|
|
200
231
|
}
|
|
201
|
-
const parent =
|
|
232
|
+
const parent = path26.dirname(current);
|
|
202
233
|
if (parent === current) {
|
|
203
|
-
return
|
|
234
|
+
return path26.resolve(startDir);
|
|
204
235
|
}
|
|
205
236
|
current = parent;
|
|
206
237
|
}
|
|
@@ -213,9 +244,9 @@ function resolveSharedDir(projectRoot, flags) {
|
|
|
213
244
|
}
|
|
214
245
|
function listExistingShared(projectRoot) {
|
|
215
246
|
const sharedDir = resolveSharedDir(projectRoot);
|
|
216
|
-
if (!
|
|
247
|
+
if (!fs17.existsSync(sharedDir)) return [];
|
|
217
248
|
try {
|
|
218
|
-
const entries =
|
|
249
|
+
const entries = fs17.readdirSync(sharedDir, { withFileTypes: true });
|
|
219
250
|
return entries.filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => e.name).sort();
|
|
220
251
|
} catch {
|
|
221
252
|
return [];
|
|
@@ -223,9 +254,9 @@ function listExistingShared(projectRoot) {
|
|
|
223
254
|
}
|
|
224
255
|
function listExistingFeatures(projectRoot) {
|
|
225
256
|
const featuresDir = resolveFeaturesDir(projectRoot);
|
|
226
|
-
if (!
|
|
257
|
+
if (!fs17.existsSync(featuresDir)) return [];
|
|
227
258
|
try {
|
|
228
|
-
const entries =
|
|
259
|
+
const entries = fs17.readdirSync(featuresDir, { withFileTypes: true });
|
|
229
260
|
return entries.filter((e) => e.isDirectory()).map((e) => e.name).sort();
|
|
230
261
|
} catch {
|
|
231
262
|
return [];
|
|
@@ -235,14 +266,14 @@ function listDomainInterfaces(projectRoot, featureName) {
|
|
|
235
266
|
const results = [];
|
|
236
267
|
const features = featureName ? [featureName] : listExistingFeatures(projectRoot);
|
|
237
268
|
for (const feat of features) {
|
|
238
|
-
const domainDir =
|
|
239
|
-
if (!
|
|
269
|
+
const domainDir = path26.join(resolveFeaturesDir(projectRoot), feat, "domain");
|
|
270
|
+
if (!fs17.existsSync(domainDir)) continue;
|
|
240
271
|
try {
|
|
241
|
-
const files =
|
|
272
|
+
const files = fs17.readdirSync(domainDir);
|
|
242
273
|
for (const file of files) {
|
|
243
274
|
if (file.endsWith(".ts") && !file.endsWith(".test.ts") && !file.endsWith(".d.ts")) {
|
|
244
275
|
const name = file.replace(/\.ts$/, "");
|
|
245
|
-
const fullPath =
|
|
276
|
+
const fullPath = path26.join(domainDir, file);
|
|
246
277
|
if (/^I[A-Z]/.test(name)) {
|
|
247
278
|
results.push({
|
|
248
279
|
name,
|
|
@@ -251,7 +282,7 @@ function listDomainInterfaces(projectRoot, featureName) {
|
|
|
251
282
|
});
|
|
252
283
|
} else {
|
|
253
284
|
try {
|
|
254
|
-
const content =
|
|
285
|
+
const content = fs17.readFileSync(fullPath, "utf-8");
|
|
255
286
|
if (/export\s+(?:abstract\s+class|interface)\s+(\w+)/.test(content)) {
|
|
256
287
|
results.push({
|
|
257
288
|
name,
|
|
@@ -273,17 +304,17 @@ function listDomainEntities(projectRoot, featureName) {
|
|
|
273
304
|
const results = [];
|
|
274
305
|
const features = featureName ? [featureName] : listExistingFeatures(projectRoot);
|
|
275
306
|
for (const feat of features) {
|
|
276
|
-
const domainDir =
|
|
277
|
-
if (!
|
|
307
|
+
const domainDir = path26.join(resolveFeaturesDir(projectRoot), feat, "domain");
|
|
308
|
+
if (!fs17.existsSync(domainDir)) continue;
|
|
278
309
|
try {
|
|
279
|
-
const files =
|
|
310
|
+
const files = fs17.readdirSync(domainDir);
|
|
280
311
|
for (const file of files) {
|
|
281
312
|
if (file.endsWith(".ts") && !file.endsWith(".test.ts") && !file.endsWith(".d.ts")) {
|
|
282
313
|
const name = file.replace(/\.ts$/, "");
|
|
283
314
|
if (!/^I[A-Z]/.test(name)) {
|
|
284
315
|
results.push({
|
|
285
316
|
name,
|
|
286
|
-
fullPath:
|
|
317
|
+
fullPath: path26.join(domainDir, file),
|
|
287
318
|
feature: feat
|
|
288
319
|
});
|
|
289
320
|
}
|
|
@@ -298,16 +329,16 @@ function listUseCases(projectRoot, featureName) {
|
|
|
298
329
|
const results = [];
|
|
299
330
|
const features = featureName ? [featureName] : listExistingFeatures(projectRoot);
|
|
300
331
|
for (const feat of features) {
|
|
301
|
-
const useCasesDir =
|
|
302
|
-
if (!
|
|
332
|
+
const useCasesDir = path26.join(resolveFeaturesDir(projectRoot), feat, "useCases");
|
|
333
|
+
if (!fs17.existsSync(useCasesDir)) continue;
|
|
303
334
|
try {
|
|
304
|
-
const files =
|
|
335
|
+
const files = fs17.readdirSync(useCasesDir);
|
|
305
336
|
for (const file of files) {
|
|
306
337
|
if (file.endsWith(".ts") && !file.endsWith(".test.ts") && !file.endsWith(".d.ts")) {
|
|
307
338
|
const name = file.replace(/\.ts$/, "");
|
|
308
339
|
results.push({
|
|
309
340
|
name,
|
|
310
|
-
fullPath:
|
|
341
|
+
fullPath: path26.join(useCasesDir, file),
|
|
311
342
|
feature: feat
|
|
312
343
|
});
|
|
313
344
|
}
|
|
@@ -419,25 +450,25 @@ function normalizeRegistryUrl(urlOrPath, baseDir) {
|
|
|
419
450
|
return `https://raw.githubusercontent.com/${owner}/${repo}/${branch}`;
|
|
420
451
|
}
|
|
421
452
|
if (baseDir && (trimmed.startsWith("./") || trimmed.startsWith("../") || trimmed === "." || trimmed === "..")) {
|
|
422
|
-
return
|
|
453
|
+
return path26.resolve(baseDir, trimmed);
|
|
423
454
|
}
|
|
424
455
|
return trimmed;
|
|
425
456
|
}
|
|
426
457
|
function findLocalRegistry(startDir = process.cwd()) {
|
|
427
|
-
let current =
|
|
458
|
+
let current = path26.resolve(startDir);
|
|
428
459
|
while (true) {
|
|
429
|
-
const candidate =
|
|
430
|
-
if (
|
|
460
|
+
const candidate = path26.join(current, "mason-registry");
|
|
461
|
+
if (fs17.existsSync(candidate) && fs17.existsSync(path26.join(candidate, "index.json"))) {
|
|
431
462
|
return candidate;
|
|
432
463
|
}
|
|
433
|
-
const parent =
|
|
464
|
+
const parent = path26.dirname(current);
|
|
434
465
|
if (parent === current) break;
|
|
435
466
|
current = parent;
|
|
436
467
|
}
|
|
437
468
|
return null;
|
|
438
469
|
}
|
|
439
470
|
function getRegistryBase(projectRoot, override) {
|
|
440
|
-
const rootDir = projectRoot ?
|
|
471
|
+
const rootDir = projectRoot ? path26.resolve(projectRoot) : process.cwd();
|
|
441
472
|
if (override && override.trim()) {
|
|
442
473
|
return normalizeRegistryUrl(override.trim(), rootDir);
|
|
443
474
|
}
|
|
@@ -445,30 +476,30 @@ function getRegistryBase(projectRoot, override) {
|
|
|
445
476
|
return normalizeRegistryUrl(process.env.MASON_REGISTRY_URL.trim(), rootDir);
|
|
446
477
|
}
|
|
447
478
|
const configLocations = [
|
|
448
|
-
|
|
449
|
-
|
|
479
|
+
path26.join(rootDir, "mason.config.json"),
|
|
480
|
+
path26.join(process.cwd(), "mason.config.json")
|
|
450
481
|
];
|
|
451
482
|
for (const configPath of configLocations) {
|
|
452
|
-
if (
|
|
483
|
+
if (fs17.existsSync(configPath)) {
|
|
453
484
|
try {
|
|
454
|
-
const config = JSON.parse(
|
|
485
|
+
const config = JSON.parse(fs17.readFileSync(configPath, "utf-8"));
|
|
455
486
|
if (config.registry && typeof config.registry === "string") {
|
|
456
|
-
return normalizeRegistryUrl(config.registry.trim(),
|
|
487
|
+
return normalizeRegistryUrl(config.registry.trim(), path26.dirname(configPath));
|
|
457
488
|
}
|
|
458
489
|
} catch {
|
|
459
490
|
}
|
|
460
491
|
}
|
|
461
492
|
}
|
|
462
493
|
const pkgLocations = [
|
|
463
|
-
|
|
464
|
-
|
|
494
|
+
path26.join(rootDir, "package.json"),
|
|
495
|
+
path26.join(process.cwd(), "package.json")
|
|
465
496
|
];
|
|
466
497
|
for (const pkgPath of pkgLocations) {
|
|
467
|
-
if (
|
|
498
|
+
if (fs17.existsSync(pkgPath)) {
|
|
468
499
|
try {
|
|
469
|
-
const pkg = JSON.parse(
|
|
500
|
+
const pkg = JSON.parse(fs17.readFileSync(pkgPath, "utf-8"));
|
|
470
501
|
if (pkg.mason?.registry && typeof pkg.mason.registry === "string") {
|
|
471
|
-
return normalizeRegistryUrl(pkg.mason.registry.trim(),
|
|
502
|
+
return normalizeRegistryUrl(pkg.mason.registry.trim(), path26.dirname(pkgPath));
|
|
472
503
|
}
|
|
473
504
|
} catch {
|
|
474
505
|
}
|
|
@@ -516,16 +547,16 @@ async function fetchRegistryFile(registryBase, relPath) {
|
|
|
516
547
|
if (baseDir.startsWith("file://")) {
|
|
517
548
|
baseDir = fileURLToPath(baseDir);
|
|
518
549
|
}
|
|
519
|
-
let filePath =
|
|
520
|
-
if (!
|
|
521
|
-
const inSrcPath =
|
|
522
|
-
if (
|
|
550
|
+
let filePath = path26.resolve(baseDir, cleanRelPath);
|
|
551
|
+
if (!fs17.existsSync(filePath)) {
|
|
552
|
+
const inSrcPath = path26.resolve(baseDir, "src", cleanRelPath);
|
|
553
|
+
if (fs17.existsSync(inSrcPath)) {
|
|
523
554
|
filePath = inSrcPath;
|
|
524
555
|
} else {
|
|
525
556
|
throw new Error(`Registry file not found at ${filePath}`);
|
|
526
557
|
}
|
|
527
558
|
}
|
|
528
|
-
return
|
|
559
|
+
return fs17.promises.readFile(filePath, "utf-8");
|
|
529
560
|
}
|
|
530
561
|
async function fetchRegistryIndex(registryBase) {
|
|
531
562
|
const content = await fetchRegistryFile(registryBase, "index.json");
|
|
@@ -587,19 +618,19 @@ function findClosestMatch(target, candidates) {
|
|
|
587
618
|
return null;
|
|
588
619
|
}
|
|
589
620
|
function detectPackageManager(projectRoot) {
|
|
590
|
-
if (
|
|
591
|
-
if (
|
|
592
|
-
if (
|
|
621
|
+
if (fs17.existsSync(path26.join(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
|
|
622
|
+
if (fs17.existsSync(path26.join(projectRoot, "yarn.lock"))) return "yarn";
|
|
623
|
+
if (fs17.existsSync(path26.join(projectRoot, "bun.lockb")) || fs17.existsSync(path26.join(projectRoot, "bun.lock"))) return "bun";
|
|
593
624
|
return "npm";
|
|
594
625
|
}
|
|
595
626
|
function getMissingNpmPackages(projectRoot, requiredPackages) {
|
|
596
627
|
if (!requiredPackages || requiredPackages.length === 0) return [];
|
|
597
|
-
const pkgJsonPath =
|
|
598
|
-
if (!
|
|
628
|
+
const pkgJsonPath = path26.join(projectRoot, "package.json");
|
|
629
|
+
if (!fs17.existsSync(pkgJsonPath)) {
|
|
599
630
|
return requiredPackages;
|
|
600
631
|
}
|
|
601
632
|
try {
|
|
602
|
-
const pkg = JSON.parse(
|
|
633
|
+
const pkg = JSON.parse(fs17.readFileSync(pkgJsonPath, "utf-8"));
|
|
603
634
|
const installed = /* @__PURE__ */ new Set([
|
|
604
635
|
...Object.keys(pkg.dependencies || {}),
|
|
605
636
|
...Object.keys(pkg.devDependencies || {}),
|
|
@@ -638,12 +669,12 @@ function installNpmPackages(projectRoot, packages, pm) {
|
|
|
638
669
|
});
|
|
639
670
|
}
|
|
640
671
|
function getAllFiles(dir, baseDir = dir) {
|
|
641
|
-
if (!
|
|
642
|
-
const entries =
|
|
672
|
+
if (!fs17.existsSync(dir)) return [];
|
|
673
|
+
const entries = fs17.readdirSync(dir, { withFileTypes: true });
|
|
643
674
|
const files = [];
|
|
644
675
|
for (const entry of entries) {
|
|
645
|
-
const fullPath =
|
|
646
|
-
const relPath =
|
|
676
|
+
const fullPath = path26.join(dir, entry.name);
|
|
677
|
+
const relPath = path26.relative(baseDir, fullPath).replace(/\\/g, "/");
|
|
647
678
|
if (entry.isDirectory()) {
|
|
648
679
|
if (entry.name === "__tests__" || entry.name.startsWith(".")) {
|
|
649
680
|
continue;
|
|
@@ -659,13 +690,13 @@ function getAllFiles(dir, baseDir = dir) {
|
|
|
659
690
|
return files.sort();
|
|
660
691
|
}
|
|
661
692
|
function computeDirectoryHash(dirPath, files) {
|
|
662
|
-
if (!
|
|
693
|
+
if (!fs17.existsSync(dirPath)) return "";
|
|
663
694
|
const hash = createHash("sha256");
|
|
664
695
|
const fileList = (files ?? getAllFiles(dirPath)).sort();
|
|
665
696
|
for (const relativePath of fileList) {
|
|
666
|
-
const absolutePath =
|
|
667
|
-
if (!
|
|
668
|
-
const content =
|
|
697
|
+
const absolutePath = path26.join(dirPath, relativePath);
|
|
698
|
+
if (!fs17.existsSync(absolutePath)) continue;
|
|
699
|
+
const content = fs17.readFileSync(absolutePath, "utf8");
|
|
669
700
|
const normalizedContent = content.replace(/\r\n/g, "\n");
|
|
670
701
|
hash.update(relativePath);
|
|
671
702
|
hash.update(normalizedContent);
|
|
@@ -688,33 +719,33 @@ hbs.registerHelper("join", (arr, sep) => {
|
|
|
688
719
|
});
|
|
689
720
|
var cachedTemplatesDir = null;
|
|
690
721
|
function getTemplatesDir() {
|
|
691
|
-
if (cachedTemplatesDir &&
|
|
722
|
+
if (cachedTemplatesDir && fs17.existsSync(cachedTemplatesDir)) {
|
|
692
723
|
return cachedTemplatesDir;
|
|
693
724
|
}
|
|
694
|
-
const currentDir = typeof __dirname !== "undefined" ? __dirname :
|
|
695
|
-
const cand1 =
|
|
696
|
-
if (
|
|
725
|
+
const currentDir = typeof __dirname !== "undefined" ? __dirname : path26.dirname(fileURLToPath(import.meta.url));
|
|
726
|
+
const cand1 = path26.resolve(currentDir, "../../templates");
|
|
727
|
+
if (fs17.existsSync(cand1)) {
|
|
697
728
|
cachedTemplatesDir = cand1;
|
|
698
729
|
return cand1;
|
|
699
730
|
}
|
|
700
|
-
const cand2 =
|
|
701
|
-
if (
|
|
731
|
+
const cand2 = path26.resolve(currentDir, "../templates");
|
|
732
|
+
if (fs17.existsSync(cand2)) {
|
|
702
733
|
cachedTemplatesDir = cand2;
|
|
703
734
|
return cand2;
|
|
704
735
|
}
|
|
705
|
-
const cand3 =
|
|
706
|
-
if (
|
|
736
|
+
const cand3 = path26.resolve(currentDir, "templates");
|
|
737
|
+
if (fs17.existsSync(cand3)) {
|
|
707
738
|
cachedTemplatesDir = cand3;
|
|
708
739
|
return cand3;
|
|
709
740
|
}
|
|
710
741
|
let curr = currentDir;
|
|
711
742
|
while (true) {
|
|
712
|
-
const candTemplates =
|
|
713
|
-
if (
|
|
743
|
+
const candTemplates = path26.join(curr, "templates");
|
|
744
|
+
if (fs17.existsSync(candTemplates)) {
|
|
714
745
|
cachedTemplatesDir = candTemplates;
|
|
715
746
|
return candTemplates;
|
|
716
747
|
}
|
|
717
|
-
const parent =
|
|
748
|
+
const parent = path26.dirname(curr);
|
|
718
749
|
if (parent === curr) break;
|
|
719
750
|
curr = parent;
|
|
720
751
|
}
|
|
@@ -722,8 +753,8 @@ function getTemplatesDir() {
|
|
|
722
753
|
}
|
|
723
754
|
var templateCache = /* @__PURE__ */ new Map();
|
|
724
755
|
function loadTemplate(relativePath) {
|
|
725
|
-
const fullPath =
|
|
726
|
-
return
|
|
756
|
+
const fullPath = path26.isAbsolute(relativePath) ? relativePath : path26.join(getTemplatesDir(), relativePath);
|
|
757
|
+
return fs17.readFileSync(fullPath, "utf-8");
|
|
727
758
|
}
|
|
728
759
|
function renderTemplateFile(relativePath, context) {
|
|
729
760
|
let compiled = templateCache.get(relativePath);
|
|
@@ -808,8 +839,8 @@ function generateDomainEntityCode(name, kind = "interface", properties = []) {
|
|
|
808
839
|
function generateDomain(options) {
|
|
809
840
|
const projectRoot = options.projectRoot || findProjectRoot();
|
|
810
841
|
const entityName = toPascalCase(options.name);
|
|
811
|
-
const targetDir = options.targetDir ||
|
|
812
|
-
const filePath =
|
|
842
|
+
const targetDir = options.targetDir || path26.join(resolveFeaturesDir(projectRoot), options.feature, "domain");
|
|
843
|
+
const filePath = path26.join(targetDir, `${entityName}.ts`);
|
|
813
844
|
const code = generateDomainEntityCode(
|
|
814
845
|
entityName,
|
|
815
846
|
options.kind || "interface",
|
|
@@ -858,8 +889,8 @@ function generateInterfaceCode(ifaceName, kind = "abstractClass", entityName, me
|
|
|
858
889
|
function generateInterface(options) {
|
|
859
890
|
const projectRoot = options.projectRoot || findProjectRoot();
|
|
860
891
|
const ifaceName = ensureInterfacePrefix(options.name);
|
|
861
|
-
const targetDir = options.targetDir ||
|
|
862
|
-
const filePath =
|
|
892
|
+
const targetDir = options.targetDir || path26.join(resolveFeaturesDir(projectRoot), options.feature, "domain");
|
|
893
|
+
const filePath = path26.join(targetDir, `${ifaceName}.ts`);
|
|
863
894
|
const code = generateInterfaceCode(
|
|
864
895
|
ifaceName,
|
|
865
896
|
options.kind || "abstractClass",
|
|
@@ -1094,7 +1125,7 @@ function parseInterfaceMethodsAndImports(content, targetIfaceName) {
|
|
|
1094
1125
|
};
|
|
1095
1126
|
}
|
|
1096
1127
|
function findInterfaceFile(projectRoot, ifaceName, featureName, customPath) {
|
|
1097
|
-
if (customPath &&
|
|
1128
|
+
if (customPath && fs17.existsSync(customPath)) {
|
|
1098
1129
|
return { filePath: customPath, ifaceName };
|
|
1099
1130
|
}
|
|
1100
1131
|
const candidateNames = [
|
|
@@ -1104,22 +1135,22 @@ function findInterfaceFile(projectRoot, ifaceName, featureName, customPath) {
|
|
|
1104
1135
|
];
|
|
1105
1136
|
const features = featureName ? [featureName, ...listExistingFeatures(projectRoot).filter((f) => f !== featureName)] : listExistingFeatures(projectRoot);
|
|
1106
1137
|
for (const feat of features) {
|
|
1107
|
-
const domainDir =
|
|
1108
|
-
if (!
|
|
1138
|
+
const domainDir = path26.join(resolveFeaturesDir(projectRoot), feat, "domain");
|
|
1139
|
+
if (!fs17.existsSync(domainDir)) continue;
|
|
1109
1140
|
for (const cand of candidateNames) {
|
|
1110
|
-
const p1 =
|
|
1111
|
-
if (
|
|
1141
|
+
const p1 = path26.join(domainDir, `${cand}.ts`);
|
|
1142
|
+
if (fs17.existsSync(p1)) {
|
|
1112
1143
|
return { filePath: p1, ifaceName: cand, feature: feat };
|
|
1113
1144
|
}
|
|
1114
1145
|
}
|
|
1115
1146
|
}
|
|
1116
1147
|
for (const cand of candidateNames) {
|
|
1117
|
-
const p1 =
|
|
1118
|
-
if (
|
|
1119
|
-
const p22 =
|
|
1120
|
-
if (
|
|
1121
|
-
const p32 =
|
|
1122
|
-
if (
|
|
1148
|
+
const p1 = path26.join(projectRoot, "domain", `${cand}.ts`);
|
|
1149
|
+
if (fs17.existsSync(p1)) return { filePath: p1, ifaceName: cand };
|
|
1150
|
+
const p22 = path26.join(projectRoot, "src", "domain", `${cand}.ts`);
|
|
1151
|
+
if (fs17.existsSync(p22)) return { filePath: p22, ifaceName: cand };
|
|
1152
|
+
const p32 = path26.join(projectRoot, "interfaces", `${cand}.ts`);
|
|
1153
|
+
if (fs17.existsSync(p32)) return { filePath: p32, ifaceName: cand };
|
|
1123
1154
|
}
|
|
1124
1155
|
return null;
|
|
1125
1156
|
}
|
|
@@ -1142,7 +1173,7 @@ function loadInterfaceHierarchy(projectRoot, initialIfaceName, featureName, cust
|
|
|
1142
1173
|
while (currentFile && !visited.has(currentFile)) {
|
|
1143
1174
|
visited.add(currentFile);
|
|
1144
1175
|
try {
|
|
1145
|
-
const content =
|
|
1176
|
+
const content = fs17.readFileSync(currentFile, "utf-8");
|
|
1146
1177
|
const parsed = parseInterfaceMethodsAndImports(content, currentName);
|
|
1147
1178
|
for (const m of parsed.methods) {
|
|
1148
1179
|
if (!allMethods.some((existing) => existing.name === m.name)) {
|
|
@@ -1218,7 +1249,7 @@ function generateStubCode(stubClassName, ifaceName, entityName, featureName, met
|
|
|
1218
1249
|
const entitiesVar = `${entityVar}s`;
|
|
1219
1250
|
const idKey = `${entityVar}Id`;
|
|
1220
1251
|
const impPath = ifaceImportPath || `../domain/${ifaceName}.js`;
|
|
1221
|
-
const entityImportPath = ifaceImportPath ? `${
|
|
1252
|
+
const entityImportPath = ifaceImportPath ? `${path26.dirname(ifaceImportPath)}/${baseEntity}.js` : `../domain/${baseEntity}.js`;
|
|
1222
1253
|
const importsByFrom = /* @__PURE__ */ new Map();
|
|
1223
1254
|
for (const imp of domainImports) {
|
|
1224
1255
|
if (imp.name === ifaceName || imp.name === baseEntity) continue;
|
|
@@ -1267,7 +1298,7 @@ function generateConcreteInfraCode(className, ifaceName, dependencies = [], meth
|
|
|
1267
1298
|
if (baseEntity) {
|
|
1268
1299
|
finalMethods = synthesizeCrudMethods(baseEntity);
|
|
1269
1300
|
if (!finalDomainImports.some((imp) => imp.name === baseEntity)) {
|
|
1270
|
-
const importPath = ifaceImportPath ? `${
|
|
1301
|
+
const importPath = ifaceImportPath ? `${path26.dirname(ifaceImportPath)}/${baseEntity}.js` : `../domain/${baseEntity}.js`;
|
|
1271
1302
|
finalDomainImports.push({
|
|
1272
1303
|
name: baseEntity,
|
|
1273
1304
|
from: importPath,
|
|
@@ -1312,8 +1343,8 @@ function generateInfrastructure(options) {
|
|
|
1312
1343
|
const projectRoot = options.projectRoot || findProjectRoot();
|
|
1313
1344
|
const className = toPascalCase(options.name);
|
|
1314
1345
|
const isFeatureScope = options.scope !== "global" && Boolean(options.feature);
|
|
1315
|
-
const targetDir = options.targetDir || (isFeatureScope ?
|
|
1316
|
-
const filePath =
|
|
1346
|
+
const targetDir = options.targetDir || (isFeatureScope ? path26.join(resolveFeaturesDir(projectRoot), options.feature, "infrastructure") : path26.join(projectRoot, "infrastructure"));
|
|
1347
|
+
const filePath = path26.join(targetDir, `${className}.ts`);
|
|
1317
1348
|
let code;
|
|
1318
1349
|
if (options.implementsInterface) {
|
|
1319
1350
|
const rawIfaceName = options.implementsInterface;
|
|
@@ -1327,7 +1358,7 @@ function generateInfrastructure(options) {
|
|
|
1327
1358
|
const ifaceFilePath = hierarchy.ifaceFilePath;
|
|
1328
1359
|
let ifaceImportPath;
|
|
1329
1360
|
if (ifaceFilePath) {
|
|
1330
|
-
let rel =
|
|
1361
|
+
let rel = path26.relative(targetDir, ifaceFilePath).replace(/\\/g, "/").replace(/\.ts$/, ".js");
|
|
1331
1362
|
if (!rel.startsWith(".")) rel = "./" + rel;
|
|
1332
1363
|
ifaceImportPath = rel;
|
|
1333
1364
|
} else if (isFeatureScope) {
|
|
@@ -1340,8 +1371,8 @@ function generateInfrastructure(options) {
|
|
|
1340
1371
|
if (new RegExp(`\\b${item.name}\\b`).test(allSignatures)) {
|
|
1341
1372
|
let fromPath;
|
|
1342
1373
|
if (imp.specifier.startsWith(".") && ifaceFilePath) {
|
|
1343
|
-
const absTarget =
|
|
1344
|
-
let rel =
|
|
1374
|
+
const absTarget = path26.resolve(path26.dirname(ifaceFilePath), imp.specifier);
|
|
1375
|
+
let rel = path26.relative(targetDir, absTarget).replace(/\\/g, "/");
|
|
1345
1376
|
if (!rel.startsWith(".")) rel = "./" + rel;
|
|
1346
1377
|
fromPath = rel;
|
|
1347
1378
|
} else {
|
|
@@ -1528,8 +1559,8 @@ function generateUseCase(options) {
|
|
|
1528
1559
|
const files = [];
|
|
1529
1560
|
const projectRoot = options.projectRoot || findProjectRoot();
|
|
1530
1561
|
const ucName = toPascalCase(options.name);
|
|
1531
|
-
const targetDir = options.targetDir ||
|
|
1532
|
-
const filePath =
|
|
1562
|
+
const targetDir = options.targetDir || path26.join(resolveFeaturesDir(projectRoot), options.feature, "useCases");
|
|
1563
|
+
const filePath = path26.join(targetDir, `${ucName}.ts`);
|
|
1533
1564
|
const code = generateUseCaseCode(
|
|
1534
1565
|
ucName,
|
|
1535
1566
|
options.dependencies || [],
|
|
@@ -1545,7 +1576,7 @@ function generateUseCase(options) {
|
|
|
1545
1576
|
})
|
|
1546
1577
|
);
|
|
1547
1578
|
if (options.includeTest) {
|
|
1548
|
-
const testPath =
|
|
1579
|
+
const testPath = path26.join(targetDir, `${ucName}.test.ts`);
|
|
1549
1580
|
const testCode = generateUseCaseTestCode(ucName, options.dependencies || []);
|
|
1550
1581
|
files.push(
|
|
1551
1582
|
writeFileSafely(testPath, testCode, {
|
|
@@ -1613,10 +1644,10 @@ function generateHttpHandler(options) {
|
|
|
1613
1644
|
const files = [];
|
|
1614
1645
|
const projectRoot = options.projectRoot || findProjectRoot();
|
|
1615
1646
|
const className = toPascalCase(options.name);
|
|
1616
|
-
const pxDir =
|
|
1617
|
-
const handlersDir =
|
|
1618
|
-
const pxIndexPath =
|
|
1619
|
-
if (!
|
|
1647
|
+
const pxDir = path26.join(resolveFeaturesDir(projectRoot), options.feature, "pxExpress");
|
|
1648
|
+
const handlersDir = path26.join(pxDir, "handlers");
|
|
1649
|
+
const pxIndexPath = path26.join(pxDir, "index.ts");
|
|
1650
|
+
if (!fs17.existsSync(pxIndexPath)) {
|
|
1620
1651
|
const featurePath = options.routePrefix || `/${options.feature.toLowerCase()}`;
|
|
1621
1652
|
const pxIndexContent = renderTemplate(expressIndexTemplate, {
|
|
1622
1653
|
routePath: featurePath
|
|
@@ -1629,7 +1660,7 @@ function generateHttpHandler(options) {
|
|
|
1629
1660
|
})
|
|
1630
1661
|
);
|
|
1631
1662
|
}
|
|
1632
|
-
const handlerFilePath =
|
|
1663
|
+
const handlerFilePath = path26.join(handlersDir, `${className}.ts`);
|
|
1633
1664
|
const code = generateHttpHandlerCode(
|
|
1634
1665
|
className,
|
|
1635
1666
|
options.method || "get",
|
|
@@ -1650,11 +1681,11 @@ function generateHttpHandler(options) {
|
|
|
1650
1681
|
return files;
|
|
1651
1682
|
}
|
|
1652
1683
|
function updateOrGenerateDiProvider(featureDir, featureName, bindings = [], options = {}) {
|
|
1653
|
-
const providerPath =
|
|
1684
|
+
const providerPath = path26.join(featureDir, "diProvider.ts");
|
|
1654
1685
|
const pascalFeature = toPascalCase(featureName);
|
|
1655
1686
|
const providerModuleName = `${pascalFeature}Provider`;
|
|
1656
|
-
if (
|
|
1657
|
-
let content =
|
|
1687
|
+
if (fs17.existsSync(providerPath) && !options.overwrite) {
|
|
1688
|
+
let content = fs17.readFileSync(providerPath, "utf-8");
|
|
1658
1689
|
content = content.replace(/\n*export\s+const\s+ScaffoldProvider\s*=[^;]+;?/g, "");
|
|
1659
1690
|
for (const b of bindings) {
|
|
1660
1691
|
const ifaceImp = b.ifaceImportPath || `./domain/${b.ifaceName}.js`;
|
|
@@ -1713,7 +1744,7 @@ function generateFeature(options) {
|
|
|
1713
1744
|
const projectRoot = options.projectRoot || findProjectRoot();
|
|
1714
1745
|
const rawName = options.name.trim();
|
|
1715
1746
|
const featureName = toCamelCase(rawName);
|
|
1716
|
-
const targetDir = options.targetDir ||
|
|
1747
|
+
const targetDir = options.targetDir || path26.join(resolveFeaturesDir(projectRoot), featureName);
|
|
1717
1748
|
const routePath = options.routePath || `/${featureName}`;
|
|
1718
1749
|
const rawEntities = [];
|
|
1719
1750
|
if (options.entityNames && options.entityNames.length > 0) {
|
|
@@ -1734,7 +1765,7 @@ function generateFeature(options) {
|
|
|
1734
1765
|
const domainFile = generateDomain({
|
|
1735
1766
|
name: ent,
|
|
1736
1767
|
feature: featureName,
|
|
1737
|
-
targetDir:
|
|
1768
|
+
targetDir: path26.join(targetDir, "domain"),
|
|
1738
1769
|
projectRoot,
|
|
1739
1770
|
dryRun: options.dryRun,
|
|
1740
1771
|
overwrite: options.overwrite,
|
|
@@ -1754,7 +1785,7 @@ function generateFeature(options) {
|
|
|
1754
1785
|
const ifaceFile = generateInterface({
|
|
1755
1786
|
name: ifaceName,
|
|
1756
1787
|
feature: featureName,
|
|
1757
|
-
targetDir:
|
|
1788
|
+
targetDir: path26.join(targetDir, "domain"),
|
|
1758
1789
|
entityName: ent,
|
|
1759
1790
|
projectRoot,
|
|
1760
1791
|
dryRun: options.dryRun,
|
|
@@ -1771,7 +1802,7 @@ function generateFeature(options) {
|
|
|
1771
1802
|
const stubFile = generateInfrastructure({
|
|
1772
1803
|
name: stubName,
|
|
1773
1804
|
feature: featureName,
|
|
1774
|
-
targetDir:
|
|
1805
|
+
targetDir: path26.join(targetDir, "infrastructure"),
|
|
1775
1806
|
kind: "stub",
|
|
1776
1807
|
implementsInterface: ifaceName,
|
|
1777
1808
|
entityName: ent,
|
|
@@ -1813,7 +1844,7 @@ function generateFeature(options) {
|
|
|
1813
1844
|
const ucFiles = generateUseCase({
|
|
1814
1845
|
name: ucName,
|
|
1815
1846
|
feature: featureName,
|
|
1816
|
-
targetDir:
|
|
1847
|
+
targetDir: path26.join(targetDir, "useCases"),
|
|
1817
1848
|
dependencies: options.includeInterface !== false ? [ifaceName] : [],
|
|
1818
1849
|
inputProperties: [{ name: idParam, type: "string" }],
|
|
1819
1850
|
outputProperties: [{ name: entVar, type: primaryEntity }],
|
|
@@ -1858,7 +1889,7 @@ function generateFeature(options) {
|
|
|
1858
1889
|
const ucFiles = generateUseCase({
|
|
1859
1890
|
name: ucName,
|
|
1860
1891
|
feature: featureName,
|
|
1861
|
-
targetDir:
|
|
1892
|
+
targetDir: path26.join(targetDir, "useCases"),
|
|
1862
1893
|
dependencies: deps,
|
|
1863
1894
|
inputProperties: [{ name: entVar, type: ent }],
|
|
1864
1895
|
outputProperties: [{ name: entVar, type: ent }],
|
|
@@ -1891,7 +1922,7 @@ function generateFeature(options) {
|
|
|
1891
1922
|
const ucFiles = generateUseCase({
|
|
1892
1923
|
name: ucName,
|
|
1893
1924
|
feature: featureName,
|
|
1894
|
-
targetDir:
|
|
1925
|
+
targetDir: path26.join(targetDir, "useCases"),
|
|
1895
1926
|
dependencies: deps,
|
|
1896
1927
|
inputProperties: [{ name: idParam, type: "string" }],
|
|
1897
1928
|
outputProperties: [{ name: entVar, type: ent }],
|
|
@@ -1924,7 +1955,7 @@ function generateFeature(options) {
|
|
|
1924
1955
|
const ucFiles = generateUseCase({
|
|
1925
1956
|
name: ucName,
|
|
1926
1957
|
feature: featureName,
|
|
1927
|
-
targetDir:
|
|
1958
|
+
targetDir: path26.join(targetDir, "useCases"),
|
|
1928
1959
|
dependencies: deps,
|
|
1929
1960
|
inputProperties: [
|
|
1930
1961
|
{ name: "page", type: "number", optional: true },
|
|
@@ -1968,7 +1999,7 @@ function generateFeature(options) {
|
|
|
1968
1999
|
const ucFiles = generateUseCase({
|
|
1969
2000
|
name: ucName,
|
|
1970
2001
|
feature: featureName,
|
|
1971
|
-
targetDir:
|
|
2002
|
+
targetDir: path26.join(targetDir, "useCases"),
|
|
1972
2003
|
dependencies: deps,
|
|
1973
2004
|
inputProperties: [{ name: entVar, type: ent }],
|
|
1974
2005
|
outputProperties: [{ name: entVar, type: ent }],
|
|
@@ -2001,7 +2032,7 @@ function generateFeature(options) {
|
|
|
2001
2032
|
const ucFiles = generateUseCase({
|
|
2002
2033
|
name: ucName,
|
|
2003
2034
|
feature: featureName,
|
|
2004
|
-
targetDir:
|
|
2035
|
+
targetDir: path26.join(targetDir, "useCases"),
|
|
2005
2036
|
dependencies: deps,
|
|
2006
2037
|
inputProperties: [{ name: idParam, type: "string" }],
|
|
2007
2038
|
outputProperties: [{ name: "success", type: "boolean" }],
|
|
@@ -2038,7 +2069,7 @@ function generateFeature(options) {
|
|
|
2038
2069
|
const ucFiles = generateUseCase({
|
|
2039
2070
|
name: ucName,
|
|
2040
2071
|
feature: featureName,
|
|
2041
|
-
targetDir:
|
|
2072
|
+
targetDir: path26.join(targetDir, "useCases"),
|
|
2042
2073
|
dependencies: customUc.dependencies || [],
|
|
2043
2074
|
inputProperties: customUc.inputProperties || [],
|
|
2044
2075
|
outputProperties: customUc.outputProperties || [],
|
|
@@ -2070,8 +2101,8 @@ function generateFeature(options) {
|
|
|
2070
2101
|
}
|
|
2071
2102
|
}
|
|
2072
2103
|
if (options.includeExpress !== false) {
|
|
2073
|
-
const pxDir =
|
|
2074
|
-
const pxIndexPath =
|
|
2104
|
+
const pxDir = path26.join(targetDir, "pxExpress");
|
|
2105
|
+
const pxIndexPath = path26.join(pxDir, "index.ts");
|
|
2075
2106
|
if (!files.some((f) => f.absolutePath === pxIndexPath)) {
|
|
2076
2107
|
const pxIndexContent = renderTemplate(expressIndexTemplate, { routePath });
|
|
2077
2108
|
files.push(
|
|
@@ -2116,7 +2147,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2116
2147
|
}
|
|
2117
2148
|
const normalizedName = toCamelCase(name);
|
|
2118
2149
|
const baseFeaturesDir = resolveFeaturesDir(projectRoot, flags);
|
|
2119
|
-
const defaultDir =
|
|
2150
|
+
const defaultDir = path26.relative(projectRoot, path26.join(baseFeaturesDir, normalizedName));
|
|
2120
2151
|
let targetDirRel = defaultDir;
|
|
2121
2152
|
if (!flags.yes && !flags.target && !flags.dest) {
|
|
2122
2153
|
targetDirRel = handleCancel(
|
|
@@ -2127,7 +2158,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2127
2158
|
})
|
|
2128
2159
|
).trim();
|
|
2129
2160
|
}
|
|
2130
|
-
const targetDir = flags.dest ?
|
|
2161
|
+
const targetDir = flags.dest ? path26.resolve(projectRoot, flags.dest) : flags.target ? path26.resolve(projectRoot, flags.target) : path26.resolve(projectRoot, targetDirRel);
|
|
2131
2162
|
let includeExpress = flags.express !== void 0 ? Boolean(flags.express) : true;
|
|
2132
2163
|
let routePath = `/${normalizedName}`;
|
|
2133
2164
|
let includeDomain = true;
|
|
@@ -2369,8 +2400,8 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2369
2400
|
};
|
|
2370
2401
|
const files = generateFeature(options);
|
|
2371
2402
|
if (isRegistry) {
|
|
2372
|
-
const registryPath =
|
|
2373
|
-
if (!
|
|
2403
|
+
const registryPath = path26.join(targetDir, "registry.json");
|
|
2404
|
+
if (!fs17.existsSync(registryPath)) {
|
|
2374
2405
|
const manifest = {
|
|
2375
2406
|
name: toKebabCase(normalizedName),
|
|
2376
2407
|
type: "feature",
|
|
@@ -2396,7 +2427,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
|
|
|
2396
2427
|
printGeneratedFiles(files, options.dryRun);
|
|
2397
2428
|
p19.outro(
|
|
2398
2429
|
pc14.green(
|
|
2399
|
-
`\u2713 Feature '${normalizedName}' initialized in ${
|
|
2430
|
+
`\u2713 Feature '${normalizedName}' initialized in ${path26.relative(projectRoot, targetDir)} (uncommitted, unregistered)`
|
|
2400
2431
|
)
|
|
2401
2432
|
);
|
|
2402
2433
|
}
|
|
@@ -2407,7 +2438,7 @@ function generateShared(options) {
|
|
|
2407
2438
|
const pascalName = toPascalCase(rawName);
|
|
2408
2439
|
const camelName = toCamelCase(rawName);
|
|
2409
2440
|
const kebabName = toKebabCase(rawName);
|
|
2410
|
-
const targetDir = options.targetDir ||
|
|
2441
|
+
const targetDir = options.targetDir || path26.join(resolveSharedDir(projectRoot), kebabName);
|
|
2411
2442
|
const fileDefs = [];
|
|
2412
2443
|
const facadeContent = `import { MakeInjectable, type DepsType } from "@solid-stack/di";
|
|
2413
2444
|
import { I${pascalName}Engine } from "./ports/I${pascalName}Engine.js";
|
|
@@ -2419,7 +2450,7 @@ export class ${pascalName} {
|
|
|
2419
2450
|
}
|
|
2420
2451
|
`;
|
|
2421
2452
|
fileDefs.push({
|
|
2422
|
-
absolutePath:
|
|
2453
|
+
absolutePath: path26.join(targetDir, `${pascalName}.ts`),
|
|
2423
2454
|
content: facadeContent
|
|
2424
2455
|
});
|
|
2425
2456
|
const portContent = `export abstract class I${pascalName}Engine {
|
|
@@ -2427,7 +2458,7 @@ export class ${pascalName} {
|
|
|
2427
2458
|
}
|
|
2428
2459
|
`;
|
|
2429
2460
|
fileDefs.push({
|
|
2430
|
-
absolutePath:
|
|
2461
|
+
absolutePath: path26.join(targetDir, "ports", `I${pascalName}Engine.ts`),
|
|
2431
2462
|
content: portContent
|
|
2432
2463
|
});
|
|
2433
2464
|
const concreteContent = `import { MakeInjectable } from "@solid-stack/di";
|
|
@@ -2439,7 +2470,7 @@ export class Default${pascalName}Engine implements I${pascalName}Engine {
|
|
|
2439
2470
|
}
|
|
2440
2471
|
`;
|
|
2441
2472
|
fileDefs.push({
|
|
2442
|
-
absolutePath:
|
|
2473
|
+
absolutePath: path26.join(targetDir, "infrastructure", `Default${pascalName}Engine.ts`),
|
|
2443
2474
|
content: concreteContent
|
|
2444
2475
|
});
|
|
2445
2476
|
if (options.includeStub !== false) {
|
|
@@ -2452,7 +2483,7 @@ export class Stub${pascalName}Engine implements I${pascalName}Engine {
|
|
|
2452
2483
|
}
|
|
2453
2484
|
`;
|
|
2454
2485
|
fileDefs.push({
|
|
2455
|
-
absolutePath:
|
|
2486
|
+
absolutePath: path26.join(targetDir, "infrastructure", `Stub${pascalName}Engine.ts`),
|
|
2456
2487
|
content: stubContent
|
|
2457
2488
|
});
|
|
2458
2489
|
}
|
|
@@ -2467,7 +2498,7 @@ export const diProvider = (c: Container): void => {
|
|
|
2467
2498
|
export default diProvider;
|
|
2468
2499
|
`;
|
|
2469
2500
|
fileDefs.push({
|
|
2470
|
-
absolutePath:
|
|
2501
|
+
absolutePath: path26.join(targetDir, "diProvider.ts"),
|
|
2471
2502
|
content: providerContent
|
|
2472
2503
|
});
|
|
2473
2504
|
if (options.isRegistry) {
|
|
@@ -2484,7 +2515,7 @@ export default diProvider;
|
|
|
2484
2515
|
files: []
|
|
2485
2516
|
};
|
|
2486
2517
|
fileDefs.push({
|
|
2487
|
-
absolutePath:
|
|
2518
|
+
absolutePath: path26.join(targetDir, "registry.json"),
|
|
2488
2519
|
content: JSON.stringify(registryManifest, null, 2) + "\n"
|
|
2489
2520
|
});
|
|
2490
2521
|
}
|
|
@@ -2521,7 +2552,7 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
|
|
|
2521
2552
|
}
|
|
2522
2553
|
const normalizedName = toKebabCase(name);
|
|
2523
2554
|
const baseSharedDir = resolveSharedDir(projectRoot, flags);
|
|
2524
|
-
const defaultDir =
|
|
2555
|
+
const defaultDir = path26.relative(projectRoot, path26.join(baseSharedDir, normalizedName));
|
|
2525
2556
|
let targetDirRel = defaultDir;
|
|
2526
2557
|
if (!flags.yes && !flags.target && !flags.dest) {
|
|
2527
2558
|
targetDirRel = handleCancel(
|
|
@@ -2532,7 +2563,7 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
|
|
|
2532
2563
|
})
|
|
2533
2564
|
).trim();
|
|
2534
2565
|
}
|
|
2535
|
-
const targetDir = flags.dest ?
|
|
2566
|
+
const targetDir = flags.dest ? path26.resolve(projectRoot, flags.dest) : flags.target ? path26.resolve(projectRoot, flags.target) : path26.resolve(projectRoot, targetDirRel);
|
|
2536
2567
|
let description = flags.description || "";
|
|
2537
2568
|
let includeStub = true;
|
|
2538
2569
|
if (!flags.yes) {
|
|
@@ -2566,7 +2597,7 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
|
|
|
2566
2597
|
printGeneratedFiles(files, Boolean(flags.dryRun));
|
|
2567
2598
|
p19.outro(
|
|
2568
2599
|
pc14.green(
|
|
2569
|
-
`\u2713 Shared module '${normalizedName}' initialized in ${
|
|
2600
|
+
`\u2713 Shared module '${normalizedName}' initialized in ${path26.relative(projectRoot, targetDir)} (uncommitted, unregistered)`
|
|
2570
2601
|
)
|
|
2571
2602
|
);
|
|
2572
2603
|
}
|
|
@@ -2993,7 +3024,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
|
|
|
2993
3024
|
const infraFile = generateInfrastructure(options);
|
|
2994
3025
|
files.push(infraFile);
|
|
2995
3026
|
if (registerInProvider && scope === "feature" && feature && implementsInterface) {
|
|
2996
|
-
const featureDir =
|
|
3027
|
+
const featureDir = path26.join(resolveFeaturesDir(projectRoot), feature);
|
|
2997
3028
|
const providerFile = updateOrGenerateDiProvider(
|
|
2998
3029
|
featureDir,
|
|
2999
3030
|
feature,
|
|
@@ -3155,7 +3186,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
|
|
|
3155
3186
|
files.push(stubFile);
|
|
3156
3187
|
}
|
|
3157
3188
|
if (registerInProvider && generateStub) {
|
|
3158
|
-
const featureDir =
|
|
3189
|
+
const featureDir = path26.join(resolveFeaturesDir(projectRoot), feature);
|
|
3159
3190
|
const providerFile = updateOrGenerateDiProvider(
|
|
3160
3191
|
featureDir,
|
|
3161
3192
|
feature,
|
|
@@ -3343,21 +3374,21 @@ function generateInjectable(options) {
|
|
|
3343
3374
|
const className = toPascalCase(options.name);
|
|
3344
3375
|
let targetDir = "";
|
|
3345
3376
|
if (options.customPath) {
|
|
3346
|
-
targetDir =
|
|
3377
|
+
targetDir = path26.isAbsolute(options.customPath) ? options.customPath : path26.join(projectRoot, options.customPath);
|
|
3347
3378
|
} else if (options.location === "feature-service" && options.feature) {
|
|
3348
|
-
targetDir =
|
|
3379
|
+
targetDir = path26.join(resolveFeaturesDir(projectRoot), options.feature, "services");
|
|
3349
3380
|
} else if (options.location === "feature-transformer" && options.feature) {
|
|
3350
|
-
targetDir =
|
|
3381
|
+
targetDir = path26.join(resolveFeaturesDir(projectRoot), options.feature, "pxExpress", "transformers");
|
|
3351
3382
|
} else if (options.location === "module") {
|
|
3352
|
-
targetDir =
|
|
3383
|
+
targetDir = path26.join(projectRoot, "modules", className);
|
|
3353
3384
|
} else {
|
|
3354
|
-
targetDir = options.feature ?
|
|
3385
|
+
targetDir = options.feature ? path26.join(resolveFeaturesDir(projectRoot), options.feature, "services") : path26.join(projectRoot, "shared", className.toLowerCase());
|
|
3355
3386
|
}
|
|
3356
|
-
const filePath =
|
|
3387
|
+
const filePath = path26.join(targetDir, `${className}.ts`);
|
|
3357
3388
|
let ifaceName;
|
|
3358
3389
|
if (options.generateInterface) {
|
|
3359
3390
|
ifaceName = `I${className}`;
|
|
3360
|
-
const ifacePath =
|
|
3391
|
+
const ifacePath = path26.join(targetDir, `${ifaceName}.ts`);
|
|
3361
3392
|
const ifaceContent = renderTemplate(injectableInterfaceTemplate, { ifaceName });
|
|
3362
3393
|
files.push(
|
|
3363
3394
|
writeFileSafely(ifacePath, ifaceContent, {
|
|
@@ -3486,7 +3517,7 @@ async function runEnvInit(flags = {}) {
|
|
|
3486
3517
|
const projectRoot = flags.cwd || flags.targetDir || findProjectRoot();
|
|
3487
3518
|
const s = p19.spinner();
|
|
3488
3519
|
s.start("Scanning for .example environment files...");
|
|
3489
|
-
const files =
|
|
3520
|
+
const files = fs17.readdirSync(projectRoot);
|
|
3490
3521
|
const exampleFiles = files.filter((file) => file.startsWith(".env") && file.endsWith(".example")).sort();
|
|
3491
3522
|
if (exampleFiles.length === 0) {
|
|
3492
3523
|
s.stop("No .example files found.");
|
|
@@ -3496,11 +3527,11 @@ async function runEnvInit(flags = {}) {
|
|
|
3496
3527
|
s.message(`Found ${exampleFiles.length} template(s). Generating...`);
|
|
3497
3528
|
const generatedFiles = [];
|
|
3498
3529
|
for (const exampleFile of exampleFiles) {
|
|
3499
|
-
const sourcePath =
|
|
3530
|
+
const sourcePath = path26.join(projectRoot, exampleFile);
|
|
3500
3531
|
const targetFile = exampleFile.replace(/\.example$/, "");
|
|
3501
|
-
const targetPath =
|
|
3532
|
+
const targetPath = path26.join(projectRoot, targetFile);
|
|
3502
3533
|
let overwrite = flags.overwrite;
|
|
3503
|
-
if (overwrite === void 0 && !flags.dryRun && !flags.yes && !process.env.VITEST && process.stdin.isTTY &&
|
|
3534
|
+
if (overwrite === void 0 && !flags.dryRun && !flags.yes && !process.env.VITEST && process.stdin.isTTY && fs17.existsSync(targetPath)) {
|
|
3504
3535
|
overwrite = await p19.confirm({
|
|
3505
3536
|
message: `${targetFile} already exists. Overwrite?`,
|
|
3506
3537
|
initialValue: false
|
|
@@ -3510,7 +3541,7 @@ async function runEnvInit(flags = {}) {
|
|
|
3510
3541
|
process.exit(0);
|
|
3511
3542
|
}
|
|
3512
3543
|
}
|
|
3513
|
-
const content =
|
|
3544
|
+
const content = fs17.readFileSync(sourcePath, "utf-8");
|
|
3514
3545
|
const genFile = writeFileSafely(targetPath, content, {
|
|
3515
3546
|
projectRoot,
|
|
3516
3547
|
dryRun: Boolean(flags.dryRun),
|
|
@@ -3529,7 +3560,7 @@ var EnvEditor = class {
|
|
|
3529
3560
|
filePath;
|
|
3530
3561
|
constructor(filePath) {
|
|
3531
3562
|
this.filePath = filePath;
|
|
3532
|
-
this.lines =
|
|
3563
|
+
this.lines = fs17.existsSync(filePath) ? fs17.readFileSync(filePath, "utf-8").split(/\r?\n/) : [];
|
|
3533
3564
|
}
|
|
3534
3565
|
getLines() {
|
|
3535
3566
|
return [...this.lines];
|
|
@@ -3593,18 +3624,18 @@ var EnvEditor = class {
|
|
|
3593
3624
|
});
|
|
3594
3625
|
}
|
|
3595
3626
|
save() {
|
|
3596
|
-
const dir =
|
|
3597
|
-
if (!
|
|
3598
|
-
|
|
3627
|
+
const dir = path26.dirname(this.filePath);
|
|
3628
|
+
if (!fs17.existsSync(dir)) {
|
|
3629
|
+
fs17.mkdirSync(dir, { recursive: true });
|
|
3599
3630
|
}
|
|
3600
|
-
|
|
3631
|
+
fs17.writeFileSync(this.filePath, this.lines.join("\n"), "utf-8");
|
|
3601
3632
|
}
|
|
3602
3633
|
};
|
|
3603
3634
|
function discoverEnvironments(projectRoot) {
|
|
3604
|
-
if (!
|
|
3635
|
+
if (!fs17.existsSync(projectRoot)) {
|
|
3605
3636
|
return ["local", "dev", "prod"];
|
|
3606
3637
|
}
|
|
3607
|
-
const files =
|
|
3638
|
+
const files = fs17.readdirSync(projectRoot);
|
|
3608
3639
|
const envs = /* @__PURE__ */ new Set();
|
|
3609
3640
|
for (const file of files) {
|
|
3610
3641
|
if (file.startsWith(".env")) {
|
|
@@ -3629,7 +3660,7 @@ async function runEnvInitExamples(flags = {}) {
|
|
|
3629
3660
|
const projectRoot = flags.cwd || flags.targetDir || findProjectRoot();
|
|
3630
3661
|
const s = p19.spinner();
|
|
3631
3662
|
s.start("Scanning for local environment files...");
|
|
3632
|
-
const files =
|
|
3663
|
+
const files = fs17.readdirSync(projectRoot, { withFileTypes: true });
|
|
3633
3664
|
const envFiles = files.filter((dirent) => dirent.isFile() && dirent.name.startsWith(".env") && !dirent.name.endsWith(".example")).map((dirent) => dirent.name).sort();
|
|
3634
3665
|
if (envFiles.length === 0) {
|
|
3635
3666
|
s.stop("No local .env files found.");
|
|
@@ -3639,11 +3670,11 @@ async function runEnvInitExamples(flags = {}) {
|
|
|
3639
3670
|
s.message(`Found ${envFiles.length} local .env file(s). Generating templates...`);
|
|
3640
3671
|
const generatedFiles = [];
|
|
3641
3672
|
for (const envFile of envFiles) {
|
|
3642
|
-
const sourcePath =
|
|
3673
|
+
const sourcePath = path26.join(projectRoot, envFile);
|
|
3643
3674
|
const targetFile = `${envFile}.example`;
|
|
3644
|
-
const targetPath =
|
|
3675
|
+
const targetPath = path26.join(projectRoot, targetFile);
|
|
3645
3676
|
let overwrite = flags.overwrite;
|
|
3646
|
-
if (overwrite === void 0 && !flags.dryRun && !flags.yes && !process.env.VITEST && process.stdin.isTTY &&
|
|
3677
|
+
if (overwrite === void 0 && !flags.dryRun && !flags.yes && !process.env.VITEST && process.stdin.isTTY && fs17.existsSync(targetPath)) {
|
|
3647
3678
|
overwrite = await p19.confirm({
|
|
3648
3679
|
message: `${targetFile} already exists. Overwrite with redacted values?`,
|
|
3649
3680
|
initialValue: true
|
|
@@ -3677,12 +3708,12 @@ function isInteractive(flags) {
|
|
|
3677
3708
|
function getAllExistingKeys(projectRoot, envs) {
|
|
3678
3709
|
const keys = /* @__PURE__ */ new Set();
|
|
3679
3710
|
for (const env of envs) {
|
|
3680
|
-
const localPath =
|
|
3681
|
-
const examplePath =
|
|
3682
|
-
if (
|
|
3711
|
+
const localPath = path26.join(projectRoot, resolveEnvFilename(env, false));
|
|
3712
|
+
const examplePath = path26.join(projectRoot, resolveEnvFilename(env, true));
|
|
3713
|
+
if (fs17.existsSync(localPath)) {
|
|
3683
3714
|
new EnvEditor(localPath).getKeys().forEach((k) => keys.add(k));
|
|
3684
3715
|
}
|
|
3685
|
-
if (
|
|
3716
|
+
if (fs17.existsSync(examplePath)) {
|
|
3686
3717
|
new EnvEditor(examplePath).getKeys().forEach((k) => keys.add(k));
|
|
3687
3718
|
}
|
|
3688
3719
|
}
|
|
@@ -3754,8 +3785,8 @@ async function runEnvAdd(key, value, flags = {}) {
|
|
|
3754
3785
|
})
|
|
3755
3786
|
);
|
|
3756
3787
|
}
|
|
3757
|
-
const localPath =
|
|
3758
|
-
const examplePath =
|
|
3788
|
+
const localPath = path26.join(projectRoot, resolveEnvFilename(env, false));
|
|
3789
|
+
const examplePath = path26.join(projectRoot, resolveEnvFilename(env, true));
|
|
3759
3790
|
if (flags.dryRun) {
|
|
3760
3791
|
p19.log.info(
|
|
3761
3792
|
pc14.cyan(`[DRY RUN] Would set ${targetKey}=${envVal} in ${resolveEnvFilename(env, false)}`)
|
|
@@ -3802,8 +3833,8 @@ async function runEnvUpdate(key, value, flags = {}) {
|
|
|
3802
3833
|
);
|
|
3803
3834
|
}
|
|
3804
3835
|
const envsWithKey = allEnvs.filter((env) => {
|
|
3805
|
-
const localPath =
|
|
3806
|
-
return
|
|
3836
|
+
const localPath = path26.join(projectRoot, resolveEnvFilename(env, false));
|
|
3837
|
+
return fs17.existsSync(localPath) && new EnvEditor(localPath).has(targetKey);
|
|
3807
3838
|
});
|
|
3808
3839
|
let targetEnvs = [];
|
|
3809
3840
|
if (flags.env) {
|
|
@@ -3829,7 +3860,7 @@ async function runEnvUpdate(key, value, flags = {}) {
|
|
|
3829
3860
|
return { key: targetKey, environments: [] };
|
|
3830
3861
|
}
|
|
3831
3862
|
for (const env of targetEnvs) {
|
|
3832
|
-
const localPath =
|
|
3863
|
+
const localPath = path26.join(projectRoot, resolveEnvFilename(env, false));
|
|
3833
3864
|
const localEditor = new EnvEditor(localPath);
|
|
3834
3865
|
const currentVal = localEditor.getValue(targetKey);
|
|
3835
3866
|
let newVal = value;
|
|
@@ -3859,7 +3890,7 @@ async function runEnvUpdate(key, value, flags = {}) {
|
|
|
3859
3890
|
} else {
|
|
3860
3891
|
localEditor.set(targetKey, newVal);
|
|
3861
3892
|
localEditor.save();
|
|
3862
|
-
const examplePath =
|
|
3893
|
+
const examplePath = path26.join(projectRoot, resolveEnvFilename(env, true));
|
|
3863
3894
|
const exampleEditor = new EnvEditor(examplePath);
|
|
3864
3895
|
if (!exampleEditor.has(targetKey)) {
|
|
3865
3896
|
exampleEditor.set(targetKey, "");
|
|
@@ -3895,9 +3926,9 @@ async function runEnvDelete(key, flags = {}) {
|
|
|
3895
3926
|
);
|
|
3896
3927
|
}
|
|
3897
3928
|
const envsWithKey = allEnvs.filter((env) => {
|
|
3898
|
-
const localPath =
|
|
3899
|
-
const examplePath =
|
|
3900
|
-
return
|
|
3929
|
+
const localPath = path26.join(projectRoot, resolveEnvFilename(env, false));
|
|
3930
|
+
const examplePath = path26.join(projectRoot, resolveEnvFilename(env, true));
|
|
3931
|
+
return fs17.existsSync(localPath) && new EnvEditor(localPath).has(targetKey) || fs17.existsSync(examplePath) && new EnvEditor(examplePath).has(targetKey);
|
|
3901
3932
|
});
|
|
3902
3933
|
let targetEnvs = [];
|
|
3903
3934
|
if (flags.env) {
|
|
@@ -3935,19 +3966,19 @@ async function runEnvDelete(key, flags = {}) {
|
|
|
3935
3966
|
}
|
|
3936
3967
|
}
|
|
3937
3968
|
for (const env of targetEnvs) {
|
|
3938
|
-
const localPath =
|
|
3939
|
-
const examplePath =
|
|
3969
|
+
const localPath = path26.join(projectRoot, resolveEnvFilename(env, false));
|
|
3970
|
+
const examplePath = path26.join(projectRoot, resolveEnvFilename(env, true));
|
|
3940
3971
|
if (flags.dryRun) {
|
|
3941
3972
|
p19.log.info(
|
|
3942
3973
|
pc14.cyan(`[DRY RUN] Would delete ${targetKey} from ${resolveEnvFilename(env, false)} and ${resolveEnvFilename(env, true)}`)
|
|
3943
3974
|
);
|
|
3944
3975
|
} else {
|
|
3945
|
-
if (
|
|
3976
|
+
if (fs17.existsSync(localPath)) {
|
|
3946
3977
|
const localEditor = new EnvEditor(localPath);
|
|
3947
3978
|
localEditor.delete(targetKey);
|
|
3948
3979
|
localEditor.save();
|
|
3949
3980
|
}
|
|
3950
|
-
if (
|
|
3981
|
+
if (fs17.existsSync(examplePath)) {
|
|
3951
3982
|
const exampleEditor = new EnvEditor(examplePath);
|
|
3952
3983
|
exampleEditor.delete(targetKey);
|
|
3953
3984
|
exampleEditor.save();
|
|
@@ -3972,10 +4003,10 @@ async function runEnvAudit(flags = {}) {
|
|
|
3972
4003
|
for (const env of envs) {
|
|
3973
4004
|
const localFile = resolveEnvFilename(env, false);
|
|
3974
4005
|
const exampleFile = resolveEnvFilename(env, true);
|
|
3975
|
-
const localPath =
|
|
3976
|
-
const examplePath =
|
|
3977
|
-
const localExists =
|
|
3978
|
-
const exampleExists =
|
|
4006
|
+
const localPath = path26.join(projectRoot, localFile);
|
|
4007
|
+
const examplePath = path26.join(projectRoot, exampleFile);
|
|
4008
|
+
const localExists = fs17.existsSync(localPath);
|
|
4009
|
+
const exampleExists = fs17.existsSync(examplePath);
|
|
3979
4010
|
const localEditor = new EnvEditor(localPath);
|
|
3980
4011
|
const exampleEditor = new EnvEditor(examplePath);
|
|
3981
4012
|
const localKeys = localExists ? localEditor.getKeys() : [];
|
|
@@ -4314,17 +4345,17 @@ function getModuleBaseDir(projectRoot, modType) {
|
|
|
4314
4345
|
return modType === "shared" ? getConfiguredSharedDir(projectRoot) : getConfiguredFeaturesDir(projectRoot);
|
|
4315
4346
|
}
|
|
4316
4347
|
const folder = modType === "shared" ? "shared" : "features";
|
|
4317
|
-
return
|
|
4348
|
+
return path26.join(projectRoot, "src", folder);
|
|
4318
4349
|
}
|
|
4319
4350
|
function getExistingModuleDir(projectRoot, modType, modName) {
|
|
4320
4351
|
const folder = modType === "shared" ? "shared" : "features";
|
|
4321
4352
|
const configuredDir = modType === "shared" ? getConfiguredSharedDir(projectRoot) : getConfiguredFeaturesDir(projectRoot);
|
|
4322
|
-
const inConfigured =
|
|
4323
|
-
if (
|
|
4324
|
-
const inSrc =
|
|
4325
|
-
if (
|
|
4326
|
-
const inRoot =
|
|
4327
|
-
if (
|
|
4353
|
+
const inConfigured = path26.join(configuredDir, modName);
|
|
4354
|
+
if (fs17.existsSync(inConfigured)) return inConfigured;
|
|
4355
|
+
const inSrc = path26.join(projectRoot, "src", folder, modName);
|
|
4356
|
+
if (fs17.existsSync(inSrc)) return inSrc;
|
|
4357
|
+
const inRoot = path26.join(projectRoot, folder, modName);
|
|
4358
|
+
if (fs17.existsSync(inRoot)) return inRoot;
|
|
4328
4359
|
return null;
|
|
4329
4360
|
}
|
|
4330
4361
|
function checkModuleExists(projectRoot, modType, modName) {
|
|
@@ -4335,14 +4366,14 @@ function getAvailableLocalModules(projectRoot, modType) {
|
|
|
4335
4366
|
const configuredDir = modType === "shared" ? getConfiguredSharedDir(projectRoot) : getConfiguredFeaturesDir(projectRoot);
|
|
4336
4367
|
const dirs = [
|
|
4337
4368
|
configuredDir,
|
|
4338
|
-
|
|
4339
|
-
|
|
4369
|
+
path26.join(projectRoot, "src", folder),
|
|
4370
|
+
path26.join(projectRoot, folder)
|
|
4340
4371
|
];
|
|
4341
4372
|
const set = /* @__PURE__ */ new Set();
|
|
4342
4373
|
for (const dir of dirs) {
|
|
4343
|
-
if (
|
|
4374
|
+
if (fs17.existsSync(dir)) {
|
|
4344
4375
|
try {
|
|
4345
|
-
const entries =
|
|
4376
|
+
const entries = fs17.readdirSync(dir, { withFileTypes: true });
|
|
4346
4377
|
for (const e of entries) {
|
|
4347
4378
|
if (e.isDirectory() && !e.name.startsWith(".")) {
|
|
4348
4379
|
set.add(e.name);
|
|
@@ -4544,7 +4575,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
4544
4575
|
globalAliasMap.set(`@/${folder}/${registryName}/`, `@/${folder}/${programmaticAlias}/`);
|
|
4545
4576
|
globalAliasMap.set(`@/${folder}/${registryName}`, `@/${folder}/${programmaticAlias}`);
|
|
4546
4577
|
const baseDir = getModuleBaseDir(projectRoot, modType);
|
|
4547
|
-
const displayDest =
|
|
4578
|
+
const displayDest = path26.relative(projectRoot, path26.join(baseDir, programmaticAlias));
|
|
4548
4579
|
p19.log.step(`Importing '${registryName}' into '${displayDest}'...`);
|
|
4549
4580
|
resolutions.set(key, {
|
|
4550
4581
|
type: modType,
|
|
@@ -4732,7 +4763,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
4732
4763
|
globalAliasMap.set(`@/${folder}/${registryName}/`, `@/${folder}/${newName}/`);
|
|
4733
4764
|
globalAliasMap.set(`@/${folder}/${registryName}`, `@/${folder}/${newName}`);
|
|
4734
4765
|
const baseDir = getModuleBaseDir(projectRoot, modType);
|
|
4735
|
-
const displayDest =
|
|
4766
|
+
const displayDest = path26.relative(projectRoot, path26.join(baseDir, newName));
|
|
4736
4767
|
p19.log.step(`Importing '${registryName}' into '${displayDest}'...`);
|
|
4737
4768
|
resolutions.set(key, {
|
|
4738
4769
|
type: modType,
|
|
@@ -4784,7 +4815,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
4784
4815
|
continue;
|
|
4785
4816
|
}
|
|
4786
4817
|
const folder = res.type === "shared" ? "shared" : "features";
|
|
4787
|
-
const targetDir =
|
|
4818
|
+
const targetDir = path26.join(getModuleBaseDir(projectRoot, res.type), res.targetName);
|
|
4788
4819
|
const isOverwrite = Boolean(flags.overwrite || res.action === "overwrite");
|
|
4789
4820
|
if (key !== rootKey) {
|
|
4790
4821
|
p19.log.step(
|
|
@@ -4794,30 +4825,30 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
4794
4825
|
if (res.action === "overwrite" && !flags.dryRun) {
|
|
4795
4826
|
const existingDir = getExistingModuleDir(projectRoot, res.type, res.targetName);
|
|
4796
4827
|
if (existingDir && existingDir !== targetDir) {
|
|
4797
|
-
|
|
4828
|
+
fs17.rmSync(existingDir, { recursive: true, force: true });
|
|
4798
4829
|
}
|
|
4799
|
-
if (
|
|
4800
|
-
|
|
4830
|
+
if (fs17.existsSync(targetDir)) {
|
|
4831
|
+
fs17.rmSync(targetDir, { recursive: true, force: true });
|
|
4801
4832
|
}
|
|
4802
4833
|
}
|
|
4803
4834
|
for (const file of res.manifest.files || []) {
|
|
4804
4835
|
if (file === "registry.json") continue;
|
|
4805
4836
|
if (!includeTests && isTestFile(file)) continue;
|
|
4806
4837
|
const remoteFilePath = `${folder}/${res.registryName}/${file}`;
|
|
4807
|
-
const localFilePath =
|
|
4808
|
-
if (
|
|
4838
|
+
const localFilePath = path26.join(targetDir, file);
|
|
4839
|
+
if (fs17.existsSync(localFilePath) && !isOverwrite) {
|
|
4809
4840
|
p19.log.warn(
|
|
4810
|
-
` \u21B3 Skipping existing file: ${pc14.dim(
|
|
4841
|
+
` \u21B3 Skipping existing file: ${pc14.dim(path26.relative(projectRoot, localFilePath))} (use --overwrite to replace)`
|
|
4811
4842
|
);
|
|
4812
4843
|
continue;
|
|
4813
4844
|
}
|
|
4814
4845
|
let content = await fetchRegistryFile(registryBase, remoteFilePath);
|
|
4815
4846
|
content = rewriteImports(content, globalAliasMap);
|
|
4816
4847
|
if (!flags.dryRun) {
|
|
4817
|
-
|
|
4818
|
-
|
|
4848
|
+
fs17.mkdirSync(path26.dirname(localFilePath), { recursive: true });
|
|
4849
|
+
fs17.writeFileSync(localFilePath, content, "utf-8");
|
|
4819
4850
|
}
|
|
4820
|
-
const displayPath =
|
|
4851
|
+
const displayPath = path26.relative(projectRoot, localFilePath);
|
|
4821
4852
|
totalWrittenFiles.push(displayPath);
|
|
4822
4853
|
p19.log.message(` ${pc14.green("+")} ${displayPath}`);
|
|
4823
4854
|
}
|
|
@@ -4843,7 +4874,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
|
|
|
4843
4874
|
} else {
|
|
4844
4875
|
const rootRes = resolutions.get(rootKey);
|
|
4845
4876
|
const baseDir = getModuleBaseDir(projectRoot, type);
|
|
4846
|
-
const displayTarget =
|
|
4877
|
+
const displayTarget = path26.relative(projectRoot, path26.join(baseDir, rootRes.targetName));
|
|
4847
4878
|
p19.log.success(
|
|
4848
4879
|
pc14.green(
|
|
4849
4880
|
`Successfully imported ${type} '${name}' (${totalWrittenFiles.length} file${totalWrittenFiles.length === 1 ? "" : "s"} placed in ${displayTarget})`
|
|
@@ -4862,19 +4893,19 @@ var DependencyRuleError = class extends Error {
|
|
|
4862
4893
|
}
|
|
4863
4894
|
};
|
|
4864
4895
|
function isTestFile2(filePath, projectRoot) {
|
|
4865
|
-
const norm = (projectRoot ?
|
|
4866
|
-
const base =
|
|
4896
|
+
const norm = (projectRoot ? path26.relative(projectRoot, filePath) : filePath).replace(/\\/g, "/");
|
|
4897
|
+
const base = path26.basename(norm);
|
|
4867
4898
|
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);
|
|
4868
4899
|
}
|
|
4869
4900
|
function scanDirFiles(dir, projectRoot) {
|
|
4870
|
-
if (!
|
|
4871
|
-
const entries =
|
|
4901
|
+
if (!fs17.existsSync(dir)) return [];
|
|
4902
|
+
const entries = fs17.readdirSync(dir, { withFileTypes: true });
|
|
4872
4903
|
const files = [];
|
|
4873
4904
|
for (const entry of entries) {
|
|
4874
4905
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "__tests__" || entry.name.startsWith(".")) {
|
|
4875
4906
|
continue;
|
|
4876
4907
|
}
|
|
4877
|
-
const fullPath =
|
|
4908
|
+
const fullPath = path26.join(dir, entry.name);
|
|
4878
4909
|
if (entry.isDirectory()) {
|
|
4879
4910
|
files.push(...scanDirFiles(fullPath, projectRoot));
|
|
4880
4911
|
} else if (entry.isFile() && (entry.name.endsWith(".ts") || entry.name.endsWith(".js")) && !isTestFile2(fullPath, projectRoot)) {
|
|
@@ -4883,101 +4914,194 @@ function scanDirFiles(dir, projectRoot) {
|
|
|
4883
4914
|
}
|
|
4884
4915
|
return files;
|
|
4885
4916
|
}
|
|
4886
|
-
function classifyFile(
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
}
|
|
4906
|
-
const
|
|
4907
|
-
if (
|
|
4908
|
-
const
|
|
4909
|
-
|
|
4910
|
-
|
|
4911
|
-
|
|
4912
|
-
layer = "
|
|
4913
|
-
|
|
4914
|
-
|
|
4915
|
-
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4917
|
+
function classifyFile(fullPathAbs, featuresBaseAbs, sharedBaseAbs, errorsBaseAbs) {
|
|
4918
|
+
if (!sharedBaseAbs || !errorsBaseAbs) {
|
|
4919
|
+
const paths = getResolvedLintPaths(featuresBaseAbs, loadLintConfig(featuresBaseAbs));
|
|
4920
|
+
featuresBaseAbs = paths.featuresBase;
|
|
4921
|
+
sharedBaseAbs = paths.sharedBase;
|
|
4922
|
+
errorsBaseAbs = paths.errorsBase;
|
|
4923
|
+
}
|
|
4924
|
+
const normFullPath = path26.resolve(fullPathAbs);
|
|
4925
|
+
const normErrorsBase = path26.resolve(errorsBaseAbs);
|
|
4926
|
+
const normSharedBase = path26.resolve(sharedBaseAbs);
|
|
4927
|
+
const normFeaturesBase = path26.resolve(featuresBaseAbs);
|
|
4928
|
+
const relErrors = path26.relative(normErrorsBase, normFullPath).replace(/\\/g, "/");
|
|
4929
|
+
if (!relErrors.startsWith("..") && !path26.isAbsolute(relErrors)) {
|
|
4930
|
+
return {
|
|
4931
|
+
moduleType: "error",
|
|
4932
|
+
moduleName: "global-errors",
|
|
4933
|
+
feature: "global-errors",
|
|
4934
|
+
layer: "domain"
|
|
4935
|
+
};
|
|
4936
|
+
}
|
|
4937
|
+
const relShared = path26.relative(normSharedBase, normFullPath).replace(/\\/g, "/");
|
|
4938
|
+
if (!relShared.startsWith("..") && !path26.isAbsolute(relShared)) {
|
|
4939
|
+
const parts = relShared.split("/").filter(Boolean);
|
|
4940
|
+
if (parts.length >= 1) {
|
|
4941
|
+
const moduleName = parts[0];
|
|
4942
|
+
const rest = parts.slice(1).join("/");
|
|
4943
|
+
let layer = "root";
|
|
4944
|
+
if (rest.startsWith("domain/") || rest === "domain" || rest.startsWith("errors/") || rest === "errors") {
|
|
4945
|
+
layer = "domain";
|
|
4946
|
+
} else if (rest.startsWith("ports/") || rest === "ports") {
|
|
4947
|
+
layer = "ports";
|
|
4948
|
+
} else if (rest.startsWith("infrastructure/") || rest === "infrastructure") {
|
|
4949
|
+
layer = "infrastructure";
|
|
4950
|
+
}
|
|
4951
|
+
return { moduleType: "shared", moduleName, feature: moduleName, layer };
|
|
4952
|
+
}
|
|
4953
|
+
}
|
|
4954
|
+
const relFeatures = path26.relative(normFeaturesBase, normFullPath).replace(/\\/g, "/");
|
|
4955
|
+
if (!relFeatures.startsWith("..") && !path26.isAbsolute(relFeatures)) {
|
|
4956
|
+
const parts = relFeatures.split("/").filter(Boolean);
|
|
4957
|
+
if (parts.length >= 2) {
|
|
4958
|
+
const moduleName = parts[0];
|
|
4959
|
+
const subfolder = parts[1];
|
|
4960
|
+
let layer;
|
|
4961
|
+
if (subfolder === "domain" || subfolder === "errors") {
|
|
4962
|
+
layer = "domain";
|
|
4963
|
+
} else if (subfolder === "useCases" || subfolder === "usecases") {
|
|
4964
|
+
layer = "useCases";
|
|
4965
|
+
} else if (subfolder === "services") {
|
|
4966
|
+
layer = "services";
|
|
4967
|
+
} else if (subfolder === "infrastructure") {
|
|
4968
|
+
layer = "infrastructure";
|
|
4969
|
+
} else if (subfolder === "pxExpress" || subfolder === "presentation" || subfolder === "handlers" || subfolder.startsWith("px")) {
|
|
4970
|
+
layer = "presentation";
|
|
4971
|
+
}
|
|
4972
|
+
return { moduleType: "feature", moduleName, feature: moduleName, layer };
|
|
4973
|
+
}
|
|
4919
4974
|
}
|
|
4920
4975
|
return {};
|
|
4921
4976
|
}
|
|
4922
|
-
function classifyTarget(specifier, sourceFileAbs, projectRoot) {
|
|
4977
|
+
function classifyTarget(specifier, sourceFileAbs, projectRoot, featuresBaseAbs, sharedBaseAbs, errorsBaseAbs) {
|
|
4923
4978
|
if (specifier === "@solid-stack/di" || specifier.startsWith("@solid-stack/di/")) {
|
|
4924
4979
|
return { isExternal: true, isDiFramework: true };
|
|
4925
4980
|
}
|
|
4926
|
-
if (specifier.startsWith("node:") || [
|
|
4981
|
+
if (specifier.startsWith("node:") || [
|
|
4982
|
+
"crypto",
|
|
4983
|
+
"fs",
|
|
4984
|
+
"path",
|
|
4985
|
+
"http",
|
|
4986
|
+
"https",
|
|
4987
|
+
"url",
|
|
4988
|
+
"os",
|
|
4989
|
+
"child_process",
|
|
4990
|
+
"stream",
|
|
4991
|
+
"express",
|
|
4992
|
+
"cors",
|
|
4993
|
+
"dotenv"
|
|
4994
|
+
].includes(specifier)) {
|
|
4927
4995
|
return { isExternal: true, isDiFramework: false };
|
|
4928
4996
|
}
|
|
4929
|
-
|
|
4997
|
+
if (!featuresBaseAbs || !sharedBaseAbs || !errorsBaseAbs) {
|
|
4998
|
+
const paths = getResolvedLintPaths(projectRoot, loadLintConfig(projectRoot));
|
|
4999
|
+
featuresBaseAbs = featuresBaseAbs || paths.featuresBase;
|
|
5000
|
+
sharedBaseAbs = sharedBaseAbs || paths.sharedBase;
|
|
5001
|
+
errorsBaseAbs = errorsBaseAbs || paths.errorsBase;
|
|
5002
|
+
}
|
|
5003
|
+
const isGlobalConfig = specifier === "@configs" || specifier.startsWith("@configs/") || specifier === "@/configs" || specifier.startsWith("@/configs/") || specifier === "~/configs" || specifier.startsWith("~/configs/") || specifier === "configs" || specifier.startsWith("configs/");
|
|
5004
|
+
let targetAbs = null;
|
|
4930
5005
|
if (specifier.startsWith(".")) {
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
4943
|
-
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
5006
|
+
targetAbs = path26.resolve(path26.dirname(sourceFileAbs), specifier);
|
|
5007
|
+
} else {
|
|
5008
|
+
const featRel = path26.relative(projectRoot, featuresBaseAbs).replace(/\\/g, "/");
|
|
5009
|
+
const sharedRel = path26.relative(projectRoot, sharedBaseAbs).replace(/\\/g, "/");
|
|
5010
|
+
const errorsRel = path26.relative(projectRoot, errorsBaseAbs).replace(/\\/g, "/");
|
|
5011
|
+
const featPrefixes = ["features"];
|
|
5012
|
+
if (featRel && featRel !== "." && !featRel.startsWith("..")) {
|
|
5013
|
+
featPrefixes.push(featRel);
|
|
5014
|
+
const b = path26.basename(featRel);
|
|
5015
|
+
if (!featPrefixes.includes(b)) featPrefixes.push(b);
|
|
5016
|
+
}
|
|
5017
|
+
const sharedPrefixes = ["shared"];
|
|
5018
|
+
if (sharedRel && sharedRel !== "." && !sharedRel.startsWith("..")) {
|
|
5019
|
+
sharedPrefixes.push(sharedRel);
|
|
5020
|
+
const b = path26.basename(sharedRel);
|
|
5021
|
+
if (!sharedPrefixes.includes(b)) sharedPrefixes.push(b);
|
|
5022
|
+
}
|
|
5023
|
+
const errorsPrefixes = ["errors"];
|
|
5024
|
+
if (errorsRel && errorsRel !== "." && !errorsRel.startsWith("..")) {
|
|
5025
|
+
errorsPrefixes.push(errorsRel);
|
|
5026
|
+
const b = path26.basename(errorsRel);
|
|
5027
|
+
if (!errorsPrefixes.includes(b)) errorsPrefixes.push(b);
|
|
5028
|
+
}
|
|
5029
|
+
for (const prefix of featPrefixes) {
|
|
5030
|
+
const aliasRegex = new RegExp(`^([@~]\\/|@)?${prefix}\\/(.*)$`);
|
|
5031
|
+
const m = specifier.match(aliasRegex);
|
|
5032
|
+
if (m && m[2]) {
|
|
5033
|
+
targetAbs = path26.resolve(featuresBaseAbs, m[2]);
|
|
5034
|
+
break;
|
|
5035
|
+
}
|
|
5036
|
+
}
|
|
5037
|
+
if (!targetAbs) {
|
|
5038
|
+
for (const prefix of sharedPrefixes) {
|
|
5039
|
+
const aliasRegex = new RegExp(`^([@~]\\/|@)?${prefix}\\/(.*)$`);
|
|
5040
|
+
const m = specifier.match(aliasRegex);
|
|
5041
|
+
if (m && m[2]) {
|
|
5042
|
+
targetAbs = path26.resolve(sharedBaseAbs, m[2]);
|
|
5043
|
+
break;
|
|
5044
|
+
}
|
|
5045
|
+
}
|
|
5046
|
+
}
|
|
5047
|
+
if (!targetAbs) {
|
|
5048
|
+
for (const prefix of errorsPrefixes) {
|
|
5049
|
+
const aliasRegex = new RegExp(`^([@~]\\/|@)?${prefix}(?:\\/(.*))?$`);
|
|
5050
|
+
const m = specifier.match(aliasRegex);
|
|
5051
|
+
if (m) {
|
|
5052
|
+
targetAbs = path26.resolve(errorsBaseAbs, m[2] || "");
|
|
5053
|
+
break;
|
|
5054
|
+
}
|
|
5055
|
+
}
|
|
5056
|
+
}
|
|
5057
|
+
if (!targetAbs && (specifier.startsWith("@/") || specifier.startsWith("~/"))) {
|
|
5058
|
+
const sub = specifier.slice(2);
|
|
5059
|
+
const srcCandidate = path26.resolve(projectRoot, "src", sub);
|
|
5060
|
+
const rootCandidate = path26.resolve(projectRoot, sub);
|
|
5061
|
+
if (fs17.existsSync(srcCandidate)) {
|
|
5062
|
+
targetAbs = srcCandidate;
|
|
5063
|
+
} else if (fs17.existsSync(rootCandidate)) {
|
|
5064
|
+
targetAbs = rootCandidate;
|
|
5065
|
+
} else {
|
|
5066
|
+
targetAbs = srcCandidate;
|
|
5067
|
+
}
|
|
5068
|
+
}
|
|
5069
|
+
if (!targetAbs) {
|
|
5070
|
+
const featCandidate = path26.resolve(featuresBaseAbs, specifier);
|
|
5071
|
+
if (fs17.existsSync(featCandidate) || fs17.existsSync(featCandidate + ".ts") || fs17.existsSync(featCandidate + ".js")) {
|
|
5072
|
+
targetAbs = featCandidate;
|
|
5073
|
+
}
|
|
5074
|
+
}
|
|
5075
|
+
}
|
|
5076
|
+
if (!targetAbs) {
|
|
5077
|
+
return { isExternal: true, isDiFramework: false, isGlobalConfig };
|
|
5078
|
+
}
|
|
5079
|
+
const normTarget = path26.resolve(targetAbs);
|
|
5080
|
+
const srcConfig = path26.resolve(projectRoot, "src/configs");
|
|
5081
|
+
const rootConfig = path26.resolve(projectRoot, "configs");
|
|
5082
|
+
const isTargetConfig = isGlobalConfig || normTarget === srcConfig || normTarget.startsWith(srcConfig + path26.sep) || normTarget === rootConfig || normTarget.startsWith(rootConfig + path26.sep);
|
|
5083
|
+
const classification = classifyFile(targetAbs, featuresBaseAbs, sharedBaseAbs, errorsBaseAbs);
|
|
5084
|
+
if (classification.moduleType === "error") {
|
|
5085
|
+
return {
|
|
5086
|
+
isExternal: false,
|
|
5087
|
+
isDiFramework: false,
|
|
5088
|
+
isGlobalError: true,
|
|
5089
|
+
isTargetError: true
|
|
5090
|
+
};
|
|
4952
5091
|
}
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
const
|
|
4957
|
-
const
|
|
4958
|
-
const rest = featMatch[3] || "";
|
|
4959
|
-
let targetLayer;
|
|
4960
|
-
if (targetSubfolder === "domain" || targetSubfolder === "errors") {
|
|
4961
|
-
targetLayer = "domain";
|
|
4962
|
-
} else if (targetSubfolder === "useCases" || targetSubfolder === "usecases") {
|
|
4963
|
-
targetLayer = "useCases";
|
|
4964
|
-
} else if (targetSubfolder === "services") {
|
|
4965
|
-
targetLayer = "services";
|
|
4966
|
-
} else if (targetSubfolder === "infrastructure") {
|
|
4967
|
-
targetLayer = "infrastructure";
|
|
4968
|
-
} else if (targetSubfolder === "pxExpress" || targetSubfolder === "presentation" || targetSubfolder === "handlers" || targetSubfolder.startsWith("px")) {
|
|
4969
|
-
targetLayer = "presentation";
|
|
4970
|
-
}
|
|
4971
|
-
const basePart = rest ? path2.basename(rest) : targetSubfolder;
|
|
4972
|
-
const targetFileName = basePart.replace(/\.(js|ts|mjs|cjs)$/, "");
|
|
5092
|
+
if (classification.moduleType === "feature") {
|
|
5093
|
+
const rel = path26.relative(featuresBaseAbs, targetAbs).replace(/\\/g, "/");
|
|
5094
|
+
const parts = rel.split("/").filter(Boolean);
|
|
5095
|
+
const targetSubfolder = parts[1];
|
|
5096
|
+
const targetFileName = path26.basename(targetAbs).replace(/\.(js|ts|mjs|cjs)$/, "");
|
|
4973
5097
|
const isTargetPort = /^I[A-Z]/.test(targetFileName);
|
|
4974
5098
|
const isTargetRepo = isTargetPort && targetFileName.includes("Repo");
|
|
4975
|
-
const isTargetError = targetSubfolder === "errors" ||
|
|
5099
|
+
const isTargetError = targetSubfolder === "errors" || rel.includes("/errors/") || targetFileName.endsWith("Error") || targetFileName.endsWith("Errors");
|
|
4976
5100
|
return {
|
|
4977
5101
|
isExternal: false,
|
|
4978
5102
|
isDiFramework: false,
|
|
4979
|
-
targetFeature,
|
|
4980
|
-
targetLayer,
|
|
5103
|
+
targetFeature: classification.moduleName,
|
|
5104
|
+
targetLayer: classification.layer,
|
|
4981
5105
|
targetSubfolder,
|
|
4982
5106
|
targetFileName,
|
|
4983
5107
|
isTargetPort,
|
|
@@ -4985,25 +5109,21 @@ function classifyTarget(specifier, sourceFileAbs, projectRoot) {
|
|
|
4985
5109
|
isTargetError
|
|
4986
5110
|
};
|
|
4987
5111
|
}
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
const
|
|
4991
|
-
const sharedRest = sharedMatch[2] || "";
|
|
4992
|
-
const isSharedRoot = !sharedRest.includes("/");
|
|
4993
|
-
const isSharedPorts = sharedRest.startsWith("ports/") || sharedRest === "ports";
|
|
4994
|
-
const isSharedInfra = sharedRest.startsWith("infrastructure/") || sharedRest === "infrastructure";
|
|
4995
|
-
const isSharedDomain = sharedRest.startsWith("domain/") || sharedRest === "domain";
|
|
5112
|
+
if (classification.moduleType === "shared") {
|
|
5113
|
+
const targetFileName = path26.basename(targetAbs).replace(/\.(js|ts|mjs|cjs)$/, "");
|
|
5114
|
+
const isTargetError = classification.layer === "domain" && (targetFileName.endsWith("Error") || targetFileName.endsWith("Errors") || targetAbs.includes("/errors/"));
|
|
4996
5115
|
return {
|
|
4997
5116
|
isExternal: false,
|
|
4998
5117
|
isDiFramework: false,
|
|
4999
|
-
targetSharedModule,
|
|
5000
|
-
isSharedRoot,
|
|
5001
|
-
isSharedPorts,
|
|
5002
|
-
isSharedInfra,
|
|
5003
|
-
isSharedDomain
|
|
5118
|
+
targetSharedModule: classification.moduleName,
|
|
5119
|
+
isSharedRoot: classification.layer === "root",
|
|
5120
|
+
isSharedPorts: classification.layer === "ports",
|
|
5121
|
+
isSharedInfra: classification.layer === "infrastructure",
|
|
5122
|
+
isSharedDomain: classification.layer === "domain",
|
|
5123
|
+
isTargetError
|
|
5004
5124
|
};
|
|
5005
5125
|
}
|
|
5006
|
-
return { isExternal: true, isDiFramework: false, isGlobalConfig };
|
|
5126
|
+
return { isExternal: true, isDiFramework: false, isGlobalConfig: isTargetConfig };
|
|
5007
5127
|
}
|
|
5008
5128
|
function extractImportStatements(content) {
|
|
5009
5129
|
const statements = [];
|
|
@@ -5125,22 +5245,50 @@ var FeatureDependencyGraph = class {
|
|
|
5125
5245
|
return dfs(start);
|
|
5126
5246
|
}
|
|
5127
5247
|
};
|
|
5128
|
-
function discoverAllFeatures(
|
|
5129
|
-
const
|
|
5130
|
-
if (!
|
|
5131
|
-
const
|
|
5132
|
-
|
|
5248
|
+
function discoverAllFeatures(featuresBaseAbs, excludeDirs = []) {
|
|
5249
|
+
const base = featuresBaseAbs;
|
|
5250
|
+
if (!fs17.existsSync(base)) return [];
|
|
5251
|
+
const excludeSet = new Set(excludeDirs.map((d) => path26.resolve(d)));
|
|
5252
|
+
const entries = fs17.readdirSync(base, { withFileTypes: true });
|
|
5253
|
+
return entries.filter((e) => {
|
|
5254
|
+
if (!e.isDirectory()) return false;
|
|
5255
|
+
if (e.name.startsWith(".")) return false;
|
|
5256
|
+
if (["__tests__", "tests", "node_modules", "dist", "coverage", "scratch"].includes(e.name)) {
|
|
5257
|
+
return false;
|
|
5258
|
+
}
|
|
5259
|
+
const resolved = path26.resolve(base, e.name);
|
|
5260
|
+
for (const ex of excludeSet) {
|
|
5261
|
+
if (ex === resolved || ex.startsWith(resolved + path26.sep) || resolved.startsWith(ex + path26.sep)) {
|
|
5262
|
+
return false;
|
|
5263
|
+
}
|
|
5264
|
+
}
|
|
5265
|
+
return true;
|
|
5266
|
+
}).map((e) => ({
|
|
5133
5267
|
name: e.name,
|
|
5134
|
-
dir:
|
|
5268
|
+
dir: path26.join(base, e.name)
|
|
5135
5269
|
})).sort((a, b) => a.name.localeCompare(b.name));
|
|
5136
5270
|
}
|
|
5137
|
-
function discoverAllShared(
|
|
5138
|
-
const
|
|
5139
|
-
if (!
|
|
5140
|
-
const
|
|
5141
|
-
|
|
5271
|
+
function discoverAllShared(sharedBaseAbs, excludeDirs = []) {
|
|
5272
|
+
const base = sharedBaseAbs;
|
|
5273
|
+
if (!fs17.existsSync(base)) return [];
|
|
5274
|
+
const excludeSet = new Set(excludeDirs.map((d) => path26.resolve(d)));
|
|
5275
|
+
const entries = fs17.readdirSync(base, { withFileTypes: true });
|
|
5276
|
+
return entries.filter((e) => {
|
|
5277
|
+
if (!e.isDirectory()) return false;
|
|
5278
|
+
if (e.name.startsWith(".")) return false;
|
|
5279
|
+
if (["__tests__", "tests", "node_modules", "dist", "coverage", "scratch"].includes(e.name)) {
|
|
5280
|
+
return false;
|
|
5281
|
+
}
|
|
5282
|
+
const resolved = path26.resolve(base, e.name);
|
|
5283
|
+
for (const ex of excludeSet) {
|
|
5284
|
+
if (ex === resolved || ex.startsWith(resolved + path26.sep) || resolved.startsWith(ex + path26.sep)) {
|
|
5285
|
+
return false;
|
|
5286
|
+
}
|
|
5287
|
+
}
|
|
5288
|
+
return true;
|
|
5289
|
+
}).map((e) => ({
|
|
5142
5290
|
name: e.name,
|
|
5143
|
-
dir:
|
|
5291
|
+
dir: path26.join(base, e.name)
|
|
5144
5292
|
})).sort((a, b) => a.name.localeCompare(b.name));
|
|
5145
5293
|
}
|
|
5146
5294
|
function extractClassMethods(content, className) {
|
|
@@ -5296,7 +5444,7 @@ function extractClassMethods(content, className) {
|
|
|
5296
5444
|
return methods;
|
|
5297
5445
|
}
|
|
5298
5446
|
function checkUseCaseShape(featureName, filePath, relativePath, content, addViolation) {
|
|
5299
|
-
const fileName =
|
|
5447
|
+
const fileName = path26.basename(filePath);
|
|
5300
5448
|
const lines = content.split(/\r?\n/);
|
|
5301
5449
|
const classMatch = content.match(/(?:export\s+(?:default\s+)?)?class\s+([A-Za-z0-9_]+)/);
|
|
5302
5450
|
if (!classMatch) {
|
|
@@ -5392,7 +5540,7 @@ private ${m.name}(...) { ... }`
|
|
|
5392
5540
|
}
|
|
5393
5541
|
}
|
|
5394
5542
|
function checkServiceShape(featureName, filePath, relativePath, content, addViolation) {
|
|
5395
|
-
const fileName =
|
|
5543
|
+
const fileName = path26.basename(filePath);
|
|
5396
5544
|
const lines = content.split(/\r?\n/);
|
|
5397
5545
|
const classMatch = content.match(/(?:export\s+(?:default\s+)?)?class\s+([A-Za-z0-9_]+)/);
|
|
5398
5546
|
if (!classMatch) {
|
|
@@ -5491,11 +5639,40 @@ function lintCodebase(options = {}) {
|
|
|
5491
5639
|
const startTime = Date.now();
|
|
5492
5640
|
const projectRoot = options.projectRoot || findProjectRoot(options.targetDir || process.cwd());
|
|
5493
5641
|
const failFast = !options.complete;
|
|
5494
|
-
const
|
|
5495
|
-
const
|
|
5642
|
+
const lintConfig = loadLintConfig(projectRoot);
|
|
5643
|
+
const { featuresBase, sharedBase, errorsBase } = getResolvedLintPaths(projectRoot, lintConfig);
|
|
5644
|
+
const missingFoundations = [];
|
|
5645
|
+
if (!fs17.existsSync(featuresBase)) missingFoundations.push("features/");
|
|
5646
|
+
if (!fs17.existsSync(sharedBase)) missingFoundations.push("shared/");
|
|
5647
|
+
if (!fs17.existsSync(errorsBase)) missingFoundations.push("errors/");
|
|
5648
|
+
if (missingFoundations.length > 0) {
|
|
5649
|
+
throw new DependencyRuleError(
|
|
5650
|
+
`Project Structure Violation: Missing required foundational directories: ${missingFoundations.join(", ")}. Every project must contain 'features/', 'shared/', and 'errors/'.`,
|
|
5651
|
+
[],
|
|
5652
|
+
true
|
|
5653
|
+
);
|
|
5654
|
+
}
|
|
5655
|
+
const baseErrorRelative = lintConfig.baseErrorPath || path26.relative(projectRoot, path26.join(errorsBase, "AppError.ts")).replace(/\\/g, "/");
|
|
5656
|
+
const baseErrorAbs = path26.resolve(projectRoot, baseErrorRelative);
|
|
5657
|
+
if (!fs17.existsSync(baseErrorAbs)) {
|
|
5658
|
+
throw new DependencyRuleError(
|
|
5659
|
+
`Project Structure Violation: Base error class not found at '${baseErrorRelative}'. Create this file or update 'baseErrorPath' in mason-lint.config.json.`,
|
|
5660
|
+
[],
|
|
5661
|
+
true
|
|
5662
|
+
);
|
|
5663
|
+
}
|
|
5664
|
+
const baseErrorContent = fs17.readFileSync(baseErrorAbs, "utf-8");
|
|
5665
|
+
const baseClassMatch = baseErrorContent.match(
|
|
5666
|
+
/(?:export\s+(?:default\s+)?)?(?:abstract\s+)?class\s+([A-Za-z0-9_]+)/
|
|
5667
|
+
);
|
|
5668
|
+
const baseErrorClassName = baseClassMatch ? baseClassMatch[1] : "AppError";
|
|
5669
|
+
const features = discoverAllFeatures(featuresBase, [sharedBase, errorsBase]);
|
|
5670
|
+
const sharedModules = discoverAllShared(sharedBase, [featuresBase, errorsBase]);
|
|
5671
|
+
const errorModule = { name: "global-errors", dir: errorsBase, type: "error" };
|
|
5496
5672
|
const allModules = [
|
|
5497
5673
|
...features.map((f) => ({ ...f, type: "feature" })),
|
|
5498
|
-
...sharedModules.map((s) => ({ ...s, type: "shared" }))
|
|
5674
|
+
...sharedModules.map((s) => ({ ...s, type: "shared" })),
|
|
5675
|
+
errorModule
|
|
5499
5676
|
];
|
|
5500
5677
|
const graph = new FeatureDependencyGraph();
|
|
5501
5678
|
const allViolations = [];
|
|
@@ -5525,7 +5702,7 @@ Code: ${v.code}`;
|
|
|
5525
5702
|
scannedFilesCount: 0,
|
|
5526
5703
|
passed: true,
|
|
5527
5704
|
violations: [],
|
|
5528
|
-
layersChecked: mod.type === "feature" ? ["domain", "useCases", "services", "infrastructure", "presentation"] : ["domain", "ports", "infrastructure", "root"]
|
|
5705
|
+
layersChecked: mod.type === "feature" ? ["domain", "useCases", "services", "infrastructure", "presentation"] : mod.type === "shared" ? ["domain", "ports", "infrastructure", "root"] : ["domain"]
|
|
5529
5706
|
});
|
|
5530
5707
|
}
|
|
5531
5708
|
for (const mod of allModules) {
|
|
@@ -5533,13 +5710,128 @@ Code: ${v.code}`;
|
|
|
5533
5710
|
const allFiles = scanDirFiles(mod.dir, projectRoot);
|
|
5534
5711
|
modResult.scannedFilesCount = allFiles.length;
|
|
5535
5712
|
for (const file of allFiles) {
|
|
5536
|
-
const relPath =
|
|
5537
|
-
const { moduleType, moduleName, layer } = classifyFile(file,
|
|
5713
|
+
const relPath = path26.relative(projectRoot, file).replace(/\\/g, "/");
|
|
5714
|
+
const { moduleType, moduleName, layer } = classifyFile(file, featuresBase, sharedBase, errorsBase);
|
|
5538
5715
|
if (!layer || !moduleType || !moduleName) continue;
|
|
5539
|
-
const content =
|
|
5716
|
+
const content = fs17.readFileSync(file, "utf-8");
|
|
5540
5717
|
const statements = extractImportStatements(content);
|
|
5541
|
-
const baseName =
|
|
5718
|
+
const baseName = path26.basename(file);
|
|
5542
5719
|
const isBarrel = baseName === "index.ts" || baseName === "index.js";
|
|
5720
|
+
const throwErrorRegex = /\bthrow\s+(?:new\s+)?Error\s*\(/g;
|
|
5721
|
+
let throwMatch;
|
|
5722
|
+
while ((throwMatch = throwErrorRegex.exec(content)) !== null) {
|
|
5723
|
+
const charIndex = throwMatch.index;
|
|
5724
|
+
const lineNum = content.substring(0, charIndex).split("\n").length;
|
|
5725
|
+
const lineCode = content.split(/\r?\n/)[lineNum - 1]?.trim() || throwMatch[0];
|
|
5726
|
+
if (lineCode.startsWith("//")) continue;
|
|
5727
|
+
addViolation({
|
|
5728
|
+
feature: moduleName,
|
|
5729
|
+
layer,
|
|
5730
|
+
file,
|
|
5731
|
+
relativePath: relPath,
|
|
5732
|
+
line: lineNum,
|
|
5733
|
+
category: "Plain Error Throw Violation",
|
|
5734
|
+
code: lineCode,
|
|
5735
|
+
ruleId: "E3_PLAIN_ERROR_THROW",
|
|
5736
|
+
severity: "error",
|
|
5737
|
+
advice: `Throwing plain 'Error' is prohibited. You must throw '${baseErrorClassName}' or a domain-specific error class that inherits from it.`,
|
|
5738
|
+
fixExample: {
|
|
5739
|
+
bad: lineCode,
|
|
5740
|
+
good: `throw new ${baseErrorClassName}("Something went wrong");`
|
|
5741
|
+
}
|
|
5742
|
+
});
|
|
5743
|
+
}
|
|
5744
|
+
const isErrorFile = relPath.includes("/errors/") || relPath.startsWith("errors/") || relPath.startsWith("src/errors/") || moduleType === "error" || baseName.endsWith("Error.ts") || baseName.endsWith("Errors.ts") || baseName.endsWith("Error.js") || baseName.endsWith("Errors.js");
|
|
5745
|
+
const isBaseErrorFile = path26.resolve(file) === path26.resolve(baseErrorAbs);
|
|
5746
|
+
if (isErrorFile && !isBaseErrorFile) {
|
|
5747
|
+
const classRegex = /(?:export\s+(?:default\s+)?)?(?:abstract\s+)?class\s+([A-Za-z0-9_]+)(?:<[^>]+>)?(?:\s+extends\s+([A-Za-z0-9_]+))?/g;
|
|
5748
|
+
let classMatch;
|
|
5749
|
+
while ((classMatch = classRegex.exec(content)) !== null) {
|
|
5750
|
+
const className = classMatch[1];
|
|
5751
|
+
const extendsName = classMatch[2];
|
|
5752
|
+
const charIndex = classMatch.index;
|
|
5753
|
+
const lineNum = content.substring(0, charIndex).split("\n").length;
|
|
5754
|
+
const lineCode = content.split(/\r?\n/)[lineNum - 1]?.trim() || classMatch[0];
|
|
5755
|
+
if (lineCode.startsWith("//")) continue;
|
|
5756
|
+
if (!extendsName) {
|
|
5757
|
+
addViolation({
|
|
5758
|
+
feature: moduleName,
|
|
5759
|
+
layer,
|
|
5760
|
+
file,
|
|
5761
|
+
relativePath: relPath,
|
|
5762
|
+
line: lineNum,
|
|
5763
|
+
category: "Error Inheritance Violation",
|
|
5764
|
+
code: lineCode,
|
|
5765
|
+
ruleId: "E4_MISSING_INHERITANCE",
|
|
5766
|
+
severity: "error",
|
|
5767
|
+
advice: `Error class '${className}' must extend '${baseErrorClassName}' (or another class that derives from it).`,
|
|
5768
|
+
fixExample: {
|
|
5769
|
+
bad: lineCode,
|
|
5770
|
+
good: `export class ${className} extends ${baseErrorClassName} { ... }`
|
|
5771
|
+
}
|
|
5772
|
+
});
|
|
5773
|
+
} else if (extendsName === "Error") {
|
|
5774
|
+
addViolation({
|
|
5775
|
+
feature: moduleName,
|
|
5776
|
+
layer,
|
|
5777
|
+
file,
|
|
5778
|
+
relativePath: relPath,
|
|
5779
|
+
line: lineNum,
|
|
5780
|
+
category: "Error Inheritance Violation",
|
|
5781
|
+
code: lineCode,
|
|
5782
|
+
ruleId: "E5_NATIVE_ERROR_INHERITANCE",
|
|
5783
|
+
severity: "error",
|
|
5784
|
+
advice: `Error class '${className}' extends the native 'Error'. It must extend your base error class ('${baseErrorClassName}').`,
|
|
5785
|
+
fixExample: {
|
|
5786
|
+
bad: lineCode,
|
|
5787
|
+
good: `export class ${className} extends ${baseErrorClassName} { ... }`
|
|
5788
|
+
}
|
|
5789
|
+
});
|
|
5790
|
+
}
|
|
5791
|
+
}
|
|
5792
|
+
}
|
|
5793
|
+
if (moduleType === "error") {
|
|
5794
|
+
for (const stmt of statements) {
|
|
5795
|
+
const target = classifyTarget(stmt.specifier, file, projectRoot, featuresBase, sharedBase, errorsBase);
|
|
5796
|
+
if (target.targetFeature) {
|
|
5797
|
+
addViolation({
|
|
5798
|
+
feature: "global-errors",
|
|
5799
|
+
layer: "domain",
|
|
5800
|
+
file,
|
|
5801
|
+
relativePath: relPath,
|
|
5802
|
+
line: stmt.line,
|
|
5803
|
+
category: "Global Error Purity Violation",
|
|
5804
|
+
code: stmt.rawCode,
|
|
5805
|
+
ruleId: "E1_FEATURE_DEPENDENCY",
|
|
5806
|
+
severity: "error",
|
|
5807
|
+
advice: `Global errors must not depend on features ('${target.targetFeature}'). Global errors represent pure domain or system states.`,
|
|
5808
|
+
fixExample: {
|
|
5809
|
+
bad: stmt.rawCode,
|
|
5810
|
+
good: "// Global errors must not reference specific features. Keep error types pure."
|
|
5811
|
+
}
|
|
5812
|
+
});
|
|
5813
|
+
}
|
|
5814
|
+
if (target.targetSharedModule && !target.isSharedDomain) {
|
|
5815
|
+
addViolation({
|
|
5816
|
+
feature: "global-errors",
|
|
5817
|
+
layer: "domain",
|
|
5818
|
+
file,
|
|
5819
|
+
relativePath: relPath,
|
|
5820
|
+
line: stmt.line,
|
|
5821
|
+
category: "Global Error Purity Violation",
|
|
5822
|
+
code: stmt.rawCode,
|
|
5823
|
+
ruleId: "E2_SHARED_NON_DOMAIN",
|
|
5824
|
+
severity: "error",
|
|
5825
|
+
advice: `Global errors can only depend on shared domain elements (e.g., value objects). They cannot depend on shared ports or infrastructure.`,
|
|
5826
|
+
fixExample: {
|
|
5827
|
+
bad: stmt.rawCode,
|
|
5828
|
+
good: "// Depend only on pure domain types from shared modules."
|
|
5829
|
+
}
|
|
5830
|
+
});
|
|
5831
|
+
}
|
|
5832
|
+
}
|
|
5833
|
+
continue;
|
|
5834
|
+
}
|
|
5543
5835
|
if (moduleType === "shared") {
|
|
5544
5836
|
if (layer === "domain") {
|
|
5545
5837
|
const lines = content.split(/\r?\n/);
|
|
@@ -5566,7 +5858,7 @@ Code: ${v.code}`;
|
|
|
5566
5858
|
}
|
|
5567
5859
|
}
|
|
5568
5860
|
for (const stmt of statements) {
|
|
5569
|
-
const target = classifyTarget(stmt.specifier, file, projectRoot);
|
|
5861
|
+
const target = classifyTarget(stmt.specifier, file, projectRoot, featuresBase, sharedBase, errorsBase);
|
|
5570
5862
|
if (target.targetFeature) {
|
|
5571
5863
|
addViolation({
|
|
5572
5864
|
feature: moduleName,
|
|
@@ -5696,7 +5988,7 @@ Code: ${v.code}`;
|
|
|
5696
5988
|
}
|
|
5697
5989
|
}
|
|
5698
5990
|
for (const stmt of statements) {
|
|
5699
|
-
const target = classifyTarget(stmt.specifier, file, projectRoot);
|
|
5991
|
+
const target = classifyTarget(stmt.specifier, file, projectRoot, featuresBase, sharedBase, errorsBase);
|
|
5700
5992
|
if (target.targetFeature && target.targetFeature !== feat.name) {
|
|
5701
5993
|
const evidence = {
|
|
5702
5994
|
fromFeature: feat.name,
|
|
@@ -6562,6 +6854,6 @@ async function runCli(argv = process.argv) {
|
|
|
6562
6854
|
cli.parse(argv, { run: true });
|
|
6563
6855
|
}
|
|
6564
6856
|
|
|
6565
|
-
export { DEFAULT_REGISTRY_BASE, DependencyRuleError, EnvEditor, FeatureDependencyGraph, PromptCancelledError, computeDirectoryHash, concreteInfraTemplate, createCli, detectPackageManager, diProviderTemplate, discoverEnvironments, domainClassTemplate, domainInterfaceTemplate, domainValueObjectTemplate, ensureInterfacePrefix, expressIndexTemplate, fetchModuleManifest, fetchRegistryFile, fetchRegistryIndex, findClosestMatch, findInterfaceFile, findLocalRegistry, findProjectRoot, generateConcreteInfraCode, generateDomain, generateDomainEntityCode, generateFeature, generateHttpHandler, generateHttpHandlerCode, generateInfrastructure, generateInjectable, generateInjectableCode, generateInterface, generateInterfaceCode, generateShared, generateStubCode, generateUseCase, generateUseCaseCode, generateUseCaseTestCode, getAllFiles, getConfiguredFeaturesDir, getConfiguredSharedDir, getEffectiveMode, getMissingNpmPackages, getRegistryBase, getTemplatesDir, handleCancel, handleCreate, handleEnv, handleImport, handleInit, handleLint, hbs, httpHandlerTemplate, injectableInterfaceTemplate, injectableTemplate, installNpmPackages, interfaceTemplate, isValidIdentifier, levenshteinDistance, lintCodebase, listDomainEntities, listDomainInterfaces, listExistingFeatures, listExistingShared, listUseCases, loadInterfaceHierarchy, loadMasonConfig, loadTemplate, normalizeRegistryUrl, parseInterfaceMethodsAndImports, printBanner, printGeneratedFiles, promptProperties, removeInterfacePrefix, renderTemplate, renderTemplateFile, resolveEnvFilename, resolveFeaturesDir, resolveSharedDir, runCli, runEnvAdd, runEnvAudit, runEnvCommand, runEnvDelete, runEnvExamplesCommand, runEnvInit, runEnvInitExamples, runEnvMenu, runEnvUpdate, runSharedCommand, stubInfraTemplate, synthesizeCrudMethods, toCamelCase, toKebabCase, toPascalCase, toPlural, toSingular, toStubName, updateOrGenerateDiProvider, useCaseTemplate, useCaseTestTemplate, writeFileSafely };
|
|
6857
|
+
export { DEFAULT_REGISTRY_BASE, DependencyRuleError, EnvEditor, FeatureDependencyGraph, PromptCancelledError, computeDirectoryHash, concreteInfraTemplate, createCli, detectPackageManager, diProviderTemplate, discoverEnvironments, domainClassTemplate, domainInterfaceTemplate, domainValueObjectTemplate, ensureInterfacePrefix, expressIndexTemplate, fetchModuleManifest, fetchRegistryFile, fetchRegistryIndex, findClosestMatch, findInterfaceFile, findLocalRegistry, findProjectRoot, generateConcreteInfraCode, generateDomain, generateDomainEntityCode, generateFeature, generateHttpHandler, generateHttpHandlerCode, generateInfrastructure, generateInjectable, generateInjectableCode, generateInterface, generateInterfaceCode, generateShared, generateStubCode, generateUseCase, generateUseCaseCode, generateUseCaseTestCode, getAllFiles, getConfiguredFeaturesDir, getConfiguredSharedDir, getEffectiveMode, getMissingNpmPackages, getRegistryBase, getResolvedLintPaths, getTemplatesDir, handleCancel, handleCreate, handleEnv, handleImport, handleInit, handleLint, hbs, httpHandlerTemplate, injectableInterfaceTemplate, injectableTemplate, installNpmPackages, interfaceTemplate, isValidIdentifier, levenshteinDistance, lintCodebase, listDomainEntities, listDomainInterfaces, listExistingFeatures, listExistingShared, listUseCases, loadInterfaceHierarchy, loadLintConfig, loadMasonConfig, loadTemplate, normalizeRegistryUrl, parseInterfaceMethodsAndImports, printBanner, printGeneratedFiles, promptProperties, removeInterfacePrefix, renderTemplate, renderTemplateFile, resolveEnvFilename, resolveFeaturesDir, resolveSharedDir, runCli, runEnvAdd, runEnvAudit, runEnvCommand, runEnvDelete, runEnvExamplesCommand, runEnvInit, runEnvInitExamples, runEnvMenu, runEnvUpdate, runSharedCommand, stubInfraTemplate, synthesizeCrudMethods, toCamelCase, toKebabCase, toPascalCase, toPlural, toSingular, toStubName, updateOrGenerateDiProvider, useCaseTemplate, useCaseTestTemplate, writeFileSafely };
|
|
6566
6858
|
//# sourceMappingURL=index.js.map
|
|
6567
6859
|
//# sourceMappingURL=index.js.map
|