@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/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import fs4 from 'fs';
2
- import path2 from 'path';
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 = path2.relative(projectRoot, absolutePath).replace(/\\/g, "/");
80
- const existedBefore = fs4.existsSync(absolutePath);
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 = path2.dirname(absolutePath);
100
- if (!fs4.existsSync(dir)) {
101
- fs4.mkdirSync(dir, { recursive: true });
99
+ const dir = path26.dirname(absolutePath);
100
+ if (!fs17.existsSync(dir)) {
101
+ fs17.mkdirSync(dir, { recursive: true });
102
102
  }
103
- fs4.writeFileSync(absolutePath, content, "utf-8");
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 = path2.resolve(startDir);
130
+ let current = path26.resolve(startDir);
131
131
  while (true) {
132
- const configPath = path2.join(current, "mason.config.json");
133
- if (fs4.existsSync(configPath)) {
132
+ const configPath = path26.join(current, "mason.config.json");
133
+ if (fs17.existsSync(configPath)) {
134
134
  try {
135
- return JSON.parse(fs4.readFileSync(configPath, "utf-8"));
135
+ return JSON.parse(fs17.readFileSync(configPath, "utf-8"));
136
136
  } catch {
137
137
  return null;
138
138
  }
139
139
  }
140
- const parent = path2.dirname(current);
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 (fs4.existsSync(path2.join(projectRoot, "index.json")) && (fs4.existsSync(path2.join(projectRoot, "features")) || fs4.existsSync(path2.join(projectRoot, "shared")) || fs4.existsSync(path2.join(projectRoot, "src/features")) || fs4.existsSync(path2.join(projectRoot, "src/shared")))) {
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 path2.resolve(projectRoot, flags.target);
157
- if (flags?.dest) return path2.resolve(projectRoot, flags.dest);
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 path2.resolve(projectRoot, config.paths.features);
160
+ return path26.resolve(projectRoot, config.paths.features);
161
161
  }
162
162
  const mode = getEffectiveMode(projectRoot, flags);
163
163
  if (mode === "registry") {
164
- if (fs4.existsSync(path2.join(projectRoot, "src/features"))) {
165
- return path2.join(projectRoot, "src/features");
164
+ if (fs17.existsSync(path26.join(projectRoot, "src/features"))) {
165
+ return path26.join(projectRoot, "src/features");
166
166
  }
167
- return path2.join(projectRoot, "features");
167
+ return path26.join(projectRoot, "features");
168
168
  }
169
- if (fs4.existsSync(path2.join(projectRoot, "src/features"))) {
170
- return path2.join(projectRoot, "src/features");
169
+ if (fs17.existsSync(path26.join(projectRoot, "src/features"))) {
170
+ return path26.join(projectRoot, "src/features");
171
171
  }
172
- return path2.join(projectRoot, "features");
172
+ return path26.join(projectRoot, "features");
173
173
  }
174
174
  function getConfiguredSharedDir(projectRoot, flags) {
175
- if (flags?.target) return path2.resolve(projectRoot, flags.target);
176
- if (flags?.dest) return path2.resolve(projectRoot, flags.dest);
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 path2.resolve(projectRoot, config.paths.shared);
179
+ return path26.resolve(projectRoot, config.paths.shared);
180
180
  }
181
181
  const mode = getEffectiveMode(projectRoot, flags);
182
182
  if (mode === "registry") {
183
- if (fs4.existsSync(path2.join(projectRoot, "src/shared"))) {
184
- return path2.join(projectRoot, "src/shared");
183
+ if (fs17.existsSync(path26.join(projectRoot, "src/shared"))) {
184
+ return path26.join(projectRoot, "src/shared");
185
185
  }
186
- return path2.join(projectRoot, "shared");
186
+ return path26.join(projectRoot, "shared");
187
187
  }
188
- if (fs4.existsSync(path2.join(projectRoot, "src/shared"))) {
189
- return path2.join(projectRoot, "src/shared");
188
+ if (fs17.existsSync(path26.join(projectRoot, "src/shared"))) {
189
+ return path26.join(projectRoot, "src/shared");
190
190
  }
191
- return path2.join(projectRoot, "shared");
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 = path2.resolve(startDir);
227
+ let current = path26.resolve(startDir);
197
228
  while (true) {
198
- if (fs4.existsSync(path2.join(current, "package.json"))) {
229
+ if (fs17.existsSync(path26.join(current, "package.json"))) {
199
230
  return current;
200
231
  }
201
- const parent = path2.dirname(current);
232
+ const parent = path26.dirname(current);
202
233
  if (parent === current) {
203
- return path2.resolve(startDir);
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 (!fs4.existsSync(sharedDir)) return [];
247
+ if (!fs17.existsSync(sharedDir)) return [];
217
248
  try {
218
- const entries = fs4.readdirSync(sharedDir, { withFileTypes: true });
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 (!fs4.existsSync(featuresDir)) return [];
257
+ if (!fs17.existsSync(featuresDir)) return [];
227
258
  try {
228
- const entries = fs4.readdirSync(featuresDir, { withFileTypes: true });
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 = path2.join(resolveFeaturesDir(projectRoot), feat, "domain");
239
- if (!fs4.existsSync(domainDir)) continue;
269
+ const domainDir = path26.join(resolveFeaturesDir(projectRoot), feat, "domain");
270
+ if (!fs17.existsSync(domainDir)) continue;
240
271
  try {
241
- const files = fs4.readdirSync(domainDir);
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 = path2.join(domainDir, file);
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 = fs4.readFileSync(fullPath, "utf-8");
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 = path2.join(resolveFeaturesDir(projectRoot), feat, "domain");
277
- if (!fs4.existsSync(domainDir)) continue;
307
+ const domainDir = path26.join(resolveFeaturesDir(projectRoot), feat, "domain");
308
+ if (!fs17.existsSync(domainDir)) continue;
278
309
  try {
279
- const files = fs4.readdirSync(domainDir);
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: path2.join(domainDir, file),
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 = path2.join(resolveFeaturesDir(projectRoot), feat, "useCases");
302
- if (!fs4.existsSync(useCasesDir)) continue;
332
+ const useCasesDir = path26.join(resolveFeaturesDir(projectRoot), feat, "useCases");
333
+ if (!fs17.existsSync(useCasesDir)) continue;
303
334
  try {
304
- const files = fs4.readdirSync(useCasesDir);
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: path2.join(useCasesDir, file),
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 path2.resolve(baseDir, trimmed);
453
+ return path26.resolve(baseDir, trimmed);
423
454
  }
424
455
  return trimmed;
425
456
  }
426
457
  function findLocalRegistry(startDir = process.cwd()) {
427
- let current = path2.resolve(startDir);
458
+ let current = path26.resolve(startDir);
428
459
  while (true) {
429
- const candidate = path2.join(current, "mason-registry");
430
- if (fs4.existsSync(candidate) && fs4.existsSync(path2.join(candidate, "index.json"))) {
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 = path2.dirname(current);
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 ? path2.resolve(projectRoot) : process.cwd();
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
- path2.join(rootDir, "mason.config.json"),
449
- path2.join(process.cwd(), "mason.config.json")
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 (fs4.existsSync(configPath)) {
483
+ if (fs17.existsSync(configPath)) {
453
484
  try {
454
- const config = JSON.parse(fs4.readFileSync(configPath, "utf-8"));
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(), path2.dirname(configPath));
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
- path2.join(rootDir, "package.json"),
464
- path2.join(process.cwd(), "package.json")
494
+ path26.join(rootDir, "package.json"),
495
+ path26.join(process.cwd(), "package.json")
465
496
  ];
466
497
  for (const pkgPath of pkgLocations) {
467
- if (fs4.existsSync(pkgPath)) {
498
+ if (fs17.existsSync(pkgPath)) {
468
499
  try {
469
- const pkg = JSON.parse(fs4.readFileSync(pkgPath, "utf-8"));
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(), path2.dirname(pkgPath));
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 = path2.resolve(baseDir, cleanRelPath);
520
- if (!fs4.existsSync(filePath)) {
521
- const inSrcPath = path2.resolve(baseDir, "src", cleanRelPath);
522
- if (fs4.existsSync(inSrcPath)) {
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 fs4.promises.readFile(filePath, "utf-8");
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 (fs4.existsSync(path2.join(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
591
- if (fs4.existsSync(path2.join(projectRoot, "yarn.lock"))) return "yarn";
592
- if (fs4.existsSync(path2.join(projectRoot, "bun.lockb")) || fs4.existsSync(path2.join(projectRoot, "bun.lock"))) return "bun";
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 = path2.join(projectRoot, "package.json");
598
- if (!fs4.existsSync(pkgJsonPath)) {
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(fs4.readFileSync(pkgJsonPath, "utf-8"));
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 (!fs4.existsSync(dir)) return [];
642
- const entries = fs4.readdirSync(dir, { withFileTypes: true });
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 = path2.join(dir, entry.name);
646
- const relPath = path2.relative(baseDir, fullPath).replace(/\\/g, "/");
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 (!fs4.existsSync(dirPath)) return "";
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 = path2.join(dirPath, relativePath);
667
- if (!fs4.existsSync(absolutePath)) continue;
668
- const content = fs4.readFileSync(absolutePath, "utf8");
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 && fs4.existsSync(cachedTemplatesDir)) {
722
+ if (cachedTemplatesDir && fs17.existsSync(cachedTemplatesDir)) {
692
723
  return cachedTemplatesDir;
693
724
  }
694
- const currentDir = typeof __dirname !== "undefined" ? __dirname : path2.dirname(fileURLToPath(import.meta.url));
695
- const cand1 = path2.resolve(currentDir, "../../templates");
696
- if (fs4.existsSync(cand1)) {
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 = path2.resolve(currentDir, "../templates");
701
- if (fs4.existsSync(cand2)) {
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 = path2.resolve(currentDir, "templates");
706
- if (fs4.existsSync(cand3)) {
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 = path2.join(curr, "templates");
713
- if (fs4.existsSync(candTemplates)) {
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 = path2.dirname(curr);
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 = path2.isAbsolute(relativePath) ? relativePath : path2.join(getTemplatesDir(), relativePath);
726
- return fs4.readFileSync(fullPath, "utf-8");
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 || path2.join(resolveFeaturesDir(projectRoot), options.feature, "domain");
812
- const filePath = path2.join(targetDir, `${entityName}.ts`);
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 || path2.join(resolveFeaturesDir(projectRoot), options.feature, "domain");
862
- const filePath = path2.join(targetDir, `${ifaceName}.ts`);
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 && fs4.existsSync(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 = path2.join(resolveFeaturesDir(projectRoot), feat, "domain");
1108
- if (!fs4.existsSync(domainDir)) continue;
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 = path2.join(domainDir, `${cand}.ts`);
1111
- if (fs4.existsSync(p1)) {
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 = path2.join(projectRoot, "domain", `${cand}.ts`);
1118
- if (fs4.existsSync(p1)) return { filePath: p1, ifaceName: cand };
1119
- const p22 = path2.join(projectRoot, "src", "domain", `${cand}.ts`);
1120
- if (fs4.existsSync(p22)) return { filePath: p22, ifaceName: cand };
1121
- const p32 = path2.join(projectRoot, "interfaces", `${cand}.ts`);
1122
- if (fs4.existsSync(p32)) return { filePath: p32, ifaceName: cand };
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 = fs4.readFileSync(currentFile, "utf-8");
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 ? `${path2.dirname(ifaceImportPath)}/${baseEntity}.js` : `../domain/${baseEntity}.js`;
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 ? `${path2.dirname(ifaceImportPath)}/${baseEntity}.js` : `../domain/${baseEntity}.js`;
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 ? path2.join(resolveFeaturesDir(projectRoot), options.feature, "infrastructure") : path2.join(projectRoot, "infrastructure"));
1316
- const filePath = path2.join(targetDir, `${className}.ts`);
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 = path2.relative(targetDir, ifaceFilePath).replace(/\\/g, "/").replace(/\.ts$/, ".js");
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 = path2.resolve(path2.dirname(ifaceFilePath), imp.specifier);
1344
- let rel = path2.relative(targetDir, absTarget).replace(/\\/g, "/");
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 || path2.join(resolveFeaturesDir(projectRoot), options.feature, "useCases");
1532
- const filePath = path2.join(targetDir, `${ucName}.ts`);
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 = path2.join(targetDir, `${ucName}.test.ts`);
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 = path2.join(resolveFeaturesDir(projectRoot), options.feature, "pxExpress");
1617
- const handlersDir = path2.join(pxDir, "handlers");
1618
- const pxIndexPath = path2.join(pxDir, "index.ts");
1619
- if (!fs4.existsSync(pxIndexPath)) {
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 = path2.join(handlersDir, `${className}.ts`);
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 = path2.join(featureDir, "diProvider.ts");
1684
+ const providerPath = path26.join(featureDir, "diProvider.ts");
1654
1685
  const pascalFeature = toPascalCase(featureName);
1655
1686
  const providerModuleName = `${pascalFeature}Provider`;
1656
- if (fs4.existsSync(providerPath) && !options.overwrite) {
1657
- let content = fs4.readFileSync(providerPath, "utf-8");
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 || path2.join(resolveFeaturesDir(projectRoot), featureName);
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: path2.join(targetDir, "domain"),
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: path2.join(targetDir, "domain"),
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: path2.join(targetDir, "infrastructure"),
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: path2.join(targetDir, "useCases"),
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: path2.join(targetDir, "useCases"),
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: path2.join(targetDir, "useCases"),
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: path2.join(targetDir, "useCases"),
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: path2.join(targetDir, "useCases"),
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: path2.join(targetDir, "useCases"),
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: path2.join(targetDir, "useCases"),
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 = path2.join(targetDir, "pxExpress");
2074
- const pxIndexPath = path2.join(pxDir, "index.ts");
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 = path2.relative(projectRoot, path2.join(baseFeaturesDir, normalizedName));
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 ? path2.resolve(projectRoot, flags.dest) : flags.target ? path2.resolve(projectRoot, flags.target) : path2.resolve(projectRoot, targetDirRel);
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 = path2.join(targetDir, "registry.json");
2373
- if (!fs4.existsSync(registryPath)) {
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 ${path2.relative(projectRoot, targetDir)} (uncommitted, unregistered)`
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 || path2.join(resolveSharedDir(projectRoot), kebabName);
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: path2.join(targetDir, `${pascalName}.ts`),
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: path2.join(targetDir, "ports", `I${pascalName}Engine.ts`),
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: path2.join(targetDir, "infrastructure", `Default${pascalName}Engine.ts`),
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: path2.join(targetDir, "infrastructure", `Stub${pascalName}Engine.ts`),
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: path2.join(targetDir, "diProvider.ts"),
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: path2.join(targetDir, "registry.json"),
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 = path2.relative(projectRoot, path2.join(baseSharedDir, normalizedName));
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 ? path2.resolve(projectRoot, flags.dest) : flags.target ? path2.resolve(projectRoot, flags.target) : path2.resolve(projectRoot, targetDirRel);
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 ${path2.relative(projectRoot, targetDir)} (uncommitted, unregistered)`
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 = path2.join(resolveFeaturesDir(projectRoot), feature);
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 = path2.join(resolveFeaturesDir(projectRoot), feature);
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 = path2.isAbsolute(options.customPath) ? options.customPath : path2.join(projectRoot, options.customPath);
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 = path2.join(resolveFeaturesDir(projectRoot), options.feature, "services");
3379
+ targetDir = path26.join(resolveFeaturesDir(projectRoot), options.feature, "services");
3349
3380
  } else if (options.location === "feature-transformer" && options.feature) {
3350
- targetDir = path2.join(resolveFeaturesDir(projectRoot), options.feature, "pxExpress", "transformers");
3381
+ targetDir = path26.join(resolveFeaturesDir(projectRoot), options.feature, "pxExpress", "transformers");
3351
3382
  } else if (options.location === "module") {
3352
- targetDir = path2.join(projectRoot, "modules", className);
3383
+ targetDir = path26.join(projectRoot, "modules", className);
3353
3384
  } else {
3354
- targetDir = options.feature ? path2.join(resolveFeaturesDir(projectRoot), options.feature, "services") : path2.join(projectRoot, "shared", className.toLowerCase());
3385
+ targetDir = options.feature ? path26.join(resolveFeaturesDir(projectRoot), options.feature, "services") : path26.join(projectRoot, "shared", className.toLowerCase());
3355
3386
  }
3356
- const filePath = path2.join(targetDir, `${className}.ts`);
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 = path2.join(targetDir, `${ifaceName}.ts`);
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 = fs4.readdirSync(projectRoot);
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 = path2.join(projectRoot, exampleFile);
3530
+ const sourcePath = path26.join(projectRoot, exampleFile);
3500
3531
  const targetFile = exampleFile.replace(/\.example$/, "");
3501
- const targetPath = path2.join(projectRoot, targetFile);
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 && fs4.existsSync(targetPath)) {
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 = fs4.readFileSync(sourcePath, "utf-8");
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 = fs4.existsSync(filePath) ? fs4.readFileSync(filePath, "utf-8").split(/\r?\n/) : [];
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 = path2.dirname(this.filePath);
3597
- if (!fs4.existsSync(dir)) {
3598
- fs4.mkdirSync(dir, { recursive: true });
3627
+ const dir = path26.dirname(this.filePath);
3628
+ if (!fs17.existsSync(dir)) {
3629
+ fs17.mkdirSync(dir, { recursive: true });
3599
3630
  }
3600
- fs4.writeFileSync(this.filePath, this.lines.join("\n"), "utf-8");
3631
+ fs17.writeFileSync(this.filePath, this.lines.join("\n"), "utf-8");
3601
3632
  }
3602
3633
  };
3603
3634
  function discoverEnvironments(projectRoot) {
3604
- if (!fs4.existsSync(projectRoot)) {
3635
+ if (!fs17.existsSync(projectRoot)) {
3605
3636
  return ["local", "dev", "prod"];
3606
3637
  }
3607
- const files = fs4.readdirSync(projectRoot);
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 = fs4.readdirSync(projectRoot, { withFileTypes: true });
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 = path2.join(projectRoot, envFile);
3673
+ const sourcePath = path26.join(projectRoot, envFile);
3643
3674
  const targetFile = `${envFile}.example`;
3644
- const targetPath = path2.join(projectRoot, targetFile);
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 && fs4.existsSync(targetPath)) {
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 = path2.join(projectRoot, resolveEnvFilename(env, false));
3681
- const examplePath = path2.join(projectRoot, resolveEnvFilename(env, true));
3682
- if (fs4.existsSync(localPath)) {
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 (fs4.existsSync(examplePath)) {
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 = path2.join(projectRoot, resolveEnvFilename(env, false));
3758
- const examplePath = path2.join(projectRoot, resolveEnvFilename(env, true));
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 = path2.join(projectRoot, resolveEnvFilename(env, false));
3806
- return fs4.existsSync(localPath) && new EnvEditor(localPath).has(targetKey);
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 = path2.join(projectRoot, resolveEnvFilename(env, false));
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 = path2.join(projectRoot, resolveEnvFilename(env, true));
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 = path2.join(projectRoot, resolveEnvFilename(env, false));
3899
- const examplePath = path2.join(projectRoot, resolveEnvFilename(env, true));
3900
- return fs4.existsSync(localPath) && new EnvEditor(localPath).has(targetKey) || fs4.existsSync(examplePath) && new EnvEditor(examplePath).has(targetKey);
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 = path2.join(projectRoot, resolveEnvFilename(env, false));
3939
- const examplePath = path2.join(projectRoot, resolveEnvFilename(env, true));
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 (fs4.existsSync(localPath)) {
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 (fs4.existsSync(examplePath)) {
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 = path2.join(projectRoot, localFile);
3976
- const examplePath = path2.join(projectRoot, exampleFile);
3977
- const localExists = fs4.existsSync(localPath);
3978
- const exampleExists = fs4.existsSync(examplePath);
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 path2.join(projectRoot, "src", folder);
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 = path2.join(configuredDir, modName);
4323
- if (fs4.existsSync(inConfigured)) return inConfigured;
4324
- const inSrc = path2.join(projectRoot, "src", folder, modName);
4325
- if (fs4.existsSync(inSrc)) return inSrc;
4326
- const inRoot = path2.join(projectRoot, folder, modName);
4327
- if (fs4.existsSync(inRoot)) return inRoot;
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
- path2.join(projectRoot, "src", folder),
4339
- path2.join(projectRoot, folder)
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 (fs4.existsSync(dir)) {
4374
+ if (fs17.existsSync(dir)) {
4344
4375
  try {
4345
- const entries = fs4.readdirSync(dir, { withFileTypes: true });
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 = path2.relative(projectRoot, path2.join(baseDir, programmaticAlias));
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 = path2.relative(projectRoot, path2.join(baseDir, newName));
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 = path2.join(getModuleBaseDir(projectRoot, res.type), res.targetName);
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
- fs4.rmSync(existingDir, { recursive: true, force: true });
4828
+ fs17.rmSync(existingDir, { recursive: true, force: true });
4798
4829
  }
4799
- if (fs4.existsSync(targetDir)) {
4800
- fs4.rmSync(targetDir, { recursive: true, force: true });
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 = path2.join(targetDir, file);
4808
- if (fs4.existsSync(localFilePath) && !isOverwrite) {
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(path2.relative(projectRoot, localFilePath))} (use --overwrite to replace)`
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
- fs4.mkdirSync(path2.dirname(localFilePath), { recursive: true });
4818
- fs4.writeFileSync(localFilePath, content, "utf-8");
4848
+ fs17.mkdirSync(path26.dirname(localFilePath), { recursive: true });
4849
+ fs17.writeFileSync(localFilePath, content, "utf-8");
4819
4850
  }
4820
- const displayPath = path2.relative(projectRoot, localFilePath);
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 = path2.relative(projectRoot, path2.join(baseDir, rootRes.targetName));
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 ? path2.relative(projectRoot, filePath) : filePath).replace(/\\/g, "/");
4866
- const base = path2.basename(norm);
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 (!fs4.existsSync(dir)) return [];
4871
- const entries = fs4.readdirSync(dir, { withFileTypes: true });
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 = path2.join(dir, entry.name);
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(fullPath, projectRoot) {
4887
- const rel = path2.relative(projectRoot, fullPath).replace(/\\/g, "/");
4888
- const featureMatch = rel.match(/(?:^|\/)(?:src\/)?features\/([^/]+)\/([^/]+)(?:\/.*)?$/);
4889
- if (featureMatch && featureMatch[1] && featureMatch[2]) {
4890
- const feature = featureMatch[1];
4891
- const subfolder = featureMatch[2];
4892
- let layer;
4893
- if (subfolder === "domain" || subfolder === "errors") {
4894
- layer = "domain";
4895
- } else if (subfolder === "useCases" || subfolder === "usecases") {
4896
- layer = "useCases";
4897
- } else if (subfolder === "services") {
4898
- layer = "services";
4899
- } else if (subfolder === "infrastructure") {
4900
- layer = "infrastructure";
4901
- } else if (subfolder === "pxExpress" || subfolder === "presentation" || subfolder === "handlers" || subfolder.startsWith("px")) {
4902
- layer = "presentation";
4903
- }
4904
- return { moduleType: "feature", moduleName: feature, feature, layer };
4905
- }
4906
- const sharedMatch = rel.match(/(?:^|\/)(?:src\/)?shared\/([^/]+)(?:\/(.*))?$/);
4907
- if (sharedMatch && sharedMatch[1]) {
4908
- const moduleName = sharedMatch[1];
4909
- const rest = sharedMatch[2] || "";
4910
- let layer = "root";
4911
- if (rest.startsWith("domain/") || rest === "domain" || rest.startsWith("errors/") || rest === "errors") {
4912
- layer = "domain";
4913
- } else if (rest.startsWith("ports/") || rest === "ports") {
4914
- layer = "ports";
4915
- } else if (rest.startsWith("infrastructure/") || rest === "infrastructure") {
4916
- layer = "infrastructure";
4917
- }
4918
- return { moduleType: "shared", moduleName, feature: moduleName, layer };
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:") || ["crypto", "fs", "path", "http", "https", "url", "os", "child_process", "stream", "express", "cors", "dotenv"].includes(specifier)) {
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
- let resolvedRel = null;
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
- const abs = path2.resolve(path2.dirname(sourceFileAbs), specifier);
4932
- resolvedRel = path2.relative(projectRoot, abs).replace(/\\/g, "/");
4933
- } else if (specifier.startsWith("@/features/") || specifier.startsWith("~/features/")) {
4934
- resolvedRel = specifier.replace(/^[@~]\//, "src/");
4935
- } else if (specifier.startsWith("@features/")) {
4936
- resolvedRel = "src/" + specifier.slice(1);
4937
- } else if (specifier.startsWith("@/shared/") || specifier.startsWith("~/shared/")) {
4938
- resolvedRel = specifier.replace(/^[@~]\//, "src/");
4939
- } else if (specifier.startsWith("@shared/")) {
4940
- resolvedRel = "src/" + specifier.slice(1);
4941
- } else if (specifier.startsWith("@/configs/") || specifier.startsWith("~/configs/") || specifier === "@/configs" || specifier === "~/configs") {
4942
- resolvedRel = specifier.replace(/^[@~]\//, "src/");
4943
- } else if (specifier === "@configs" || specifier.startsWith("@configs/")) {
4944
- resolvedRel = "src/" + specifier.slice(1);
4945
- } else if (specifier.startsWith("@/") || specifier.startsWith("~/")) {
4946
- resolvedRel = "src/" + specifier.slice(2);
4947
- } else if (specifier.startsWith("features/") || specifier.startsWith("shared/") || specifier.startsWith("configs/") || specifier === "configs") {
4948
- resolvedRel = specifier;
4949
- }
4950
- if (!resolvedRel) {
4951
- return { isExternal: true, isDiFramework: false };
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
- const isGlobalConfig = resolvedRel.startsWith("src/configs/") || resolvedRel === "src/configs" || resolvedRel.startsWith("configs/") || resolvedRel === "configs";
4954
- const featMatch = resolvedRel.match(/(?:^|\/)(?:src\/)?features\/([^/]+)\/([^/]+)(?:\/(.*))?$/);
4955
- if (featMatch && featMatch[1] && featMatch[2]) {
4956
- const targetFeature = featMatch[1];
4957
- const targetSubfolder = featMatch[2];
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" || rest.startsWith("errors/") || rest.includes("/errors/") || targetFileName.endsWith("Error") || targetFileName.endsWith("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
- const sharedMatch = resolvedRel.match(/(?:^|\/)(?:src\/)?shared\/([^/]+)(?:\/(.*))?$/);
4989
- if (sharedMatch) {
4990
- const targetSharedModule = sharedMatch[1];
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(projectRoot) {
5129
- const featuresBase = resolveFeaturesDir(projectRoot);
5130
- if (!fs4.existsSync(featuresBase)) return [];
5131
- const entries = fs4.readdirSync(featuresBase, { withFileTypes: true });
5132
- return entries.filter((e) => e.isDirectory() && !e.name.startsWith(".") && e.name !== "__tests__" && e.name !== "tests").map((e) => ({
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: path2.join(featuresBase, e.name)
5268
+ dir: path26.join(base, e.name)
5135
5269
  })).sort((a, b) => a.name.localeCompare(b.name));
5136
5270
  }
5137
- function discoverAllShared(projectRoot) {
5138
- const sharedBase = resolveSharedDir(projectRoot);
5139
- if (!fs4.existsSync(sharedBase)) return [];
5140
- const entries = fs4.readdirSync(sharedBase, { withFileTypes: true });
5141
- return entries.filter((e) => e.isDirectory() && !e.name.startsWith(".") && e.name !== "__tests__" && e.name !== "tests").map((e) => ({
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: path2.join(sharedBase, e.name)
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 = path2.basename(filePath);
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 = path2.basename(filePath);
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 features = discoverAllFeatures(projectRoot);
5495
- const sharedModules = discoverAllShared(projectRoot);
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 = path2.relative(projectRoot, file).replace(/\\/g, "/");
5537
- const { moduleType, moduleName, layer } = classifyFile(file, projectRoot);
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 = fs4.readFileSync(file, "utf-8");
5716
+ const content = fs17.readFileSync(file, "utf-8");
5540
5717
  const statements = extractImportStatements(content);
5541
- const baseName = path2.basename(file);
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