@solid-stack/mason 1.0.33 → 1.0.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js CHANGED
@@ -2,8 +2,8 @@
2
2
  import { cac } from 'cac';
3
3
  import * as p19 from '@clack/prompts';
4
4
  import pc13 from 'picocolors';
5
- import fs14 from 'fs';
6
- import path2 from 'path';
5
+ import fs17 from 'fs';
6
+ import path26 from 'path';
7
7
  import { fileURLToPath } from 'url';
8
8
  import Handlebars from 'handlebars';
9
9
  import { execSync } from 'child_process';
@@ -11,8 +11,8 @@ import { createHash } from 'crypto';
11
11
 
12
12
  function writeFileSafely(absolutePath, content, options = {}) {
13
13
  const projectRoot = options.projectRoot || process.cwd();
14
- const relPath = path2.relative(projectRoot, absolutePath).replace(/\\/g, "/");
15
- const existedBefore = fs14.existsSync(absolutePath);
14
+ const relPath = path26.relative(projectRoot, absolutePath).replace(/\\/g, "/");
15
+ const existedBefore = fs17.existsSync(absolutePath);
16
16
  if (options.dryRun) {
17
17
  return {
18
18
  relativePath: relPath,
@@ -31,11 +31,11 @@ function writeFileSafely(absolutePath, content, options = {}) {
31
31
  existedBefore: true
32
32
  };
33
33
  }
34
- const dir = path2.dirname(absolutePath);
35
- if (!fs14.existsSync(dir)) {
36
- fs14.mkdirSync(dir, { recursive: true });
34
+ const dir = path26.dirname(absolutePath);
35
+ if (!fs17.existsSync(dir)) {
36
+ fs17.mkdirSync(dir, { recursive: true });
37
37
  }
38
- fs14.writeFileSync(absolutePath, content, "utf-8");
38
+ fs17.writeFileSync(absolutePath, content, "utf-8");
39
39
  return {
40
40
  relativePath: relPath,
41
41
  absolutePath,
@@ -126,17 +126,17 @@ function toStubName(ifaceName) {
126
126
  return `Stub${base}`;
127
127
  }
128
128
  function loadMasonConfig(startDir = process.cwd()) {
129
- let current = path2.resolve(startDir);
129
+ let current = path26.resolve(startDir);
130
130
  while (true) {
131
- const configPath = path2.join(current, "mason.config.json");
132
- if (fs14.existsSync(configPath)) {
131
+ const configPath = path26.join(current, "mason.config.json");
132
+ if (fs17.existsSync(configPath)) {
133
133
  try {
134
- return JSON.parse(fs14.readFileSync(configPath, "utf-8"));
134
+ return JSON.parse(fs17.readFileSync(configPath, "utf-8"));
135
135
  } catch {
136
136
  return null;
137
137
  }
138
138
  }
139
- const parent = path2.dirname(current);
139
+ const parent = path26.dirname(current);
140
140
  if (parent === current) break;
141
141
  current = parent;
142
142
  }
@@ -146,70 +146,60 @@ function getEffectiveMode(projectRoot, flags) {
146
146
  if (flags?.registry) return "registry";
147
147
  const config = loadMasonConfig(projectRoot);
148
148
  if (config?.mode) return config.mode;
149
- if (fs14.existsSync(path2.join(projectRoot, "index.json")) && (fs14.existsSync(path2.join(projectRoot, "features")) || fs14.existsSync(path2.join(projectRoot, "shared")) || fs14.existsSync(path2.join(projectRoot, "src/features")) || fs14.existsSync(path2.join(projectRoot, "src/shared")))) {
149
+ 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")))) {
150
150
  return "registry";
151
151
  }
152
152
  return "app";
153
153
  }
154
154
  function getConfiguredFeaturesDir(projectRoot, flags) {
155
- if (flags?.target) return path2.resolve(projectRoot, flags.target);
156
- if (flags?.dest) return path2.resolve(projectRoot, flags.dest);
155
+ if (flags?.target) return path26.resolve(projectRoot, flags.target);
156
+ if (flags?.dest) return path26.resolve(projectRoot, flags.dest);
157
157
  const config = loadMasonConfig(projectRoot);
158
158
  if (config?.paths?.features) {
159
- return path2.resolve(projectRoot, config.paths.features);
159
+ return path26.resolve(projectRoot, config.paths.features);
160
160
  }
161
161
  const mode = getEffectiveMode(projectRoot, flags);
162
162
  if (mode === "registry") {
163
- if (fs14.existsSync(path2.join(projectRoot, "src/features"))) {
164
- return path2.join(projectRoot, "src/features");
163
+ if (fs17.existsSync(path26.join(projectRoot, "src/features"))) {
164
+ return path26.join(projectRoot, "src/features");
165
165
  }
166
- return path2.join(projectRoot, "features");
166
+ return path26.join(projectRoot, "features");
167
167
  }
168
- if (fs14.existsSync(path2.join(projectRoot, "src/features"))) {
169
- return path2.join(projectRoot, "src/features");
168
+ if (fs17.existsSync(path26.join(projectRoot, "src/features"))) {
169
+ return path26.join(projectRoot, "src/features");
170
170
  }
171
- return path2.join(projectRoot, "features");
171
+ return path26.join(projectRoot, "features");
172
172
  }
173
173
  function getConfiguredSharedDir(projectRoot, flags) {
174
- if (flags?.target) return path2.resolve(projectRoot, flags.target);
175
- if (flags?.dest) return path2.resolve(projectRoot, flags.dest);
174
+ if (flags?.target) return path26.resolve(projectRoot, flags.target);
175
+ if (flags?.dest) return path26.resolve(projectRoot, flags.dest);
176
176
  const config = loadMasonConfig(projectRoot);
177
177
  if (config?.paths?.shared) {
178
- return path2.resolve(projectRoot, config.paths.shared);
178
+ return path26.resolve(projectRoot, config.paths.shared);
179
179
  }
180
180
  const mode = getEffectiveMode(projectRoot, flags);
181
181
  if (mode === "registry") {
182
- if (fs14.existsSync(path2.join(projectRoot, "src/shared"))) {
183
- return path2.join(projectRoot, "src/shared");
182
+ if (fs17.existsSync(path26.join(projectRoot, "src/shared"))) {
183
+ return path26.join(projectRoot, "src/shared");
184
184
  }
185
- return path2.join(projectRoot, "shared");
185
+ return path26.join(projectRoot, "shared");
186
186
  }
187
- if (fs14.existsSync(path2.join(projectRoot, "src/shared"))) {
188
- return path2.join(projectRoot, "src/shared");
187
+ if (fs17.existsSync(path26.join(projectRoot, "src/shared"))) {
188
+ return path26.join(projectRoot, "src/shared");
189
189
  }
190
- return path2.join(projectRoot, "shared");
191
- }
192
- function loadLintConfig(projectRoot) {
193
- const configPath = path2.join(projectRoot, "mason-lint.config.json");
194
- if (fs14.existsSync(configPath)) {
195
- try {
196
- return JSON.parse(fs14.readFileSync(configPath, "utf-8"));
197
- } catch {
198
- }
199
- }
200
- return { baseErrorPath: "src/errors/AppError.ts" };
190
+ return path26.join(projectRoot, "shared");
201
191
  }
202
192
 
203
193
  // src/utils/project.ts
204
194
  function findProjectRoot(startDir = process.cwd()) {
205
- let current = path2.resolve(startDir);
195
+ let current = path26.resolve(startDir);
206
196
  while (true) {
207
- if (fs14.existsSync(path2.join(current, "package.json"))) {
197
+ if (fs17.existsSync(path26.join(current, "package.json"))) {
208
198
  return current;
209
199
  }
210
- const parent = path2.dirname(current);
200
+ const parent = path26.dirname(current);
211
201
  if (parent === current) {
212
- return path2.resolve(startDir);
202
+ return path26.resolve(startDir);
213
203
  }
214
204
  current = parent;
215
205
  }
@@ -222,9 +212,9 @@ function resolveSharedDir(projectRoot, flags) {
222
212
  }
223
213
  function listExistingFeatures(projectRoot) {
224
214
  const featuresDir = resolveFeaturesDir(projectRoot);
225
- if (!fs14.existsSync(featuresDir)) return [];
215
+ if (!fs17.existsSync(featuresDir)) return [];
226
216
  try {
227
- const entries = fs14.readdirSync(featuresDir, { withFileTypes: true });
217
+ const entries = fs17.readdirSync(featuresDir, { withFileTypes: true });
228
218
  return entries.filter((e) => e.isDirectory()).map((e) => e.name).sort();
229
219
  } catch {
230
220
  return [];
@@ -234,14 +224,14 @@ function listDomainInterfaces(projectRoot, featureName) {
234
224
  const results = [];
235
225
  const features = featureName ? [featureName] : listExistingFeatures(projectRoot);
236
226
  for (const feat of features) {
237
- const domainDir = path2.join(resolveFeaturesDir(projectRoot), feat, "domain");
238
- if (!fs14.existsSync(domainDir)) continue;
227
+ const domainDir = path26.join(resolveFeaturesDir(projectRoot), feat, "domain");
228
+ if (!fs17.existsSync(domainDir)) continue;
239
229
  try {
240
- const files = fs14.readdirSync(domainDir);
230
+ const files = fs17.readdirSync(domainDir);
241
231
  for (const file of files) {
242
232
  if (file.endsWith(".ts") && !file.endsWith(".test.ts") && !file.endsWith(".d.ts")) {
243
233
  const name = file.replace(/\.ts$/, "");
244
- const fullPath = path2.join(domainDir, file);
234
+ const fullPath = path26.join(domainDir, file);
245
235
  if (/^I[A-Z]/.test(name)) {
246
236
  results.push({
247
237
  name,
@@ -250,7 +240,7 @@ function listDomainInterfaces(projectRoot, featureName) {
250
240
  });
251
241
  } else {
252
242
  try {
253
- const content = fs14.readFileSync(fullPath, "utf-8");
243
+ const content = fs17.readFileSync(fullPath, "utf-8");
254
244
  if (/export\s+(?:abstract\s+class|interface)\s+(\w+)/.test(content)) {
255
245
  results.push({
256
246
  name,
@@ -272,17 +262,17 @@ function listDomainEntities(projectRoot, featureName) {
272
262
  const results = [];
273
263
  const features = featureName ? [featureName] : listExistingFeatures(projectRoot);
274
264
  for (const feat of features) {
275
- const domainDir = path2.join(resolveFeaturesDir(projectRoot), feat, "domain");
276
- if (!fs14.existsSync(domainDir)) continue;
265
+ const domainDir = path26.join(resolveFeaturesDir(projectRoot), feat, "domain");
266
+ if (!fs17.existsSync(domainDir)) continue;
277
267
  try {
278
- const files = fs14.readdirSync(domainDir);
268
+ const files = fs17.readdirSync(domainDir);
279
269
  for (const file of files) {
280
270
  if (file.endsWith(".ts") && !file.endsWith(".test.ts") && !file.endsWith(".d.ts")) {
281
271
  const name = file.replace(/\.ts$/, "");
282
272
  if (!/^I[A-Z]/.test(name)) {
283
273
  results.push({
284
274
  name,
285
- fullPath: path2.join(domainDir, file),
275
+ fullPath: path26.join(domainDir, file),
286
276
  feature: feat
287
277
  });
288
278
  }
@@ -297,16 +287,16 @@ function listUseCases(projectRoot, featureName) {
297
287
  const results = [];
298
288
  const features = featureName ? [featureName] : listExistingFeatures(projectRoot);
299
289
  for (const feat of features) {
300
- const useCasesDir = path2.join(resolveFeaturesDir(projectRoot), feat, "useCases");
301
- if (!fs14.existsSync(useCasesDir)) continue;
290
+ const useCasesDir = path26.join(resolveFeaturesDir(projectRoot), feat, "useCases");
291
+ if (!fs17.existsSync(useCasesDir)) continue;
302
292
  try {
303
- const files = fs14.readdirSync(useCasesDir);
293
+ const files = fs17.readdirSync(useCasesDir);
304
294
  for (const file of files) {
305
295
  if (file.endsWith(".ts") && !file.endsWith(".test.ts") && !file.endsWith(".d.ts")) {
306
296
  const name = file.replace(/\.ts$/, "");
307
297
  results.push({
308
298
  name,
309
- fullPath: path2.join(useCasesDir, file),
299
+ fullPath: path26.join(useCasesDir, file),
310
300
  feature: feat
311
301
  });
312
302
  }
@@ -332,33 +322,33 @@ hbs.registerHelper("join", (arr, sep) => {
332
322
  });
333
323
  var cachedTemplatesDir = null;
334
324
  function getTemplatesDir() {
335
- if (cachedTemplatesDir && fs14.existsSync(cachedTemplatesDir)) {
325
+ if (cachedTemplatesDir && fs17.existsSync(cachedTemplatesDir)) {
336
326
  return cachedTemplatesDir;
337
327
  }
338
- const currentDir = typeof __dirname !== "undefined" ? __dirname : path2.dirname(fileURLToPath(import.meta.url));
339
- const cand1 = path2.resolve(currentDir, "../../templates");
340
- if (fs14.existsSync(cand1)) {
328
+ const currentDir = typeof __dirname !== "undefined" ? __dirname : path26.dirname(fileURLToPath(import.meta.url));
329
+ const cand1 = path26.resolve(currentDir, "../../templates");
330
+ if (fs17.existsSync(cand1)) {
341
331
  cachedTemplatesDir = cand1;
342
332
  return cand1;
343
333
  }
344
- const cand2 = path2.resolve(currentDir, "../templates");
345
- if (fs14.existsSync(cand2)) {
334
+ const cand2 = path26.resolve(currentDir, "../templates");
335
+ if (fs17.existsSync(cand2)) {
346
336
  cachedTemplatesDir = cand2;
347
337
  return cand2;
348
338
  }
349
- const cand3 = path2.resolve(currentDir, "templates");
350
- if (fs14.existsSync(cand3)) {
339
+ const cand3 = path26.resolve(currentDir, "templates");
340
+ if (fs17.existsSync(cand3)) {
351
341
  cachedTemplatesDir = cand3;
352
342
  return cand3;
353
343
  }
354
344
  let curr = currentDir;
355
345
  while (true) {
356
- const candTemplates = path2.join(curr, "templates");
357
- if (fs14.existsSync(candTemplates)) {
346
+ const candTemplates = path26.join(curr, "templates");
347
+ if (fs17.existsSync(candTemplates)) {
358
348
  cachedTemplatesDir = candTemplates;
359
349
  return candTemplates;
360
350
  }
361
- const parent = path2.dirname(curr);
351
+ const parent = path26.dirname(curr);
362
352
  if (parent === curr) break;
363
353
  curr = parent;
364
354
  }
@@ -366,8 +356,8 @@ function getTemplatesDir() {
366
356
  }
367
357
  var templateCache = /* @__PURE__ */ new Map();
368
358
  function loadTemplate(relativePath) {
369
- const fullPath = path2.isAbsolute(relativePath) ? relativePath : path2.join(getTemplatesDir(), relativePath);
370
- return fs14.readFileSync(fullPath, "utf-8");
359
+ const fullPath = path26.isAbsolute(relativePath) ? relativePath : path26.join(getTemplatesDir(), relativePath);
360
+ return fs17.readFileSync(fullPath, "utf-8");
371
361
  }
372
362
  function renderTemplateFile(relativePath, context) {
373
363
  let compiled = templateCache.get(relativePath);
@@ -454,8 +444,8 @@ function generateDomainEntityCode(name, kind = "interface", properties = []) {
454
444
  function generateDomain(options) {
455
445
  const projectRoot = options.projectRoot || findProjectRoot();
456
446
  const entityName = toPascalCase(options.name);
457
- const targetDir = options.targetDir || path2.join(resolveFeaturesDir(projectRoot), options.feature, "domain");
458
- const filePath = path2.join(targetDir, `${entityName}.ts`);
447
+ const targetDir = options.targetDir || path26.join(resolveFeaturesDir(projectRoot), options.feature, "domain");
448
+ const filePath = path26.join(targetDir, `${entityName}.ts`);
459
449
  const code = generateDomainEntityCode(
460
450
  entityName,
461
451
  options.kind || "interface",
@@ -504,8 +494,8 @@ function generateInterfaceCode(ifaceName, kind = "abstractClass", entityName, me
504
494
  function generateInterface(options) {
505
495
  const projectRoot = options.projectRoot || findProjectRoot();
506
496
  const ifaceName = ensureInterfacePrefix(options.name);
507
- const targetDir = options.targetDir || path2.join(resolveFeaturesDir(projectRoot), options.feature, "domain");
508
- const filePath = path2.join(targetDir, `${ifaceName}.ts`);
497
+ const targetDir = options.targetDir || path26.join(resolveFeaturesDir(projectRoot), options.feature, "domain");
498
+ const filePath = path26.join(targetDir, `${ifaceName}.ts`);
509
499
  const code = generateInterfaceCode(
510
500
  ifaceName,
511
501
  options.kind || "abstractClass",
@@ -740,7 +730,7 @@ function parseInterfaceMethodsAndImports(content, targetIfaceName) {
740
730
  };
741
731
  }
742
732
  function findInterfaceFile(projectRoot, ifaceName, featureName, customPath) {
743
- if (customPath && fs14.existsSync(customPath)) {
733
+ if (customPath && fs17.existsSync(customPath)) {
744
734
  return { filePath: customPath, ifaceName };
745
735
  }
746
736
  const candidateNames = [
@@ -750,22 +740,22 @@ function findInterfaceFile(projectRoot, ifaceName, featureName, customPath) {
750
740
  ];
751
741
  const features = featureName ? [featureName, ...listExistingFeatures(projectRoot).filter((f) => f !== featureName)] : listExistingFeatures(projectRoot);
752
742
  for (const feat of features) {
753
- const domainDir = path2.join(resolveFeaturesDir(projectRoot), feat, "domain");
754
- if (!fs14.existsSync(domainDir)) continue;
743
+ const domainDir = path26.join(resolveFeaturesDir(projectRoot), feat, "domain");
744
+ if (!fs17.existsSync(domainDir)) continue;
755
745
  for (const cand of candidateNames) {
756
- const p1 = path2.join(domainDir, `${cand}.ts`);
757
- if (fs14.existsSync(p1)) {
746
+ const p1 = path26.join(domainDir, `${cand}.ts`);
747
+ if (fs17.existsSync(p1)) {
758
748
  return { filePath: p1, ifaceName: cand, feature: feat };
759
749
  }
760
750
  }
761
751
  }
762
752
  for (const cand of candidateNames) {
763
- const p1 = path2.join(projectRoot, "domain", `${cand}.ts`);
764
- if (fs14.existsSync(p1)) return { filePath: p1, ifaceName: cand };
765
- const p22 = path2.join(projectRoot, "src", "domain", `${cand}.ts`);
766
- if (fs14.existsSync(p22)) return { filePath: p22, ifaceName: cand };
767
- const p32 = path2.join(projectRoot, "interfaces", `${cand}.ts`);
768
- if (fs14.existsSync(p32)) return { filePath: p32, ifaceName: cand };
753
+ const p1 = path26.join(projectRoot, "domain", `${cand}.ts`);
754
+ if (fs17.existsSync(p1)) return { filePath: p1, ifaceName: cand };
755
+ const p22 = path26.join(projectRoot, "src", "domain", `${cand}.ts`);
756
+ if (fs17.existsSync(p22)) return { filePath: p22, ifaceName: cand };
757
+ const p32 = path26.join(projectRoot, "interfaces", `${cand}.ts`);
758
+ if (fs17.existsSync(p32)) return { filePath: p32, ifaceName: cand };
769
759
  }
770
760
  return null;
771
761
  }
@@ -788,7 +778,7 @@ function loadInterfaceHierarchy(projectRoot, initialIfaceName, featureName, cust
788
778
  while (currentFile && !visited.has(currentFile)) {
789
779
  visited.add(currentFile);
790
780
  try {
791
- const content = fs14.readFileSync(currentFile, "utf-8");
781
+ const content = fs17.readFileSync(currentFile, "utf-8");
792
782
  const parsed = parseInterfaceMethodsAndImports(content, currentName);
793
783
  for (const m of parsed.methods) {
794
784
  if (!allMethods.some((existing) => existing.name === m.name)) {
@@ -864,7 +854,7 @@ function generateStubCode(stubClassName, ifaceName, entityName, featureName, met
864
854
  const entitiesVar = `${entityVar}s`;
865
855
  const idKey = `${entityVar}Id`;
866
856
  const impPath = ifaceImportPath || `../domain/${ifaceName}.js`;
867
- const entityImportPath = ifaceImportPath ? `${path2.dirname(ifaceImportPath)}/${baseEntity}.js` : `../domain/${baseEntity}.js`;
857
+ const entityImportPath = ifaceImportPath ? `${path26.dirname(ifaceImportPath)}/${baseEntity}.js` : `../domain/${baseEntity}.js`;
868
858
  const importsByFrom = /* @__PURE__ */ new Map();
869
859
  for (const imp of domainImports) {
870
860
  if (imp.name === ifaceName || imp.name === baseEntity) continue;
@@ -913,7 +903,7 @@ function generateConcreteInfraCode(className, ifaceName, dependencies = [], meth
913
903
  if (baseEntity) {
914
904
  finalMethods = synthesizeCrudMethods(baseEntity);
915
905
  if (!finalDomainImports.some((imp) => imp.name === baseEntity)) {
916
- const importPath = ifaceImportPath ? `${path2.dirname(ifaceImportPath)}/${baseEntity}.js` : `../domain/${baseEntity}.js`;
906
+ const importPath = ifaceImportPath ? `${path26.dirname(ifaceImportPath)}/${baseEntity}.js` : `../domain/${baseEntity}.js`;
917
907
  finalDomainImports.push({
918
908
  name: baseEntity,
919
909
  from: importPath,
@@ -958,8 +948,8 @@ function generateInfrastructure(options) {
958
948
  const projectRoot = options.projectRoot || findProjectRoot();
959
949
  const className = toPascalCase(options.name);
960
950
  const isFeatureScope = options.scope !== "global" && Boolean(options.feature);
961
- const targetDir = options.targetDir || (isFeatureScope ? path2.join(resolveFeaturesDir(projectRoot), options.feature, "infrastructure") : path2.join(projectRoot, "infrastructure"));
962
- const filePath = path2.join(targetDir, `${className}.ts`);
951
+ const targetDir = options.targetDir || (isFeatureScope ? path26.join(resolveFeaturesDir(projectRoot), options.feature, "infrastructure") : path26.join(projectRoot, "infrastructure"));
952
+ const filePath = path26.join(targetDir, `${className}.ts`);
963
953
  let code;
964
954
  if (options.implementsInterface) {
965
955
  const rawIfaceName = options.implementsInterface;
@@ -973,7 +963,7 @@ function generateInfrastructure(options) {
973
963
  const ifaceFilePath = hierarchy.ifaceFilePath;
974
964
  let ifaceImportPath;
975
965
  if (ifaceFilePath) {
976
- let rel = path2.relative(targetDir, ifaceFilePath).replace(/\\/g, "/").replace(/\.ts$/, ".js");
966
+ let rel = path26.relative(targetDir, ifaceFilePath).replace(/\\/g, "/").replace(/\.ts$/, ".js");
977
967
  if (!rel.startsWith(".")) rel = "./" + rel;
978
968
  ifaceImportPath = rel;
979
969
  } else if (isFeatureScope) {
@@ -986,8 +976,8 @@ function generateInfrastructure(options) {
986
976
  if (new RegExp(`\\b${item.name}\\b`).test(allSignatures)) {
987
977
  let fromPath;
988
978
  if (imp.specifier.startsWith(".") && ifaceFilePath) {
989
- const absTarget = path2.resolve(path2.dirname(ifaceFilePath), imp.specifier);
990
- let rel = path2.relative(targetDir, absTarget).replace(/\\/g, "/");
979
+ const absTarget = path26.resolve(path26.dirname(ifaceFilePath), imp.specifier);
980
+ let rel = path26.relative(targetDir, absTarget).replace(/\\/g, "/");
991
981
  if (!rel.startsWith(".")) rel = "./" + rel;
992
982
  fromPath = rel;
993
983
  } else {
@@ -1174,8 +1164,8 @@ function generateUseCase(options) {
1174
1164
  const files = [];
1175
1165
  const projectRoot = options.projectRoot || findProjectRoot();
1176
1166
  const ucName = toPascalCase(options.name);
1177
- const targetDir = options.targetDir || path2.join(resolveFeaturesDir(projectRoot), options.feature, "useCases");
1178
- const filePath = path2.join(targetDir, `${ucName}.ts`);
1167
+ const targetDir = options.targetDir || path26.join(resolveFeaturesDir(projectRoot), options.feature, "useCases");
1168
+ const filePath = path26.join(targetDir, `${ucName}.ts`);
1179
1169
  const code = generateUseCaseCode(
1180
1170
  ucName,
1181
1171
  options.dependencies || [],
@@ -1191,7 +1181,7 @@ function generateUseCase(options) {
1191
1181
  })
1192
1182
  );
1193
1183
  if (options.includeTest) {
1194
- const testPath = path2.join(targetDir, `${ucName}.test.ts`);
1184
+ const testPath = path26.join(targetDir, `${ucName}.test.ts`);
1195
1185
  const testCode = generateUseCaseTestCode(ucName, options.dependencies || []);
1196
1186
  files.push(
1197
1187
  writeFileSafely(testPath, testCode, {
@@ -1259,10 +1249,10 @@ function generateHttpHandler(options) {
1259
1249
  const files = [];
1260
1250
  const projectRoot = options.projectRoot || findProjectRoot();
1261
1251
  const className = toPascalCase(options.name);
1262
- const pxDir = path2.join(resolveFeaturesDir(projectRoot), options.feature, "pxExpress");
1263
- const handlersDir = path2.join(pxDir, "handlers");
1264
- const pxIndexPath = path2.join(pxDir, "index.ts");
1265
- if (!fs14.existsSync(pxIndexPath)) {
1252
+ const pxDir = path26.join(resolveFeaturesDir(projectRoot), options.feature, "pxExpress");
1253
+ const handlersDir = path26.join(pxDir, "handlers");
1254
+ const pxIndexPath = path26.join(pxDir, "index.ts");
1255
+ if (!fs17.existsSync(pxIndexPath)) {
1266
1256
  const featurePath = options.routePrefix || `/${options.feature.toLowerCase()}`;
1267
1257
  const pxIndexContent = renderTemplate(expressIndexTemplate, {
1268
1258
  routePath: featurePath
@@ -1275,7 +1265,7 @@ function generateHttpHandler(options) {
1275
1265
  })
1276
1266
  );
1277
1267
  }
1278
- const handlerFilePath = path2.join(handlersDir, `${className}.ts`);
1268
+ const handlerFilePath = path26.join(handlersDir, `${className}.ts`);
1279
1269
  const code = generateHttpHandlerCode(
1280
1270
  className,
1281
1271
  options.method || "get",
@@ -1296,11 +1286,11 @@ function generateHttpHandler(options) {
1296
1286
  return files;
1297
1287
  }
1298
1288
  function updateOrGenerateDiProvider(featureDir, featureName, bindings = [], options = {}) {
1299
- const providerPath = path2.join(featureDir, "diProvider.ts");
1289
+ const providerPath = path26.join(featureDir, "diProvider.ts");
1300
1290
  const pascalFeature = toPascalCase(featureName);
1301
1291
  const providerModuleName = `${pascalFeature}Provider`;
1302
- if (fs14.existsSync(providerPath) && !options.overwrite) {
1303
- let content = fs14.readFileSync(providerPath, "utf-8");
1292
+ if (fs17.existsSync(providerPath) && !options.overwrite) {
1293
+ let content = fs17.readFileSync(providerPath, "utf-8");
1304
1294
  content = content.replace(/\n*export\s+const\s+ScaffoldProvider\s*=[^;]+;?/g, "");
1305
1295
  for (const b of bindings) {
1306
1296
  const ifaceImp = b.ifaceImportPath || `./domain/${b.ifaceName}.js`;
@@ -1359,7 +1349,7 @@ function generateFeature(options) {
1359
1349
  const projectRoot = options.projectRoot || findProjectRoot();
1360
1350
  const rawName = options.name.trim();
1361
1351
  const featureName = toCamelCase(rawName);
1362
- const targetDir = options.targetDir || path2.join(resolveFeaturesDir(projectRoot), featureName);
1352
+ const targetDir = options.targetDir || path26.join(resolveFeaturesDir(projectRoot), featureName);
1363
1353
  const routePath = options.routePath || `/${featureName}`;
1364
1354
  const rawEntities = [];
1365
1355
  if (options.entityNames && options.entityNames.length > 0) {
@@ -1380,7 +1370,7 @@ function generateFeature(options) {
1380
1370
  const domainFile = generateDomain({
1381
1371
  name: ent,
1382
1372
  feature: featureName,
1383
- targetDir: path2.join(targetDir, "domain"),
1373
+ targetDir: path26.join(targetDir, "domain"),
1384
1374
  projectRoot,
1385
1375
  dryRun: options.dryRun,
1386
1376
  overwrite: options.overwrite,
@@ -1400,7 +1390,7 @@ function generateFeature(options) {
1400
1390
  const ifaceFile = generateInterface({
1401
1391
  name: ifaceName,
1402
1392
  feature: featureName,
1403
- targetDir: path2.join(targetDir, "domain"),
1393
+ targetDir: path26.join(targetDir, "domain"),
1404
1394
  entityName: ent,
1405
1395
  projectRoot,
1406
1396
  dryRun: options.dryRun,
@@ -1417,7 +1407,7 @@ function generateFeature(options) {
1417
1407
  const stubFile = generateInfrastructure({
1418
1408
  name: stubName,
1419
1409
  feature: featureName,
1420
- targetDir: path2.join(targetDir, "infrastructure"),
1410
+ targetDir: path26.join(targetDir, "infrastructure"),
1421
1411
  kind: "stub",
1422
1412
  implementsInterface: ifaceName,
1423
1413
  entityName: ent,
@@ -1459,7 +1449,7 @@ function generateFeature(options) {
1459
1449
  const ucFiles = generateUseCase({
1460
1450
  name: ucName,
1461
1451
  feature: featureName,
1462
- targetDir: path2.join(targetDir, "useCases"),
1452
+ targetDir: path26.join(targetDir, "useCases"),
1463
1453
  dependencies: options.includeInterface !== false ? [ifaceName] : [],
1464
1454
  inputProperties: [{ name: idParam, type: "string" }],
1465
1455
  outputProperties: [{ name: entVar, type: primaryEntity }],
@@ -1504,7 +1494,7 @@ function generateFeature(options) {
1504
1494
  const ucFiles = generateUseCase({
1505
1495
  name: ucName,
1506
1496
  feature: featureName,
1507
- targetDir: path2.join(targetDir, "useCases"),
1497
+ targetDir: path26.join(targetDir, "useCases"),
1508
1498
  dependencies: deps,
1509
1499
  inputProperties: [{ name: entVar, type: ent }],
1510
1500
  outputProperties: [{ name: entVar, type: ent }],
@@ -1537,7 +1527,7 @@ function generateFeature(options) {
1537
1527
  const ucFiles = generateUseCase({
1538
1528
  name: ucName,
1539
1529
  feature: featureName,
1540
- targetDir: path2.join(targetDir, "useCases"),
1530
+ targetDir: path26.join(targetDir, "useCases"),
1541
1531
  dependencies: deps,
1542
1532
  inputProperties: [{ name: idParam, type: "string" }],
1543
1533
  outputProperties: [{ name: entVar, type: ent }],
@@ -1570,7 +1560,7 @@ function generateFeature(options) {
1570
1560
  const ucFiles = generateUseCase({
1571
1561
  name: ucName,
1572
1562
  feature: featureName,
1573
- targetDir: path2.join(targetDir, "useCases"),
1563
+ targetDir: path26.join(targetDir, "useCases"),
1574
1564
  dependencies: deps,
1575
1565
  inputProperties: [
1576
1566
  { name: "page", type: "number", optional: true },
@@ -1614,7 +1604,7 @@ function generateFeature(options) {
1614
1604
  const ucFiles = generateUseCase({
1615
1605
  name: ucName,
1616
1606
  feature: featureName,
1617
- targetDir: path2.join(targetDir, "useCases"),
1607
+ targetDir: path26.join(targetDir, "useCases"),
1618
1608
  dependencies: deps,
1619
1609
  inputProperties: [{ name: entVar, type: ent }],
1620
1610
  outputProperties: [{ name: entVar, type: ent }],
@@ -1647,7 +1637,7 @@ function generateFeature(options) {
1647
1637
  const ucFiles = generateUseCase({
1648
1638
  name: ucName,
1649
1639
  feature: featureName,
1650
- targetDir: path2.join(targetDir, "useCases"),
1640
+ targetDir: path26.join(targetDir, "useCases"),
1651
1641
  dependencies: deps,
1652
1642
  inputProperties: [{ name: idParam, type: "string" }],
1653
1643
  outputProperties: [{ name: "success", type: "boolean" }],
@@ -1684,7 +1674,7 @@ function generateFeature(options) {
1684
1674
  const ucFiles = generateUseCase({
1685
1675
  name: ucName,
1686
1676
  feature: featureName,
1687
- targetDir: path2.join(targetDir, "useCases"),
1677
+ targetDir: path26.join(targetDir, "useCases"),
1688
1678
  dependencies: customUc.dependencies || [],
1689
1679
  inputProperties: customUc.inputProperties || [],
1690
1680
  outputProperties: customUc.outputProperties || [],
@@ -1716,8 +1706,8 @@ function generateFeature(options) {
1716
1706
  }
1717
1707
  }
1718
1708
  if (options.includeExpress !== false) {
1719
- const pxDir = path2.join(targetDir, "pxExpress");
1720
- const pxIndexPath = path2.join(pxDir, "index.ts");
1709
+ const pxDir = path26.join(targetDir, "pxExpress");
1710
+ const pxIndexPath = path26.join(pxDir, "index.ts");
1721
1711
  if (!files.some((f) => f.absolutePath === pxIndexPath)) {
1722
1712
  const pxIndexContent = renderTemplate(expressIndexTemplate, { routePath });
1723
1713
  files.push(
@@ -1847,7 +1837,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
1847
1837
  }
1848
1838
  const normalizedName = toCamelCase(name);
1849
1839
  const baseFeaturesDir = resolveFeaturesDir(projectRoot, flags);
1850
- const defaultDir = path2.relative(projectRoot, path2.join(baseFeaturesDir, normalizedName));
1840
+ const defaultDir = path26.relative(projectRoot, path26.join(baseFeaturesDir, normalizedName));
1851
1841
  let targetDirRel = defaultDir;
1852
1842
  if (!flags.yes && !flags.target && !flags.dest) {
1853
1843
  targetDirRel = handleCancel(
@@ -1858,7 +1848,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
1858
1848
  })
1859
1849
  ).trim();
1860
1850
  }
1861
- const targetDir = flags.dest ? path2.resolve(projectRoot, flags.dest) : flags.target ? path2.resolve(projectRoot, flags.target) : path2.resolve(projectRoot, targetDirRel);
1851
+ const targetDir = flags.dest ? path26.resolve(projectRoot, flags.dest) : flags.target ? path26.resolve(projectRoot, flags.target) : path26.resolve(projectRoot, targetDirRel);
1862
1852
  let includeExpress = flags.express !== void 0 ? Boolean(flags.express) : true;
1863
1853
  let routePath = `/${normalizedName}`;
1864
1854
  let includeDomain = true;
@@ -2100,8 +2090,8 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
2100
2090
  };
2101
2091
  const files = generateFeature(options);
2102
2092
  if (isRegistry) {
2103
- const registryPath = path2.join(targetDir, "registry.json");
2104
- if (!fs14.existsSync(registryPath)) {
2093
+ const registryPath = path26.join(targetDir, "registry.json");
2094
+ if (!fs17.existsSync(registryPath)) {
2105
2095
  const manifest = {
2106
2096
  name: toKebabCase(normalizedName),
2107
2097
  type: "feature",
@@ -2127,7 +2117,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
2127
2117
  printGeneratedFiles(files, options.dryRun);
2128
2118
  p19.outro(
2129
2119
  pc13.green(
2130
- `\u2713 Feature '${normalizedName}' initialized in ${path2.relative(projectRoot, targetDir)} (uncommitted, unregistered)`
2120
+ `\u2713 Feature '${normalizedName}' initialized in ${path26.relative(projectRoot, targetDir)} (uncommitted, unregistered)`
2131
2121
  )
2132
2122
  );
2133
2123
  }
@@ -2138,7 +2128,7 @@ function generateShared(options) {
2138
2128
  const pascalName = toPascalCase(rawName);
2139
2129
  const camelName = toCamelCase(rawName);
2140
2130
  const kebabName = toKebabCase(rawName);
2141
- const targetDir = options.targetDir || path2.join(resolveSharedDir(projectRoot), kebabName);
2131
+ const targetDir = options.targetDir || path26.join(resolveSharedDir(projectRoot), kebabName);
2142
2132
  const fileDefs = [];
2143
2133
  const facadeContent = `import { MakeInjectable, type DepsType } from "@solid-stack/di";
2144
2134
  import { I${pascalName}Engine } from "./ports/I${pascalName}Engine.js";
@@ -2150,7 +2140,7 @@ export class ${pascalName} {
2150
2140
  }
2151
2141
  `;
2152
2142
  fileDefs.push({
2153
- absolutePath: path2.join(targetDir, `${pascalName}.ts`),
2143
+ absolutePath: path26.join(targetDir, `${pascalName}.ts`),
2154
2144
  content: facadeContent
2155
2145
  });
2156
2146
  const portContent = `export abstract class I${pascalName}Engine {
@@ -2158,7 +2148,7 @@ export class ${pascalName} {
2158
2148
  }
2159
2149
  `;
2160
2150
  fileDefs.push({
2161
- absolutePath: path2.join(targetDir, "ports", `I${pascalName}Engine.ts`),
2151
+ absolutePath: path26.join(targetDir, "ports", `I${pascalName}Engine.ts`),
2162
2152
  content: portContent
2163
2153
  });
2164
2154
  const concreteContent = `import { MakeInjectable } from "@solid-stack/di";
@@ -2170,7 +2160,7 @@ export class Default${pascalName}Engine implements I${pascalName}Engine {
2170
2160
  }
2171
2161
  `;
2172
2162
  fileDefs.push({
2173
- absolutePath: path2.join(targetDir, "infrastructure", `Default${pascalName}Engine.ts`),
2163
+ absolutePath: path26.join(targetDir, "infrastructure", `Default${pascalName}Engine.ts`),
2174
2164
  content: concreteContent
2175
2165
  });
2176
2166
  if (options.includeStub !== false) {
@@ -2183,7 +2173,7 @@ export class Stub${pascalName}Engine implements I${pascalName}Engine {
2183
2173
  }
2184
2174
  `;
2185
2175
  fileDefs.push({
2186
- absolutePath: path2.join(targetDir, "infrastructure", `Stub${pascalName}Engine.ts`),
2176
+ absolutePath: path26.join(targetDir, "infrastructure", `Stub${pascalName}Engine.ts`),
2187
2177
  content: stubContent
2188
2178
  });
2189
2179
  }
@@ -2198,7 +2188,7 @@ export const diProvider = (c: Container): void => {
2198
2188
  export default diProvider;
2199
2189
  `;
2200
2190
  fileDefs.push({
2201
- absolutePath: path2.join(targetDir, "diProvider.ts"),
2191
+ absolutePath: path26.join(targetDir, "diProvider.ts"),
2202
2192
  content: providerContent
2203
2193
  });
2204
2194
  if (options.isRegistry) {
@@ -2215,7 +2205,7 @@ export default diProvider;
2215
2205
  files: []
2216
2206
  };
2217
2207
  fileDefs.push({
2218
- absolutePath: path2.join(targetDir, "registry.json"),
2208
+ absolutePath: path26.join(targetDir, "registry.json"),
2219
2209
  content: JSON.stringify(registryManifest, null, 2) + "\n"
2220
2210
  });
2221
2211
  }
@@ -2252,7 +2242,7 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
2252
2242
  }
2253
2243
  const normalizedName = toKebabCase(name);
2254
2244
  const baseSharedDir = resolveSharedDir(projectRoot, flags);
2255
- const defaultDir = path2.relative(projectRoot, path2.join(baseSharedDir, normalizedName));
2245
+ const defaultDir = path26.relative(projectRoot, path26.join(baseSharedDir, normalizedName));
2256
2246
  let targetDirRel = defaultDir;
2257
2247
  if (!flags.yes && !flags.target && !flags.dest) {
2258
2248
  targetDirRel = handleCancel(
@@ -2263,7 +2253,7 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
2263
2253
  })
2264
2254
  ).trim();
2265
2255
  }
2266
- const targetDir = flags.dest ? path2.resolve(projectRoot, flags.dest) : flags.target ? path2.resolve(projectRoot, flags.target) : path2.resolve(projectRoot, targetDirRel);
2256
+ const targetDir = flags.dest ? path26.resolve(projectRoot, flags.dest) : flags.target ? path26.resolve(projectRoot, flags.target) : path26.resolve(projectRoot, targetDirRel);
2267
2257
  let description = flags.description || "";
2268
2258
  let includeStub = true;
2269
2259
  if (!flags.yes) {
@@ -2297,7 +2287,7 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
2297
2287
  printGeneratedFiles(files, Boolean(flags.dryRun));
2298
2288
  p19.outro(
2299
2289
  pc13.green(
2300
- `\u2713 Shared module '${normalizedName}' initialized in ${path2.relative(projectRoot, targetDir)} (uncommitted, unregistered)`
2290
+ `\u2713 Shared module '${normalizedName}' initialized in ${path26.relative(projectRoot, targetDir)} (uncommitted, unregistered)`
2301
2291
  )
2302
2292
  );
2303
2293
  }
@@ -2724,7 +2714,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
2724
2714
  const infraFile = generateInfrastructure(options);
2725
2715
  files.push(infraFile);
2726
2716
  if (registerInProvider && scope === "feature" && feature && implementsInterface) {
2727
- const featureDir = path2.join(resolveFeaturesDir(projectRoot), feature);
2717
+ const featureDir = path26.join(resolveFeaturesDir(projectRoot), feature);
2728
2718
  const providerFile = updateOrGenerateDiProvider(
2729
2719
  featureDir,
2730
2720
  feature,
@@ -2886,7 +2876,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
2886
2876
  files.push(stubFile);
2887
2877
  }
2888
2878
  if (registerInProvider && generateStub) {
2889
- const featureDir = path2.join(resolveFeaturesDir(projectRoot), feature);
2879
+ const featureDir = path26.join(resolveFeaturesDir(projectRoot), feature);
2890
2880
  const providerFile = updateOrGenerateDiProvider(
2891
2881
  featureDir,
2892
2882
  feature,
@@ -3074,21 +3064,21 @@ function generateInjectable(options) {
3074
3064
  const className = toPascalCase(options.name);
3075
3065
  let targetDir = "";
3076
3066
  if (options.customPath) {
3077
- targetDir = path2.isAbsolute(options.customPath) ? options.customPath : path2.join(projectRoot, options.customPath);
3067
+ targetDir = path26.isAbsolute(options.customPath) ? options.customPath : path26.join(projectRoot, options.customPath);
3078
3068
  } else if (options.location === "feature-service" && options.feature) {
3079
- targetDir = path2.join(resolveFeaturesDir(projectRoot), options.feature, "services");
3069
+ targetDir = path26.join(resolveFeaturesDir(projectRoot), options.feature, "services");
3080
3070
  } else if (options.location === "feature-transformer" && options.feature) {
3081
- targetDir = path2.join(resolveFeaturesDir(projectRoot), options.feature, "pxExpress", "transformers");
3071
+ targetDir = path26.join(resolveFeaturesDir(projectRoot), options.feature, "pxExpress", "transformers");
3082
3072
  } else if (options.location === "module") {
3083
- targetDir = path2.join(projectRoot, "modules", className);
3073
+ targetDir = path26.join(projectRoot, "modules", className);
3084
3074
  } else {
3085
- targetDir = options.feature ? path2.join(resolveFeaturesDir(projectRoot), options.feature, "services") : path2.join(projectRoot, "shared", className.toLowerCase());
3075
+ targetDir = options.feature ? path26.join(resolveFeaturesDir(projectRoot), options.feature, "services") : path26.join(projectRoot, "shared", className.toLowerCase());
3086
3076
  }
3087
- const filePath = path2.join(targetDir, `${className}.ts`);
3077
+ const filePath = path26.join(targetDir, `${className}.ts`);
3088
3078
  let ifaceName;
3089
3079
  if (options.generateInterface) {
3090
3080
  ifaceName = `I${className}`;
3091
- const ifacePath = path2.join(targetDir, `${ifaceName}.ts`);
3081
+ const ifacePath = path26.join(targetDir, `${ifaceName}.ts`);
3092
3082
  const ifaceContent = renderTemplate(injectableInterfaceTemplate, { ifaceName });
3093
3083
  files.push(
3094
3084
  writeFileSafely(ifacePath, ifaceContent, {
@@ -3217,7 +3207,7 @@ async function runEnvInit(flags = {}) {
3217
3207
  const projectRoot = flags.cwd || flags.targetDir || findProjectRoot();
3218
3208
  const s = p19.spinner();
3219
3209
  s.start("Scanning for .example environment files...");
3220
- const files = fs14.readdirSync(projectRoot);
3210
+ const files = fs17.readdirSync(projectRoot);
3221
3211
  const exampleFiles = files.filter((file) => file.startsWith(".env") && file.endsWith(".example")).sort();
3222
3212
  if (exampleFiles.length === 0) {
3223
3213
  s.stop("No .example files found.");
@@ -3227,11 +3217,11 @@ async function runEnvInit(flags = {}) {
3227
3217
  s.message(`Found ${exampleFiles.length} template(s). Generating...`);
3228
3218
  const generatedFiles = [];
3229
3219
  for (const exampleFile of exampleFiles) {
3230
- const sourcePath = path2.join(projectRoot, exampleFile);
3220
+ const sourcePath = path26.join(projectRoot, exampleFile);
3231
3221
  const targetFile = exampleFile.replace(/\.example$/, "");
3232
- const targetPath = path2.join(projectRoot, targetFile);
3222
+ const targetPath = path26.join(projectRoot, targetFile);
3233
3223
  let overwrite = flags.overwrite;
3234
- if (overwrite === void 0 && !flags.dryRun && !flags.yes && !process.env.VITEST && process.stdin.isTTY && fs14.existsSync(targetPath)) {
3224
+ if (overwrite === void 0 && !flags.dryRun && !flags.yes && !process.env.VITEST && process.stdin.isTTY && fs17.existsSync(targetPath)) {
3235
3225
  overwrite = await p19.confirm({
3236
3226
  message: `${targetFile} already exists. Overwrite?`,
3237
3227
  initialValue: false
@@ -3241,7 +3231,7 @@ async function runEnvInit(flags = {}) {
3241
3231
  process.exit(0);
3242
3232
  }
3243
3233
  }
3244
- const content = fs14.readFileSync(sourcePath, "utf-8");
3234
+ const content = fs17.readFileSync(sourcePath, "utf-8");
3245
3235
  const genFile = writeFileSafely(targetPath, content, {
3246
3236
  projectRoot,
3247
3237
  dryRun: Boolean(flags.dryRun),
@@ -3259,7 +3249,7 @@ var EnvEditor = class {
3259
3249
  filePath;
3260
3250
  constructor(filePath) {
3261
3251
  this.filePath = filePath;
3262
- this.lines = fs14.existsSync(filePath) ? fs14.readFileSync(filePath, "utf-8").split(/\r?\n/) : [];
3252
+ this.lines = fs17.existsSync(filePath) ? fs17.readFileSync(filePath, "utf-8").split(/\r?\n/) : [];
3263
3253
  }
3264
3254
  getLines() {
3265
3255
  return [...this.lines];
@@ -3323,18 +3313,18 @@ var EnvEditor = class {
3323
3313
  });
3324
3314
  }
3325
3315
  save() {
3326
- const dir = path2.dirname(this.filePath);
3327
- if (!fs14.existsSync(dir)) {
3328
- fs14.mkdirSync(dir, { recursive: true });
3316
+ const dir = path26.dirname(this.filePath);
3317
+ if (!fs17.existsSync(dir)) {
3318
+ fs17.mkdirSync(dir, { recursive: true });
3329
3319
  }
3330
- fs14.writeFileSync(this.filePath, this.lines.join("\n"), "utf-8");
3320
+ fs17.writeFileSync(this.filePath, this.lines.join("\n"), "utf-8");
3331
3321
  }
3332
3322
  };
3333
3323
  function discoverEnvironments(projectRoot) {
3334
- if (!fs14.existsSync(projectRoot)) {
3324
+ if (!fs17.existsSync(projectRoot)) {
3335
3325
  return ["local", "dev", "prod"];
3336
3326
  }
3337
- const files = fs14.readdirSync(projectRoot);
3327
+ const files = fs17.readdirSync(projectRoot);
3338
3328
  const envs = /* @__PURE__ */ new Set();
3339
3329
  for (const file of files) {
3340
3330
  if (file.startsWith(".env")) {
@@ -3359,7 +3349,7 @@ async function runEnvInitExamples(flags = {}) {
3359
3349
  const projectRoot = flags.cwd || flags.targetDir || findProjectRoot();
3360
3350
  const s = p19.spinner();
3361
3351
  s.start("Scanning for local environment files...");
3362
- const files = fs14.readdirSync(projectRoot, { withFileTypes: true });
3352
+ const files = fs17.readdirSync(projectRoot, { withFileTypes: true });
3363
3353
  const envFiles = files.filter((dirent) => dirent.isFile() && dirent.name.startsWith(".env") && !dirent.name.endsWith(".example")).map((dirent) => dirent.name).sort();
3364
3354
  if (envFiles.length === 0) {
3365
3355
  s.stop("No local .env files found.");
@@ -3369,11 +3359,11 @@ async function runEnvInitExamples(flags = {}) {
3369
3359
  s.message(`Found ${envFiles.length} local .env file(s). Generating templates...`);
3370
3360
  const generatedFiles = [];
3371
3361
  for (const envFile of envFiles) {
3372
- const sourcePath = path2.join(projectRoot, envFile);
3362
+ const sourcePath = path26.join(projectRoot, envFile);
3373
3363
  const targetFile = `${envFile}.example`;
3374
- const targetPath = path2.join(projectRoot, targetFile);
3364
+ const targetPath = path26.join(projectRoot, targetFile);
3375
3365
  let overwrite = flags.overwrite;
3376
- if (overwrite === void 0 && !flags.dryRun && !flags.yes && !process.env.VITEST && process.stdin.isTTY && fs14.existsSync(targetPath)) {
3366
+ if (overwrite === void 0 && !flags.dryRun && !flags.yes && !process.env.VITEST && process.stdin.isTTY && fs17.existsSync(targetPath)) {
3377
3367
  overwrite = await p19.confirm({
3378
3368
  message: `${targetFile} already exists. Overwrite with redacted values?`,
3379
3369
  initialValue: true
@@ -3406,12 +3396,12 @@ function isInteractive(flags) {
3406
3396
  function getAllExistingKeys(projectRoot, envs) {
3407
3397
  const keys = /* @__PURE__ */ new Set();
3408
3398
  for (const env of envs) {
3409
- const localPath = path2.join(projectRoot, resolveEnvFilename(env, false));
3410
- const examplePath = path2.join(projectRoot, resolveEnvFilename(env, true));
3411
- if (fs14.existsSync(localPath)) {
3399
+ const localPath = path26.join(projectRoot, resolveEnvFilename(env, false));
3400
+ const examplePath = path26.join(projectRoot, resolveEnvFilename(env, true));
3401
+ if (fs17.existsSync(localPath)) {
3412
3402
  new EnvEditor(localPath).getKeys().forEach((k) => keys.add(k));
3413
3403
  }
3414
- if (fs14.existsSync(examplePath)) {
3404
+ if (fs17.existsSync(examplePath)) {
3415
3405
  new EnvEditor(examplePath).getKeys().forEach((k) => keys.add(k));
3416
3406
  }
3417
3407
  }
@@ -3483,8 +3473,8 @@ async function runEnvAdd(key, value, flags = {}) {
3483
3473
  })
3484
3474
  );
3485
3475
  }
3486
- const localPath = path2.join(projectRoot, resolveEnvFilename(env, false));
3487
- const examplePath = path2.join(projectRoot, resolveEnvFilename(env, true));
3476
+ const localPath = path26.join(projectRoot, resolveEnvFilename(env, false));
3477
+ const examplePath = path26.join(projectRoot, resolveEnvFilename(env, true));
3488
3478
  if (flags.dryRun) {
3489
3479
  p19.log.info(
3490
3480
  pc13.cyan(`[DRY RUN] Would set ${targetKey}=${envVal} in ${resolveEnvFilename(env, false)}`)
@@ -3531,8 +3521,8 @@ async function runEnvUpdate(key, value, flags = {}) {
3531
3521
  );
3532
3522
  }
3533
3523
  const envsWithKey = allEnvs.filter((env) => {
3534
- const localPath = path2.join(projectRoot, resolveEnvFilename(env, false));
3535
- return fs14.existsSync(localPath) && new EnvEditor(localPath).has(targetKey);
3524
+ const localPath = path26.join(projectRoot, resolveEnvFilename(env, false));
3525
+ return fs17.existsSync(localPath) && new EnvEditor(localPath).has(targetKey);
3536
3526
  });
3537
3527
  let targetEnvs = [];
3538
3528
  if (flags.env) {
@@ -3558,7 +3548,7 @@ async function runEnvUpdate(key, value, flags = {}) {
3558
3548
  return { key: targetKey, environments: [] };
3559
3549
  }
3560
3550
  for (const env of targetEnvs) {
3561
- const localPath = path2.join(projectRoot, resolveEnvFilename(env, false));
3551
+ const localPath = path26.join(projectRoot, resolveEnvFilename(env, false));
3562
3552
  const localEditor = new EnvEditor(localPath);
3563
3553
  const currentVal = localEditor.getValue(targetKey);
3564
3554
  let newVal = value;
@@ -3588,7 +3578,7 @@ async function runEnvUpdate(key, value, flags = {}) {
3588
3578
  } else {
3589
3579
  localEditor.set(targetKey, newVal);
3590
3580
  localEditor.save();
3591
- const examplePath = path2.join(projectRoot, resolveEnvFilename(env, true));
3581
+ const examplePath = path26.join(projectRoot, resolveEnvFilename(env, true));
3592
3582
  const exampleEditor = new EnvEditor(examplePath);
3593
3583
  if (!exampleEditor.has(targetKey)) {
3594
3584
  exampleEditor.set(targetKey, "");
@@ -3624,9 +3614,9 @@ async function runEnvDelete(key, flags = {}) {
3624
3614
  );
3625
3615
  }
3626
3616
  const envsWithKey = allEnvs.filter((env) => {
3627
- const localPath = path2.join(projectRoot, resolveEnvFilename(env, false));
3628
- const examplePath = path2.join(projectRoot, resolveEnvFilename(env, true));
3629
- return fs14.existsSync(localPath) && new EnvEditor(localPath).has(targetKey) || fs14.existsSync(examplePath) && new EnvEditor(examplePath).has(targetKey);
3617
+ const localPath = path26.join(projectRoot, resolveEnvFilename(env, false));
3618
+ const examplePath = path26.join(projectRoot, resolveEnvFilename(env, true));
3619
+ return fs17.existsSync(localPath) && new EnvEditor(localPath).has(targetKey) || fs17.existsSync(examplePath) && new EnvEditor(examplePath).has(targetKey);
3630
3620
  });
3631
3621
  let targetEnvs = [];
3632
3622
  if (flags.env) {
@@ -3664,19 +3654,19 @@ async function runEnvDelete(key, flags = {}) {
3664
3654
  }
3665
3655
  }
3666
3656
  for (const env of targetEnvs) {
3667
- const localPath = path2.join(projectRoot, resolveEnvFilename(env, false));
3668
- const examplePath = path2.join(projectRoot, resolveEnvFilename(env, true));
3657
+ const localPath = path26.join(projectRoot, resolveEnvFilename(env, false));
3658
+ const examplePath = path26.join(projectRoot, resolveEnvFilename(env, true));
3669
3659
  if (flags.dryRun) {
3670
3660
  p19.log.info(
3671
3661
  pc13.cyan(`[DRY RUN] Would delete ${targetKey} from ${resolveEnvFilename(env, false)} and ${resolveEnvFilename(env, true)}`)
3672
3662
  );
3673
3663
  } else {
3674
- if (fs14.existsSync(localPath)) {
3664
+ if (fs17.existsSync(localPath)) {
3675
3665
  const localEditor = new EnvEditor(localPath);
3676
3666
  localEditor.delete(targetKey);
3677
3667
  localEditor.save();
3678
3668
  }
3679
- if (fs14.existsSync(examplePath)) {
3669
+ if (fs17.existsSync(examplePath)) {
3680
3670
  const exampleEditor = new EnvEditor(examplePath);
3681
3671
  exampleEditor.delete(targetKey);
3682
3672
  exampleEditor.save();
@@ -3701,10 +3691,10 @@ async function runEnvAudit(flags = {}) {
3701
3691
  for (const env of envs) {
3702
3692
  const localFile = resolveEnvFilename(env, false);
3703
3693
  const exampleFile = resolveEnvFilename(env, true);
3704
- const localPath = path2.join(projectRoot, localFile);
3705
- const examplePath = path2.join(projectRoot, exampleFile);
3706
- const localExists = fs14.existsSync(localPath);
3707
- const exampleExists = fs14.existsSync(examplePath);
3694
+ const localPath = path26.join(projectRoot, localFile);
3695
+ const examplePath = path26.join(projectRoot, exampleFile);
3696
+ const localExists = fs17.existsSync(localPath);
3697
+ const exampleExists = fs17.existsSync(examplePath);
3708
3698
  const localEditor = new EnvEditor(localPath);
3709
3699
  const exampleEditor = new EnvEditor(examplePath);
3710
3700
  const localKeys = localExists ? localEditor.getKeys() : [];
@@ -4031,25 +4021,25 @@ function normalizeRegistryUrl(urlOrPath, baseDir) {
4031
4021
  return `https://raw.githubusercontent.com/${owner}/${repo}/${branch}`;
4032
4022
  }
4033
4023
  if (baseDir && (trimmed.startsWith("./") || trimmed.startsWith("../") || trimmed === "." || trimmed === "..")) {
4034
- return path2.resolve(baseDir, trimmed);
4024
+ return path26.resolve(baseDir, trimmed);
4035
4025
  }
4036
4026
  return trimmed;
4037
4027
  }
4038
4028
  function findLocalRegistry(startDir = process.cwd()) {
4039
- let current = path2.resolve(startDir);
4029
+ let current = path26.resolve(startDir);
4040
4030
  while (true) {
4041
- const candidate = path2.join(current, "mason-registry");
4042
- if (fs14.existsSync(candidate) && fs14.existsSync(path2.join(candidate, "index.json"))) {
4031
+ const candidate = path26.join(current, "mason-registry");
4032
+ if (fs17.existsSync(candidate) && fs17.existsSync(path26.join(candidate, "index.json"))) {
4043
4033
  return candidate;
4044
4034
  }
4045
- const parent = path2.dirname(current);
4035
+ const parent = path26.dirname(current);
4046
4036
  if (parent === current) break;
4047
4037
  current = parent;
4048
4038
  }
4049
4039
  return null;
4050
4040
  }
4051
4041
  function getRegistryBase(projectRoot, override) {
4052
- const rootDir = projectRoot ? path2.resolve(projectRoot) : process.cwd();
4042
+ const rootDir = projectRoot ? path26.resolve(projectRoot) : process.cwd();
4053
4043
  if (override && override.trim()) {
4054
4044
  return normalizeRegistryUrl(override.trim(), rootDir);
4055
4045
  }
@@ -4057,30 +4047,30 @@ function getRegistryBase(projectRoot, override) {
4057
4047
  return normalizeRegistryUrl(process.env.MASON_REGISTRY_URL.trim(), rootDir);
4058
4048
  }
4059
4049
  const configLocations = [
4060
- path2.join(rootDir, "mason.config.json"),
4061
- path2.join(process.cwd(), "mason.config.json")
4050
+ path26.join(rootDir, "mason.config.json"),
4051
+ path26.join(process.cwd(), "mason.config.json")
4062
4052
  ];
4063
4053
  for (const configPath of configLocations) {
4064
- if (fs14.existsSync(configPath)) {
4054
+ if (fs17.existsSync(configPath)) {
4065
4055
  try {
4066
- const config = JSON.parse(fs14.readFileSync(configPath, "utf-8"));
4056
+ const config = JSON.parse(fs17.readFileSync(configPath, "utf-8"));
4067
4057
  if (config.registry && typeof config.registry === "string") {
4068
- return normalizeRegistryUrl(config.registry.trim(), path2.dirname(configPath));
4058
+ return normalizeRegistryUrl(config.registry.trim(), path26.dirname(configPath));
4069
4059
  }
4070
4060
  } catch {
4071
4061
  }
4072
4062
  }
4073
4063
  }
4074
4064
  const pkgLocations = [
4075
- path2.join(rootDir, "package.json"),
4076
- path2.join(process.cwd(), "package.json")
4065
+ path26.join(rootDir, "package.json"),
4066
+ path26.join(process.cwd(), "package.json")
4077
4067
  ];
4078
4068
  for (const pkgPath of pkgLocations) {
4079
- if (fs14.existsSync(pkgPath)) {
4069
+ if (fs17.existsSync(pkgPath)) {
4080
4070
  try {
4081
- const pkg = JSON.parse(fs14.readFileSync(pkgPath, "utf-8"));
4071
+ const pkg = JSON.parse(fs17.readFileSync(pkgPath, "utf-8"));
4082
4072
  if (pkg.mason?.registry && typeof pkg.mason.registry === "string") {
4083
- return normalizeRegistryUrl(pkg.mason.registry.trim(), path2.dirname(pkgPath));
4073
+ return normalizeRegistryUrl(pkg.mason.registry.trim(), path26.dirname(pkgPath));
4084
4074
  }
4085
4075
  } catch {
4086
4076
  }
@@ -4128,16 +4118,16 @@ async function fetchRegistryFile(registryBase, relPath) {
4128
4118
  if (baseDir.startsWith("file://")) {
4129
4119
  baseDir = fileURLToPath(baseDir);
4130
4120
  }
4131
- let filePath = path2.resolve(baseDir, cleanRelPath);
4132
- if (!fs14.existsSync(filePath)) {
4133
- const inSrcPath = path2.resolve(baseDir, "src", cleanRelPath);
4134
- if (fs14.existsSync(inSrcPath)) {
4121
+ let filePath = path26.resolve(baseDir, cleanRelPath);
4122
+ if (!fs17.existsSync(filePath)) {
4123
+ const inSrcPath = path26.resolve(baseDir, "src", cleanRelPath);
4124
+ if (fs17.existsSync(inSrcPath)) {
4135
4125
  filePath = inSrcPath;
4136
4126
  } else {
4137
4127
  throw new Error(`Registry file not found at ${filePath}`);
4138
4128
  }
4139
4129
  }
4140
- return fs14.promises.readFile(filePath, "utf-8");
4130
+ return fs17.promises.readFile(filePath, "utf-8");
4141
4131
  }
4142
4132
  async function fetchRegistryIndex(registryBase) {
4143
4133
  const content = await fetchRegistryFile(registryBase, "index.json");
@@ -4199,19 +4189,19 @@ function findClosestMatch(target, candidates) {
4199
4189
  return null;
4200
4190
  }
4201
4191
  function detectPackageManager(projectRoot) {
4202
- if (fs14.existsSync(path2.join(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
4203
- if (fs14.existsSync(path2.join(projectRoot, "yarn.lock"))) return "yarn";
4204
- if (fs14.existsSync(path2.join(projectRoot, "bun.lockb")) || fs14.existsSync(path2.join(projectRoot, "bun.lock"))) return "bun";
4192
+ if (fs17.existsSync(path26.join(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
4193
+ if (fs17.existsSync(path26.join(projectRoot, "yarn.lock"))) return "yarn";
4194
+ if (fs17.existsSync(path26.join(projectRoot, "bun.lockb")) || fs17.existsSync(path26.join(projectRoot, "bun.lock"))) return "bun";
4205
4195
  return "npm";
4206
4196
  }
4207
4197
  function getMissingNpmPackages(projectRoot, requiredPackages) {
4208
4198
  if (!requiredPackages || requiredPackages.length === 0) return [];
4209
- const pkgJsonPath = path2.join(projectRoot, "package.json");
4210
- if (!fs14.existsSync(pkgJsonPath)) {
4199
+ const pkgJsonPath = path26.join(projectRoot, "package.json");
4200
+ if (!fs17.existsSync(pkgJsonPath)) {
4211
4201
  return requiredPackages;
4212
4202
  }
4213
4203
  try {
4214
- const pkg = JSON.parse(fs14.readFileSync(pkgJsonPath, "utf-8"));
4204
+ const pkg = JSON.parse(fs17.readFileSync(pkgJsonPath, "utf-8"));
4215
4205
  const installed = /* @__PURE__ */ new Set([
4216
4206
  ...Object.keys(pkg.dependencies || {}),
4217
4207
  ...Object.keys(pkg.devDependencies || {}),
@@ -4250,12 +4240,12 @@ function installNpmPackages(projectRoot, packages, pm) {
4250
4240
  });
4251
4241
  }
4252
4242
  function getAllFiles(dir, baseDir = dir) {
4253
- if (!fs14.existsSync(dir)) return [];
4254
- const entries = fs14.readdirSync(dir, { withFileTypes: true });
4243
+ if (!fs17.existsSync(dir)) return [];
4244
+ const entries = fs17.readdirSync(dir, { withFileTypes: true });
4255
4245
  const files = [];
4256
4246
  for (const entry of entries) {
4257
- const fullPath = path2.join(dir, entry.name);
4258
- const relPath = path2.relative(baseDir, fullPath).replace(/\\/g, "/");
4247
+ const fullPath = path26.join(dir, entry.name);
4248
+ const relPath = path26.relative(baseDir, fullPath).replace(/\\/g, "/");
4259
4249
  if (entry.isDirectory()) {
4260
4250
  if (entry.name === "__tests__" || entry.name.startsWith(".")) {
4261
4251
  continue;
@@ -4271,13 +4261,13 @@ function getAllFiles(dir, baseDir = dir) {
4271
4261
  return files.sort();
4272
4262
  }
4273
4263
  function computeDirectoryHash(dirPath, files) {
4274
- if (!fs14.existsSync(dirPath)) return "";
4264
+ if (!fs17.existsSync(dirPath)) return "";
4275
4265
  const hash = createHash("sha256");
4276
4266
  const fileList = (getAllFiles(dirPath)).sort();
4277
4267
  for (const relativePath of fileList) {
4278
- const absolutePath = path2.join(dirPath, relativePath);
4279
- if (!fs14.existsSync(absolutePath)) continue;
4280
- const content = fs14.readFileSync(absolutePath, "utf8");
4268
+ const absolutePath = path26.join(dirPath, relativePath);
4269
+ if (!fs17.existsSync(absolutePath)) continue;
4270
+ const content = fs17.readFileSync(absolutePath, "utf8");
4281
4271
  const normalizedContent = content.replace(/\r\n/g, "\n");
4282
4272
  hash.update(relativePath);
4283
4273
  hash.update(normalizedContent);
@@ -4315,17 +4305,17 @@ function getModuleBaseDir(projectRoot, modType) {
4315
4305
  return modType === "shared" ? getConfiguredSharedDir(projectRoot) : getConfiguredFeaturesDir(projectRoot);
4316
4306
  }
4317
4307
  const folder = modType === "shared" ? "shared" : "features";
4318
- return path2.join(projectRoot, "src", folder);
4308
+ return path26.join(projectRoot, "src", folder);
4319
4309
  }
4320
4310
  function getExistingModuleDir(projectRoot, modType, modName) {
4321
4311
  const folder = modType === "shared" ? "shared" : "features";
4322
4312
  const configuredDir = modType === "shared" ? getConfiguredSharedDir(projectRoot) : getConfiguredFeaturesDir(projectRoot);
4323
- const inConfigured = path2.join(configuredDir, modName);
4324
- if (fs14.existsSync(inConfigured)) return inConfigured;
4325
- const inSrc = path2.join(projectRoot, "src", folder, modName);
4326
- if (fs14.existsSync(inSrc)) return inSrc;
4327
- const inRoot = path2.join(projectRoot, folder, modName);
4328
- if (fs14.existsSync(inRoot)) return inRoot;
4313
+ const inConfigured = path26.join(configuredDir, modName);
4314
+ if (fs17.existsSync(inConfigured)) return inConfigured;
4315
+ const inSrc = path26.join(projectRoot, "src", folder, modName);
4316
+ if (fs17.existsSync(inSrc)) return inSrc;
4317
+ const inRoot = path26.join(projectRoot, folder, modName);
4318
+ if (fs17.existsSync(inRoot)) return inRoot;
4329
4319
  return null;
4330
4320
  }
4331
4321
  function checkModuleExists(projectRoot, modType, modName) {
@@ -4336,14 +4326,14 @@ function getAvailableLocalModules(projectRoot, modType) {
4336
4326
  const configuredDir = modType === "shared" ? getConfiguredSharedDir(projectRoot) : getConfiguredFeaturesDir(projectRoot);
4337
4327
  const dirs = [
4338
4328
  configuredDir,
4339
- path2.join(projectRoot, "src", folder),
4340
- path2.join(projectRoot, folder)
4329
+ path26.join(projectRoot, "src", folder),
4330
+ path26.join(projectRoot, folder)
4341
4331
  ];
4342
4332
  const set = /* @__PURE__ */ new Set();
4343
4333
  for (const dir of dirs) {
4344
- if (fs14.existsSync(dir)) {
4334
+ if (fs17.existsSync(dir)) {
4345
4335
  try {
4346
- const entries = fs14.readdirSync(dir, { withFileTypes: true });
4336
+ const entries = fs17.readdirSync(dir, { withFileTypes: true });
4347
4337
  for (const e of entries) {
4348
4338
  if (e.isDirectory() && !e.name.startsWith(".")) {
4349
4339
  set.add(e.name);
@@ -4545,7 +4535,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
4545
4535
  globalAliasMap.set(`@/${folder}/${registryName}/`, `@/${folder}/${programmaticAlias}/`);
4546
4536
  globalAliasMap.set(`@/${folder}/${registryName}`, `@/${folder}/${programmaticAlias}`);
4547
4537
  const baseDir = getModuleBaseDir(projectRoot, modType);
4548
- const displayDest = path2.relative(projectRoot, path2.join(baseDir, programmaticAlias));
4538
+ const displayDest = path26.relative(projectRoot, path26.join(baseDir, programmaticAlias));
4549
4539
  p19.log.step(`Importing '${registryName}' into '${displayDest}'...`);
4550
4540
  resolutions.set(key, {
4551
4541
  type: modType,
@@ -4733,7 +4723,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
4733
4723
  globalAliasMap.set(`@/${folder}/${registryName}/`, `@/${folder}/${newName}/`);
4734
4724
  globalAliasMap.set(`@/${folder}/${registryName}`, `@/${folder}/${newName}`);
4735
4725
  const baseDir = getModuleBaseDir(projectRoot, modType);
4736
- const displayDest = path2.relative(projectRoot, path2.join(baseDir, newName));
4726
+ const displayDest = path26.relative(projectRoot, path26.join(baseDir, newName));
4737
4727
  p19.log.step(`Importing '${registryName}' into '${displayDest}'...`);
4738
4728
  resolutions.set(key, {
4739
4729
  type: modType,
@@ -4785,7 +4775,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
4785
4775
  continue;
4786
4776
  }
4787
4777
  const folder = res.type === "shared" ? "shared" : "features";
4788
- const targetDir = path2.join(getModuleBaseDir(projectRoot, res.type), res.targetName);
4778
+ const targetDir = path26.join(getModuleBaseDir(projectRoot, res.type), res.targetName);
4789
4779
  const isOverwrite = Boolean(flags.overwrite || res.action === "overwrite");
4790
4780
  if (key !== rootKey) {
4791
4781
  p19.log.step(
@@ -4795,30 +4785,30 @@ async function handleImport(typeArg, nameArg, flags = {}) {
4795
4785
  if (res.action === "overwrite" && !flags.dryRun) {
4796
4786
  const existingDir = getExistingModuleDir(projectRoot, res.type, res.targetName);
4797
4787
  if (existingDir && existingDir !== targetDir) {
4798
- fs14.rmSync(existingDir, { recursive: true, force: true });
4788
+ fs17.rmSync(existingDir, { recursive: true, force: true });
4799
4789
  }
4800
- if (fs14.existsSync(targetDir)) {
4801
- fs14.rmSync(targetDir, { recursive: true, force: true });
4790
+ if (fs17.existsSync(targetDir)) {
4791
+ fs17.rmSync(targetDir, { recursive: true, force: true });
4802
4792
  }
4803
4793
  }
4804
4794
  for (const file of res.manifest.files || []) {
4805
4795
  if (file === "registry.json") continue;
4806
4796
  if (!includeTests && isTestFile(file)) continue;
4807
4797
  const remoteFilePath = `${folder}/${res.registryName}/${file}`;
4808
- const localFilePath = path2.join(targetDir, file);
4809
- if (fs14.existsSync(localFilePath) && !isOverwrite) {
4798
+ const localFilePath = path26.join(targetDir, file);
4799
+ if (fs17.existsSync(localFilePath) && !isOverwrite) {
4810
4800
  p19.log.warn(
4811
- ` \u21B3 Skipping existing file: ${pc13.dim(path2.relative(projectRoot, localFilePath))} (use --overwrite to replace)`
4801
+ ` \u21B3 Skipping existing file: ${pc13.dim(path26.relative(projectRoot, localFilePath))} (use --overwrite to replace)`
4812
4802
  );
4813
4803
  continue;
4814
4804
  }
4815
4805
  let content = await fetchRegistryFile(registryBase, remoteFilePath);
4816
4806
  content = rewriteImports(content, globalAliasMap);
4817
4807
  if (!flags.dryRun) {
4818
- fs14.mkdirSync(path2.dirname(localFilePath), { recursive: true });
4819
- fs14.writeFileSync(localFilePath, content, "utf-8");
4808
+ fs17.mkdirSync(path26.dirname(localFilePath), { recursive: true });
4809
+ fs17.writeFileSync(localFilePath, content, "utf-8");
4820
4810
  }
4821
- const displayPath = path2.relative(projectRoot, localFilePath);
4811
+ const displayPath = path26.relative(projectRoot, localFilePath);
4822
4812
  totalWrittenFiles.push(displayPath);
4823
4813
  p19.log.message(` ${pc13.green("+")} ${displayPath}`);
4824
4814
  }
@@ -4844,7 +4834,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
4844
4834
  } else {
4845
4835
  const rootRes = resolutions.get(rootKey);
4846
4836
  const baseDir = getModuleBaseDir(projectRoot, type);
4847
- const displayTarget = path2.relative(projectRoot, path2.join(baseDir, rootRes.targetName));
4837
+ const displayTarget = path26.relative(projectRoot, path26.join(baseDir, rootRes.targetName));
4848
4838
  p19.log.success(
4849
4839
  pc13.green(
4850
4840
  `Successfully imported ${type} '${name}' (${totalWrittenFiles.length} file${totalWrittenFiles.length === 1 ? "" : "s"} placed in ${displayTarget})`
@@ -4863,19 +4853,19 @@ var DependencyRuleError = class extends Error {
4863
4853
  }
4864
4854
  };
4865
4855
  function isTestFile2(filePath, projectRoot) {
4866
- const norm = (projectRoot ? path2.relative(projectRoot, filePath) : filePath).replace(/\\/g, "/");
4867
- const base = path2.basename(norm);
4856
+ const norm = (projectRoot ? path26.relative(projectRoot, filePath) : filePath).replace(/\\/g, "/");
4857
+ const base = path26.basename(norm);
4868
4858
  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);
4869
4859
  }
4870
4860
  function scanDirFiles(dir, projectRoot) {
4871
- if (!fs14.existsSync(dir)) return [];
4872
- const entries = fs14.readdirSync(dir, { withFileTypes: true });
4861
+ if (!fs17.existsSync(dir)) return [];
4862
+ const entries = fs17.readdirSync(dir, { withFileTypes: true });
4873
4863
  const files = [];
4874
4864
  for (const entry of entries) {
4875
4865
  if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "__tests__" || entry.name.startsWith(".")) {
4876
4866
  continue;
4877
4867
  }
4878
- const fullPath = path2.join(dir, entry.name);
4868
+ const fullPath = path26.join(dir, entry.name);
4879
4869
  if (entry.isDirectory()) {
4880
4870
  files.push(...scanDirFiles(fullPath, projectRoot));
4881
4871
  } else if (entry.isFile() && (entry.name.endsWith(".ts") || entry.name.endsWith(".js")) && !isTestFile2(fullPath, projectRoot)) {
@@ -4884,42 +4874,43 @@ function scanDirFiles(dir, projectRoot) {
4884
4874
  }
4885
4875
  return files;
4886
4876
  }
4887
- function classifyFile(fullPath, projectRoot) {
4888
- const rel = path2.relative(projectRoot, fullPath).replace(/\\/g, "/");
4889
- const featureMatch = rel.match(/(?:^|\/)(?:src\/)?features\/([^/]+)\/([^/]+)(?:\/.*)?$/);
4890
- if (featureMatch && featureMatch[1] && featureMatch[2]) {
4891
- const feature = featureMatch[1];
4892
- const subfolder = featureMatch[2];
4893
- let layer;
4894
- if (subfolder === "domain" || subfolder === "errors") {
4895
- layer = "domain";
4896
- } else if (subfolder === "useCases" || subfolder === "usecases") {
4897
- layer = "useCases";
4898
- } else if (subfolder === "services") {
4899
- layer = "services";
4900
- } else if (subfolder === "infrastructure") {
4901
- layer = "infrastructure";
4902
- } else if (subfolder === "pxExpress" || subfolder === "presentation" || subfolder === "handlers" || subfolder.startsWith("px")) {
4903
- layer = "presentation";
4904
- }
4905
- return { moduleType: "feature", moduleName: feature, feature, layer };
4906
- }
4907
- const sharedMatch = rel.match(/(?:^|\/)(?:src\/)?shared\/([^/]+)(?:\/(.*))?$/);
4908
- if (sharedMatch && sharedMatch[1]) {
4909
- const moduleName = sharedMatch[1];
4910
- const rest = sharedMatch[2] || "";
4911
- let layer = "root";
4912
- if (rest.startsWith("domain/") || rest === "domain" || rest.startsWith("errors/") || rest === "errors") {
4913
- layer = "domain";
4914
- } else if (rest.startsWith("ports/") || rest === "ports") {
4915
- layer = "ports";
4916
- } else if (rest.startsWith("infrastructure/") || rest === "infrastructure") {
4917
- layer = "infrastructure";
4918
- }
4919
- return { moduleType: "shared", moduleName, feature: moduleName, layer };
4920
- }
4921
- const errorMatch = rel.match(/(?:^|\/)(?:src\/)?errors(?:\/(.*))?$/);
4922
- if (errorMatch) {
4877
+ function resolveLintEnvironment(projectRoot) {
4878
+ const config = loadMasonConfig(projectRoot);
4879
+ const resolveDir = (configured, defaultSrc, defaultRoot) => {
4880
+ if (configured !== void 0) {
4881
+ return path26.resolve(projectRoot, configured);
4882
+ }
4883
+ const srcPath = path26.join(projectRoot, defaultSrc);
4884
+ if (fs17.existsSync(srcPath)) return srcPath;
4885
+ const rootPath = path26.join(projectRoot, defaultRoot);
4886
+ if (fs17.existsSync(rootPath)) return rootPath;
4887
+ return srcPath;
4888
+ };
4889
+ const featuresBase = resolveDir(config?.paths?.features, "src/features", "features");
4890
+ const sharedBase = resolveDir(config?.paths?.shared, "src/shared", "shared");
4891
+ const errorsBase = resolveDir(config?.paths?.errors, "src/errors", "errors");
4892
+ const defaultBaseErrorRelative = config?.paths?.errors ? path26.join(config.paths.errors, "AppError.ts") : fs17.existsSync(path26.join(projectRoot, "src/errors")) ? "src/errors/AppError.ts" : fs17.existsSync(path26.join(projectRoot, "errors")) ? "errors/AppError.ts" : "src/errors/AppError.ts";
4893
+ const baseErrorAbs = path26.resolve(
4894
+ projectRoot,
4895
+ config?.paths?.baseError || defaultBaseErrorRelative
4896
+ );
4897
+ return { featuresBase, sharedBase, errorsBase, baseErrorAbs };
4898
+ }
4899
+ function classifyFile(fullPathAbs, featuresBaseAbs, sharedBaseAbs, errorsBaseAbs) {
4900
+ if (!sharedBaseAbs || !errorsBaseAbs) {
4901
+ const env = resolveLintEnvironment(featuresBaseAbs);
4902
+ featuresBaseAbs = env.featuresBase;
4903
+ sharedBaseAbs = env.sharedBase;
4904
+ errorsBaseAbs = env.errorsBase;
4905
+ }
4906
+ const normFullPath = path26.resolve(fullPathAbs);
4907
+ const normErrorsBase = path26.resolve(errorsBaseAbs);
4908
+ const normSharedBase = path26.resolve(sharedBaseAbs);
4909
+ const normFeaturesBase = path26.resolve(featuresBaseAbs);
4910
+ const isUnder = (base, target) => {
4911
+ return target === base || target.startsWith(base + path26.sep);
4912
+ };
4913
+ if (isUnder(normErrorsBase, normFullPath)) {
4923
4914
  return {
4924
4915
  moduleType: "error",
4925
4916
  moduleName: "global-errors",
@@ -4927,46 +4918,154 @@ function classifyFile(fullPath, projectRoot) {
4927
4918
  layer: "domain"
4928
4919
  };
4929
4920
  }
4921
+ if (isUnder(normSharedBase, normFullPath)) {
4922
+ const rel = path26.relative(normSharedBase, normFullPath).replace(/\\/g, "/");
4923
+ const parts = rel.split("/").filter(Boolean);
4924
+ if (parts.length >= 1) {
4925
+ const moduleName = parts[0];
4926
+ const subfolder = parts[1];
4927
+ let layer = "root";
4928
+ if (subfolder === "domain" || subfolder === "errors") {
4929
+ layer = "domain";
4930
+ } else if (subfolder === "ports") {
4931
+ layer = "ports";
4932
+ } else if (subfolder === "infrastructure") {
4933
+ layer = "infrastructure";
4934
+ }
4935
+ return { moduleType: "shared", moduleName, feature: moduleName, layer };
4936
+ }
4937
+ }
4938
+ if (isUnder(normFeaturesBase, normFullPath)) {
4939
+ const rel = path26.relative(normFeaturesBase, normFullPath).replace(/\\/g, "/");
4940
+ const parts = rel.split("/").filter(Boolean);
4941
+ if (parts.length >= 2) {
4942
+ const moduleName = parts[0];
4943
+ const subfolder = parts[1];
4944
+ let layer;
4945
+ if (subfolder === "domain" || subfolder === "errors") {
4946
+ layer = "domain";
4947
+ } else if (subfolder === "useCases" || subfolder === "usecases") {
4948
+ layer = "useCases";
4949
+ } else if (subfolder === "services") {
4950
+ layer = "services";
4951
+ } else if (subfolder === "infrastructure") {
4952
+ layer = "infrastructure";
4953
+ } else if (subfolder.startsWith("px") || subfolder === "presentation" || subfolder === "handlers" || subfolder === "transformers") {
4954
+ layer = "presentation";
4955
+ }
4956
+ return { moduleType: "feature", moduleName, feature: moduleName, layer };
4957
+ }
4958
+ }
4930
4959
  return {};
4931
4960
  }
4932
- function classifyTarget(specifier, sourceFileAbs, projectRoot) {
4961
+ function classifyTarget(specifier, sourceFileAbs, projectRoot, featuresBaseAbs, sharedBaseAbs, errorsBaseAbs) {
4933
4962
  if (specifier === "@solid-stack/di" || specifier.startsWith("@solid-stack/di/")) {
4934
4963
  return { isExternal: true, isDiFramework: true };
4935
4964
  }
4936
- if (specifier.startsWith("node:") || ["crypto", "fs", "path", "http", "https", "url", "os", "child_process", "stream", "express", "cors", "dotenv"].includes(specifier)) {
4965
+ if (specifier.startsWith("node:") || [
4966
+ "crypto",
4967
+ "fs",
4968
+ "path",
4969
+ "http",
4970
+ "https",
4971
+ "url",
4972
+ "os",
4973
+ "child_process",
4974
+ "stream",
4975
+ "express",
4976
+ "cors",
4977
+ "dotenv"
4978
+ ].includes(specifier)) {
4937
4979
  return { isExternal: true, isDiFramework: false };
4938
4980
  }
4939
- let resolvedRel = null;
4981
+ if (!featuresBaseAbs || !sharedBaseAbs || !errorsBaseAbs) {
4982
+ const env = resolveLintEnvironment(projectRoot);
4983
+ featuresBaseAbs = featuresBaseAbs || env.featuresBase;
4984
+ sharedBaseAbs = sharedBaseAbs || env.sharedBase;
4985
+ errorsBaseAbs = errorsBaseAbs || env.errorsBase;
4986
+ }
4987
+ const isGlobalConfig = specifier === "@configs" || specifier.startsWith("@configs/") || specifier === "@/configs" || specifier.startsWith("@/configs/") || specifier === "~/configs" || specifier.startsWith("~/configs/") || specifier === "configs" || specifier.startsWith("configs/");
4988
+ let targetAbs = null;
4940
4989
  if (specifier.startsWith(".")) {
4941
- const abs = path2.resolve(path2.dirname(sourceFileAbs), specifier);
4942
- resolvedRel = path2.relative(projectRoot, abs).replace(/\\/g, "/");
4943
- } else if (specifier.startsWith("@/features/") || specifier.startsWith("~/features/")) {
4944
- resolvedRel = specifier.replace(/^[@~]\//, "src/");
4945
- } else if (specifier.startsWith("@features/")) {
4946
- resolvedRel = "src/" + specifier.slice(1);
4947
- } else if (specifier.startsWith("@/shared/") || specifier.startsWith("~/shared/")) {
4948
- resolvedRel = specifier.replace(/^[@~]\//, "src/");
4949
- } else if (specifier.startsWith("@shared/")) {
4950
- resolvedRel = "src/" + specifier.slice(1);
4951
- } else if (specifier.startsWith("@/configs/") || specifier.startsWith("~/configs/") || specifier === "@/configs" || specifier === "~/configs") {
4952
- resolvedRel = specifier.replace(/^[@~]\//, "src/");
4953
- } else if (specifier === "@configs" || specifier.startsWith("@configs/")) {
4954
- resolvedRel = "src/" + specifier.slice(1);
4955
- } else if (specifier.startsWith("@/errors/") || specifier.startsWith("~/errors/") || specifier === "@/errors" || specifier === "~/errors") {
4956
- resolvedRel = specifier.replace(/^[@~]\//, "src/");
4957
- } else if (specifier === "@errors" || specifier.startsWith("@errors/")) {
4958
- resolvedRel = "src/" + specifier.slice(1);
4959
- } else if (specifier.startsWith("@/") || specifier.startsWith("~/")) {
4960
- resolvedRel = "src/" + specifier.slice(2);
4961
- } else if (specifier.startsWith("features/") || specifier.startsWith("shared/") || specifier.startsWith("configs/") || specifier === "configs" || specifier.startsWith("errors/") || specifier === "errors") {
4962
- resolvedRel = specifier;
4963
- }
4964
- if (!resolvedRel) {
4965
- return { isExternal: true, isDiFramework: false };
4990
+ targetAbs = path26.resolve(path26.dirname(sourceFileAbs), specifier);
4991
+ } else {
4992
+ const featRel = path26.relative(projectRoot, featuresBaseAbs).replace(/\\/g, "/");
4993
+ const sharedRel = path26.relative(projectRoot, sharedBaseAbs).replace(/\\/g, "/");
4994
+ const errorsRel = path26.relative(projectRoot, errorsBaseAbs).replace(/\\/g, "/");
4995
+ const featPrefixes = ["features"];
4996
+ if (featRel && featRel !== "." && !featRel.startsWith("..")) {
4997
+ featPrefixes.push(featRel);
4998
+ const b = path26.basename(featRel);
4999
+ if (!featPrefixes.includes(b)) featPrefixes.push(b);
5000
+ }
5001
+ const sharedPrefixes = ["shared"];
5002
+ if (sharedRel && sharedRel !== "." && !sharedRel.startsWith("..")) {
5003
+ sharedPrefixes.push(sharedRel);
5004
+ const b = path26.basename(sharedRel);
5005
+ if (!sharedPrefixes.includes(b)) sharedPrefixes.push(b);
5006
+ }
5007
+ const errorsPrefixes = ["errors"];
5008
+ if (errorsRel && errorsRel !== "." && !errorsRel.startsWith("..")) {
5009
+ errorsPrefixes.push(errorsRel);
5010
+ const b = path26.basename(errorsRel);
5011
+ if (!errorsPrefixes.includes(b)) errorsPrefixes.push(b);
5012
+ }
5013
+ for (const prefix of featPrefixes) {
5014
+ const aliasRegex = new RegExp(`^([@~]\\/|@)?${prefix}\\/(.*)$`);
5015
+ const m = specifier.match(aliasRegex);
5016
+ if (m && m[2]) {
5017
+ targetAbs = path26.resolve(featuresBaseAbs, m[2]);
5018
+ break;
5019
+ }
5020
+ }
5021
+ if (!targetAbs) {
5022
+ for (const prefix of sharedPrefixes) {
5023
+ const aliasRegex = new RegExp(`^([@~]\\/|@)?${prefix}\\/(.*)$`);
5024
+ const m = specifier.match(aliasRegex);
5025
+ if (m && m[2]) {
5026
+ targetAbs = path26.resolve(sharedBaseAbs, m[2]);
5027
+ break;
5028
+ }
5029
+ }
5030
+ }
5031
+ if (!targetAbs) {
5032
+ for (const prefix of errorsPrefixes) {
5033
+ const aliasRegex = new RegExp(`^([@~]\\/|@)?${prefix}(?:\\/(.*))?$`);
5034
+ const m = specifier.match(aliasRegex);
5035
+ if (m) {
5036
+ targetAbs = path26.resolve(errorsBaseAbs, m[2] || "");
5037
+ break;
5038
+ }
5039
+ }
5040
+ }
5041
+ if (!targetAbs && (specifier.startsWith("@/") || specifier.startsWith("~/"))) {
5042
+ const sub = specifier.slice(2);
5043
+ const srcCandidate = path26.resolve(projectRoot, "src", sub);
5044
+ const rootCandidate = path26.resolve(projectRoot, sub);
5045
+ if (fs17.existsSync(srcCandidate)) {
5046
+ targetAbs = srcCandidate;
5047
+ } else if (fs17.existsSync(rootCandidate)) {
5048
+ targetAbs = rootCandidate;
5049
+ } else {
5050
+ targetAbs = srcCandidate;
5051
+ }
5052
+ }
5053
+ if (!targetAbs) {
5054
+ const featCandidate = path26.resolve(featuresBaseAbs, specifier);
5055
+ if (fs17.existsSync(featCandidate) || fs17.existsSync(featCandidate + ".ts") || fs17.existsSync(featCandidate + ".js")) {
5056
+ targetAbs = featCandidate;
5057
+ }
5058
+ }
4966
5059
  }
4967
- const isGlobalConfig = resolvedRel.startsWith("src/configs/") || resolvedRel === "src/configs" || resolvedRel.startsWith("configs/") || resolvedRel === "configs";
4968
- const isGlobalError = resolvedRel.startsWith("src/errors/") || resolvedRel === "src/errors" || resolvedRel.startsWith("errors/") || resolvedRel === "errors";
4969
- if (isGlobalError) {
5060
+ if (!targetAbs) {
5061
+ return { isExternal: true, isDiFramework: false, isGlobalConfig };
5062
+ }
5063
+ const normTarget = path26.resolve(targetAbs);
5064
+ const srcConfig = path26.resolve(projectRoot, "src/configs");
5065
+ const rootConfig = path26.resolve(projectRoot, "configs");
5066
+ const isTargetConfig = isGlobalConfig || normTarget === srcConfig || normTarget.startsWith(srcConfig + path26.sep) || normTarget === rootConfig || normTarget.startsWith(rootConfig + path26.sep);
5067
+ const classification = classifyFile(targetAbs, featuresBaseAbs, sharedBaseAbs, errorsBaseAbs);
5068
+ if (classification.moduleType === "error") {
4970
5069
  return {
4971
5070
  isExternal: false,
4972
5071
  isDiFramework: false,
@@ -4974,33 +5073,19 @@ function classifyTarget(specifier, sourceFileAbs, projectRoot) {
4974
5073
  isTargetError: true
4975
5074
  };
4976
5075
  }
4977
- const featMatch = resolvedRel.match(/(?:^|\/)(?:src\/)?features\/([^/]+)\/([^/]+)(?:\/(.*))?$/);
4978
- if (featMatch && featMatch[1] && featMatch[2]) {
4979
- const targetFeature = featMatch[1];
4980
- const targetSubfolder = featMatch[2];
4981
- const rest = featMatch[3] || "";
4982
- let targetLayer;
4983
- if (targetSubfolder === "domain" || targetSubfolder === "errors") {
4984
- targetLayer = "domain";
4985
- } else if (targetSubfolder === "useCases" || targetSubfolder === "usecases") {
4986
- targetLayer = "useCases";
4987
- } else if (targetSubfolder === "services") {
4988
- targetLayer = "services";
4989
- } else if (targetSubfolder === "infrastructure") {
4990
- targetLayer = "infrastructure";
4991
- } else if (targetSubfolder === "pxExpress" || targetSubfolder === "presentation" || targetSubfolder === "handlers" || targetSubfolder.startsWith("px")) {
4992
- targetLayer = "presentation";
4993
- }
4994
- const basePart = rest ? path2.basename(rest) : targetSubfolder;
4995
- const targetFileName = basePart.replace(/\.(js|ts|mjs|cjs)$/, "");
5076
+ if (classification.moduleType === "feature") {
5077
+ const rel = path26.relative(featuresBaseAbs, targetAbs).replace(/\\/g, "/");
5078
+ const parts = rel.split("/").filter(Boolean);
5079
+ const targetSubfolder = parts[1];
5080
+ const targetFileName = path26.basename(targetAbs).replace(/\.(js|ts|mjs|cjs)$/, "");
4996
5081
  const isTargetPort = /^I[A-Z]/.test(targetFileName);
4997
5082
  const isTargetRepo = isTargetPort && targetFileName.includes("Repo");
4998
- const isTargetError = targetSubfolder === "errors" || rest.startsWith("errors/") || rest.includes("/errors/") || targetFileName.endsWith("Error") || targetFileName.endsWith("Errors");
5083
+ const isTargetError = targetSubfolder === "errors" || rel.includes("/errors/") || targetFileName.endsWith("Error") || targetFileName.endsWith("Errors");
4999
5084
  return {
5000
5085
  isExternal: false,
5001
5086
  isDiFramework: false,
5002
- targetFeature,
5003
- targetLayer,
5087
+ targetFeature: classification.moduleName,
5088
+ targetLayer: classification.layer,
5004
5089
  targetSubfolder,
5005
5090
  targetFileName,
5006
5091
  isTargetPort,
@@ -5008,25 +5093,21 @@ function classifyTarget(specifier, sourceFileAbs, projectRoot) {
5008
5093
  isTargetError
5009
5094
  };
5010
5095
  }
5011
- const sharedMatch = resolvedRel.match(/(?:^|\/)(?:src\/)?shared\/([^/]+)(?:\/(.*))?$/);
5012
- if (sharedMatch) {
5013
- const targetSharedModule = sharedMatch[1];
5014
- const sharedRest = sharedMatch[2] || "";
5015
- const isSharedRoot = !sharedRest.includes("/");
5016
- const isSharedPorts = sharedRest.startsWith("ports/") || sharedRest === "ports";
5017
- const isSharedInfra = sharedRest.startsWith("infrastructure/") || sharedRest === "infrastructure";
5018
- const isSharedDomain = sharedRest.startsWith("domain/") || sharedRest === "domain";
5096
+ if (classification.moduleType === "shared") {
5097
+ const targetFileName = path26.basename(targetAbs).replace(/\.(js|ts|mjs|cjs)$/, "");
5098
+ const isTargetError = classification.layer === "domain" && (targetFileName.endsWith("Error") || targetFileName.endsWith("Errors") || targetAbs.includes("/errors/"));
5019
5099
  return {
5020
5100
  isExternal: false,
5021
5101
  isDiFramework: false,
5022
- targetSharedModule,
5023
- isSharedRoot,
5024
- isSharedPorts,
5025
- isSharedInfra,
5026
- isSharedDomain
5102
+ targetSharedModule: classification.moduleName,
5103
+ isSharedRoot: classification.layer === "root",
5104
+ isSharedPorts: classification.layer === "ports",
5105
+ isSharedInfra: classification.layer === "infrastructure",
5106
+ isSharedDomain: classification.layer === "domain",
5107
+ isTargetError
5027
5108
  };
5028
5109
  }
5029
- return { isExternal: true, isDiFramework: false, isGlobalConfig };
5110
+ return { isExternal: true, isDiFramework: false, isGlobalConfig: isTargetConfig };
5030
5111
  }
5031
5112
  function extractImportStatements(content) {
5032
5113
  const statements = [];
@@ -5148,22 +5229,50 @@ var FeatureDependencyGraph = class {
5148
5229
  return dfs(start);
5149
5230
  }
5150
5231
  };
5151
- function discoverAllFeatures(projectRoot) {
5152
- const featuresBase = resolveFeaturesDir(projectRoot);
5153
- if (!fs14.existsSync(featuresBase)) return [];
5154
- const entries = fs14.readdirSync(featuresBase, { withFileTypes: true });
5155
- return entries.filter((e) => e.isDirectory() && !e.name.startsWith(".") && e.name !== "__tests__" && e.name !== "tests").map((e) => ({
5232
+ function discoverAllFeatures(featuresBaseAbs, excludeDirs = []) {
5233
+ const base = featuresBaseAbs;
5234
+ if (!fs17.existsSync(base)) return [];
5235
+ const excludeSet = new Set(excludeDirs.map((d) => path26.resolve(d)));
5236
+ const entries = fs17.readdirSync(base, { withFileTypes: true });
5237
+ return entries.filter((e) => {
5238
+ if (!e.isDirectory()) return false;
5239
+ if (e.name.startsWith(".")) return false;
5240
+ if (["__tests__", "tests", "node_modules", "dist", "coverage", "scratch"].includes(e.name)) {
5241
+ return false;
5242
+ }
5243
+ const resolved = path26.resolve(base, e.name);
5244
+ for (const ex of excludeSet) {
5245
+ if (ex === resolved || ex.startsWith(resolved + path26.sep) || resolved.startsWith(ex + path26.sep)) {
5246
+ return false;
5247
+ }
5248
+ }
5249
+ return true;
5250
+ }).map((e) => ({
5156
5251
  name: e.name,
5157
- dir: path2.join(featuresBase, e.name)
5252
+ dir: path26.join(base, e.name)
5158
5253
  })).sort((a, b) => a.name.localeCompare(b.name));
5159
5254
  }
5160
- function discoverAllShared(projectRoot) {
5161
- const sharedBase = resolveSharedDir(projectRoot);
5162
- if (!fs14.existsSync(sharedBase)) return [];
5163
- const entries = fs14.readdirSync(sharedBase, { withFileTypes: true });
5164
- return entries.filter((e) => e.isDirectory() && !e.name.startsWith(".") && e.name !== "__tests__" && e.name !== "tests").map((e) => ({
5255
+ function discoverAllShared(sharedBaseAbs, excludeDirs = []) {
5256
+ const base = sharedBaseAbs;
5257
+ if (!fs17.existsSync(base)) return [];
5258
+ const excludeSet = new Set(excludeDirs.map((d) => path26.resolve(d)));
5259
+ const entries = fs17.readdirSync(base, { withFileTypes: true });
5260
+ return entries.filter((e) => {
5261
+ if (!e.isDirectory()) return false;
5262
+ if (e.name.startsWith(".")) return false;
5263
+ if (["__tests__", "tests", "node_modules", "dist", "coverage", "scratch"].includes(e.name)) {
5264
+ return false;
5265
+ }
5266
+ const resolved = path26.resolve(base, e.name);
5267
+ for (const ex of excludeSet) {
5268
+ if (ex === resolved || ex.startsWith(resolved + path26.sep) || resolved.startsWith(ex + path26.sep)) {
5269
+ return false;
5270
+ }
5271
+ }
5272
+ return true;
5273
+ }).map((e) => ({
5165
5274
  name: e.name,
5166
- dir: path2.join(sharedBase, e.name)
5275
+ dir: path26.join(base, e.name)
5167
5276
  })).sort((a, b) => a.name.localeCompare(b.name));
5168
5277
  }
5169
5278
  function extractClassMethods(content, className) {
@@ -5319,7 +5428,7 @@ function extractClassMethods(content, className) {
5319
5428
  return methods;
5320
5429
  }
5321
5430
  function checkUseCaseShape(featureName, filePath, relativePath, content, addViolation) {
5322
- const fileName = path2.basename(filePath);
5431
+ const fileName = path26.basename(filePath);
5323
5432
  const lines = content.split(/\r?\n/);
5324
5433
  const classMatch = content.match(/(?:export\s+(?:default\s+)?)?class\s+([A-Za-z0-9_]+)/);
5325
5434
  if (!classMatch) {
@@ -5415,7 +5524,7 @@ private ${m.name}(...) { ... }`
5415
5524
  }
5416
5525
  }
5417
5526
  function checkServiceShape(featureName, filePath, relativePath, content, addViolation) {
5418
- const fileName = path2.basename(filePath);
5527
+ const fileName = path26.basename(filePath);
5419
5528
  const lines = content.split(/\r?\n/);
5420
5529
  const classMatch = content.match(/(?:export\s+(?:default\s+)?)?class\s+([A-Za-z0-9_]+)/);
5421
5530
  if (!classMatch) {
@@ -5514,40 +5623,32 @@ function lintCodebase(options = {}) {
5514
5623
  const startTime = Date.now();
5515
5624
  const projectRoot = options.projectRoot || findProjectRoot(options.targetDir || process.cwd());
5516
5625
  const failFast = !options.complete;
5517
- const lintConfig = loadLintConfig(projectRoot);
5518
- const baseErrorRelative = lintConfig.baseErrorPath || "src/errors/AppError.ts";
5519
- const baseErrorAbs = path2.resolve(projectRoot, baseErrorRelative);
5520
- const featuresBase = resolveFeaturesDir(projectRoot);
5521
- const sharedBase = resolveSharedDir(projectRoot);
5522
- let errorsBase = path2.join(projectRoot, "src/errors");
5523
- if (!fs14.existsSync(errorsBase) && fs14.existsSync(path2.join(projectRoot, "errors"))) {
5524
- errorsBase = path2.join(projectRoot, "errors");
5525
- }
5626
+ const { featuresBase, sharedBase, errorsBase, baseErrorAbs } = resolveLintEnvironment(projectRoot);
5526
5627
  const missingFoundations = [];
5527
- if (!fs14.existsSync(featuresBase)) missingFoundations.push("features/");
5528
- if (!fs14.existsSync(sharedBase)) missingFoundations.push("shared/");
5529
- if (!fs14.existsSync(errorsBase)) missingFoundations.push("errors/");
5628
+ if (!fs17.existsSync(featuresBase)) missingFoundations.push("features/");
5629
+ if (!fs17.existsSync(sharedBase)) missingFoundations.push("shared/");
5630
+ if (!fs17.existsSync(errorsBase)) missingFoundations.push("errors/");
5530
5631
  if (missingFoundations.length > 0) {
5531
5632
  throw new DependencyRuleError(
5532
- `Project Structure Violation: Missing required foundational directories: ${missingFoundations.join(", ")}. Every project must contain 'features/', 'shared/', and 'errors/'.`,
5633
+ `Project Structure Violation: Missing required foundational directories: ${missingFoundations.join(", ")}. Every architecture must contain 'features/', 'shared/', and 'errors/'.`,
5533
5634
  [],
5534
5635
  true
5535
5636
  );
5536
5637
  }
5537
- if (!fs14.existsSync(baseErrorAbs)) {
5638
+ if (!fs17.existsSync(baseErrorAbs)) {
5538
5639
  throw new DependencyRuleError(
5539
- `Project Structure Violation: Base error class not found at '${baseErrorRelative}'. Create this file or update 'baseErrorPath' in mason-lint.config.json.`,
5640
+ `Project Structure Violation: Base error class not found at '${path26.relative(projectRoot, baseErrorAbs).replace(/\\/g, "/")}'. Configure paths.baseError in mason.config.json.`,
5540
5641
  [],
5541
5642
  true
5542
5643
  );
5543
5644
  }
5544
- const baseErrorContent = fs14.readFileSync(baseErrorAbs, "utf-8");
5645
+ const baseErrorContent = fs17.readFileSync(baseErrorAbs, "utf-8");
5545
5646
  const baseClassMatch = baseErrorContent.match(
5546
5647
  /(?:export\s+(?:default\s+)?)?(?:abstract\s+)?class\s+([A-Za-z0-9_]+)/
5547
5648
  );
5548
5649
  const baseErrorClassName = baseClassMatch ? baseClassMatch[1] : "AppError";
5549
- const features = discoverAllFeatures(projectRoot);
5550
- const sharedModules = discoverAllShared(projectRoot);
5650
+ const features = discoverAllFeatures(featuresBase, [sharedBase, errorsBase]);
5651
+ const sharedModules = discoverAllShared(sharedBase, [featuresBase, errorsBase]);
5551
5652
  const errorModule = { name: "global-errors", dir: errorsBase, type: "error" };
5552
5653
  const allModules = [
5553
5654
  ...features.map((f) => ({ ...f, type: "feature" })),
@@ -5590,12 +5691,12 @@ Code: ${v.code}`;
5590
5691
  const allFiles = scanDirFiles(mod.dir, projectRoot);
5591
5692
  modResult.scannedFilesCount = allFiles.length;
5592
5693
  for (const file of allFiles) {
5593
- const relPath = path2.relative(projectRoot, file).replace(/\\/g, "/");
5594
- const { moduleType, moduleName, layer } = classifyFile(file, projectRoot);
5694
+ const relPath = path26.relative(projectRoot, file).replace(/\\/g, "/");
5695
+ const { moduleType, moduleName, layer } = classifyFile(file, featuresBase, sharedBase, errorsBase);
5595
5696
  if (!layer || !moduleType || !moduleName) continue;
5596
- const content = fs14.readFileSync(file, "utf-8");
5697
+ const content = fs17.readFileSync(file, "utf-8");
5597
5698
  const statements = extractImportStatements(content);
5598
- const baseName = path2.basename(file);
5699
+ const baseName = path26.basename(file);
5599
5700
  const isBarrel = baseName === "index.ts" || baseName === "index.js";
5600
5701
  const throwErrorRegex = /\bthrow\s+(?:new\s+)?Error\s*\(/g;
5601
5702
  let throwMatch;
@@ -5614,7 +5715,7 @@ Code: ${v.code}`;
5614
5715
  code: lineCode,
5615
5716
  ruleId: "E3_PLAIN_ERROR_THROW",
5616
5717
  severity: "error",
5617
- advice: `Throwing plain 'Error' is prohibited. You must throw '${baseErrorClassName}' or a domain-specific error class that inherits from it.`,
5718
+ advice: `Throwing plain 'Error' is prohibited. You must throw '${baseErrorClassName}' or a custom error class that inherits from it.`,
5618
5719
  fixExample: {
5619
5720
  bad: lineCode,
5620
5721
  good: `throw new ${baseErrorClassName}("Something went wrong");`
@@ -5622,7 +5723,7 @@ Code: ${v.code}`;
5622
5723
  });
5623
5724
  }
5624
5725
  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");
5625
- const isBaseErrorFile = path2.resolve(file) === path2.resolve(baseErrorAbs);
5726
+ const isBaseErrorFile = path26.resolve(file) === path26.resolve(baseErrorAbs);
5626
5727
  if (isErrorFile && !isBaseErrorFile) {
5627
5728
  const classRegex = /(?:export\s+(?:default\s+)?)?(?:abstract\s+)?class\s+([A-Za-z0-9_]+)(?:<[^>]+>)?(?:\s+extends\s+([A-Za-z0-9_]+))?/g;
5628
5729
  let classMatch;
@@ -5644,7 +5745,7 @@ Code: ${v.code}`;
5644
5745
  code: lineCode,
5645
5746
  ruleId: "E4_MISSING_INHERITANCE",
5646
5747
  severity: "error",
5647
- advice: `Error class '${className}' must extend '${baseErrorClassName}' (or another class that derives from it).`,
5748
+ advice: `Error class '${className}' must extend '${baseErrorClassName}'.`,
5648
5749
  fixExample: {
5649
5750
  bad: lineCode,
5650
5751
  good: `export class ${className} extends ${baseErrorClassName} { ... }`
@@ -5661,7 +5762,7 @@ Code: ${v.code}`;
5661
5762
  code: lineCode,
5662
5763
  ruleId: "E5_NATIVE_ERROR_INHERITANCE",
5663
5764
  severity: "error",
5664
- advice: `Error class '${className}' extends the native 'Error'. It must extend your base error class ('${baseErrorClassName}').`,
5765
+ advice: `Error class '${className}' extends native 'Error'. It must extend your configured base error class ('${baseErrorClassName}').`,
5665
5766
  fixExample: {
5666
5767
  bad: lineCode,
5667
5768
  good: `export class ${className} extends ${baseErrorClassName} { ... }`
@@ -5672,7 +5773,7 @@ Code: ${v.code}`;
5672
5773
  }
5673
5774
  if (moduleType === "error") {
5674
5775
  for (const stmt of statements) {
5675
- const target = classifyTarget(stmt.specifier, file, projectRoot);
5776
+ const target = classifyTarget(stmt.specifier, file, projectRoot, featuresBase, sharedBase, errorsBase);
5676
5777
  if (target.targetFeature) {
5677
5778
  addViolation({
5678
5779
  feature: "global-errors",
@@ -5738,7 +5839,7 @@ Code: ${v.code}`;
5738
5839
  }
5739
5840
  }
5740
5841
  for (const stmt of statements) {
5741
- const target = classifyTarget(stmt.specifier, file, projectRoot);
5842
+ const target = classifyTarget(stmt.specifier, file, projectRoot, featuresBase, sharedBase, errorsBase);
5742
5843
  if (target.targetFeature) {
5743
5844
  addViolation({
5744
5845
  feature: moduleName,
@@ -5868,7 +5969,7 @@ Code: ${v.code}`;
5868
5969
  }
5869
5970
  }
5870
5971
  for (const stmt of statements) {
5871
- const target = classifyTarget(stmt.specifier, file, projectRoot);
5972
+ const target = classifyTarget(stmt.specifier, file, projectRoot, featuresBase, sharedBase, errorsBase);
5872
5973
  if (target.targetFeature && target.targetFeature !== feat.name) {
5873
5974
  const evidence = {
5874
5975
  fromFeature: feat.name,