@solid-stack/mason 1.0.34 → 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
@@ -189,37 +189,6 @@ function getConfiguredSharedDir(projectRoot, flags) {
189
189
  }
190
190
  return path26.join(projectRoot, "shared");
191
191
  }
192
- function loadLintConfig(projectRoot) {
193
- const configPath = path26.join(projectRoot, "mason-lint.config.json");
194
- if (fs17.existsSync(configPath)) {
195
- try {
196
- return JSON.parse(fs17.readFileSync(configPath, "utf-8"));
197
- } catch {
198
- }
199
- }
200
- return {};
201
- }
202
- function getResolvedLintPaths(projectRoot, config) {
203
- const masonConfig = loadMasonConfig(projectRoot);
204
- const configuredFeatures = config.paths?.features ?? masonConfig?.paths?.features;
205
- const configuredShared = config.paths?.shared ?? masonConfig?.paths?.shared;
206
- const configuredErrors = config.paths?.errors;
207
- const resolveBase = (configuredPath, defaultSrc, defaultRoot) => {
208
- if (configuredPath !== void 0) {
209
- return path26.resolve(projectRoot, configuredPath);
210
- }
211
- const srcPath = path26.join(projectRoot, defaultSrc);
212
- if (fs17.existsSync(srcPath)) return srcPath;
213
- const rootPath = path26.join(projectRoot, defaultRoot);
214
- if (fs17.existsSync(rootPath)) return rootPath;
215
- return srcPath;
216
- };
217
- return {
218
- featuresBase: resolveBase(configuredFeatures, "src/features", "features"),
219
- sharedBase: resolveBase(configuredShared, "src/shared", "shared"),
220
- errorsBase: resolveBase(configuredErrors, "src/errors", "errors")
221
- };
222
- }
223
192
 
224
193
  // src/utils/project.ts
225
194
  function findProjectRoot(startDir = process.cwd()) {
@@ -4905,19 +4874,43 @@ function scanDirFiles(dir, projectRoot) {
4905
4874
  }
4906
4875
  return files;
4907
4876
  }
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
+ }
4908
4899
  function classifyFile(fullPathAbs, featuresBaseAbs, sharedBaseAbs, errorsBaseAbs) {
4909
4900
  if (!sharedBaseAbs || !errorsBaseAbs) {
4910
- const paths = getResolvedLintPaths(featuresBaseAbs, loadLintConfig(featuresBaseAbs));
4911
- featuresBaseAbs = paths.featuresBase;
4912
- sharedBaseAbs = paths.sharedBase;
4913
- errorsBaseAbs = paths.errorsBase;
4901
+ const env = resolveLintEnvironment(featuresBaseAbs);
4902
+ featuresBaseAbs = env.featuresBase;
4903
+ sharedBaseAbs = env.sharedBase;
4904
+ errorsBaseAbs = env.errorsBase;
4914
4905
  }
4915
4906
  const normFullPath = path26.resolve(fullPathAbs);
4916
4907
  const normErrorsBase = path26.resolve(errorsBaseAbs);
4917
4908
  const normSharedBase = path26.resolve(sharedBaseAbs);
4918
4909
  const normFeaturesBase = path26.resolve(featuresBaseAbs);
4919
- const relErrors = path26.relative(normErrorsBase, normFullPath).replace(/\\/g, "/");
4920
- if (!relErrors.startsWith("..") && !path26.isAbsolute(relErrors)) {
4910
+ const isUnder = (base, target) => {
4911
+ return target === base || target.startsWith(base + path26.sep);
4912
+ };
4913
+ if (isUnder(normErrorsBase, normFullPath)) {
4921
4914
  return {
4922
4915
  moduleType: "error",
4923
4916
  moduleName: "global-errors",
@@ -4925,26 +4918,26 @@ function classifyFile(fullPathAbs, featuresBaseAbs, sharedBaseAbs, errorsBaseAbs
4925
4918
  layer: "domain"
4926
4919
  };
4927
4920
  }
4928
- const relShared = path26.relative(normSharedBase, normFullPath).replace(/\\/g, "/");
4929
- if (!relShared.startsWith("..") && !path26.isAbsolute(relShared)) {
4930
- const parts = relShared.split("/").filter(Boolean);
4921
+ if (isUnder(normSharedBase, normFullPath)) {
4922
+ const rel = path26.relative(normSharedBase, normFullPath).replace(/\\/g, "/");
4923
+ const parts = rel.split("/").filter(Boolean);
4931
4924
  if (parts.length >= 1) {
4932
4925
  const moduleName = parts[0];
4933
- const rest = parts.slice(1).join("/");
4926
+ const subfolder = parts[1];
4934
4927
  let layer = "root";
4935
- if (rest.startsWith("domain/") || rest === "domain" || rest.startsWith("errors/") || rest === "errors") {
4928
+ if (subfolder === "domain" || subfolder === "errors") {
4936
4929
  layer = "domain";
4937
- } else if (rest.startsWith("ports/") || rest === "ports") {
4930
+ } else if (subfolder === "ports") {
4938
4931
  layer = "ports";
4939
- } else if (rest.startsWith("infrastructure/") || rest === "infrastructure") {
4932
+ } else if (subfolder === "infrastructure") {
4940
4933
  layer = "infrastructure";
4941
4934
  }
4942
4935
  return { moduleType: "shared", moduleName, feature: moduleName, layer };
4943
4936
  }
4944
4937
  }
4945
- const relFeatures = path26.relative(normFeaturesBase, normFullPath).replace(/\\/g, "/");
4946
- if (!relFeatures.startsWith("..") && !path26.isAbsolute(relFeatures)) {
4947
- const parts = relFeatures.split("/").filter(Boolean);
4938
+ if (isUnder(normFeaturesBase, normFullPath)) {
4939
+ const rel = path26.relative(normFeaturesBase, normFullPath).replace(/\\/g, "/");
4940
+ const parts = rel.split("/").filter(Boolean);
4948
4941
  if (parts.length >= 2) {
4949
4942
  const moduleName = parts[0];
4950
4943
  const subfolder = parts[1];
@@ -4957,7 +4950,7 @@ function classifyFile(fullPathAbs, featuresBaseAbs, sharedBaseAbs, errorsBaseAbs
4957
4950
  layer = "services";
4958
4951
  } else if (subfolder === "infrastructure") {
4959
4952
  layer = "infrastructure";
4960
- } else if (subfolder === "pxExpress" || subfolder === "presentation" || subfolder === "handlers" || subfolder.startsWith("px")) {
4953
+ } else if (subfolder.startsWith("px") || subfolder === "presentation" || subfolder === "handlers" || subfolder === "transformers") {
4961
4954
  layer = "presentation";
4962
4955
  }
4963
4956
  return { moduleType: "feature", moduleName, feature: moduleName, layer };
@@ -4986,10 +4979,10 @@ function classifyTarget(specifier, sourceFileAbs, projectRoot, featuresBaseAbs,
4986
4979
  return { isExternal: true, isDiFramework: false };
4987
4980
  }
4988
4981
  if (!featuresBaseAbs || !sharedBaseAbs || !errorsBaseAbs) {
4989
- const paths = getResolvedLintPaths(projectRoot, loadLintConfig(projectRoot));
4990
- featuresBaseAbs = featuresBaseAbs || paths.featuresBase;
4991
- sharedBaseAbs = sharedBaseAbs || paths.sharedBase;
4992
- errorsBaseAbs = errorsBaseAbs || paths.errorsBase;
4982
+ const env = resolveLintEnvironment(projectRoot);
4983
+ featuresBaseAbs = featuresBaseAbs || env.featuresBase;
4984
+ sharedBaseAbs = sharedBaseAbs || env.sharedBase;
4985
+ errorsBaseAbs = errorsBaseAbs || env.errorsBase;
4993
4986
  }
4994
4987
  const isGlobalConfig = specifier === "@configs" || specifier.startsWith("@configs/") || specifier === "@/configs" || specifier.startsWith("@/configs/") || specifier === "~/configs" || specifier.startsWith("~/configs/") || specifier === "configs" || specifier.startsWith("configs/");
4995
4988
  let targetAbs = null;
@@ -5630,24 +5623,21 @@ function lintCodebase(options = {}) {
5630
5623
  const startTime = Date.now();
5631
5624
  const projectRoot = options.projectRoot || findProjectRoot(options.targetDir || process.cwd());
5632
5625
  const failFast = !options.complete;
5633
- const lintConfig = loadLintConfig(projectRoot);
5634
- const { featuresBase, sharedBase, errorsBase } = getResolvedLintPaths(projectRoot, lintConfig);
5626
+ const { featuresBase, sharedBase, errorsBase, baseErrorAbs } = resolveLintEnvironment(projectRoot);
5635
5627
  const missingFoundations = [];
5636
5628
  if (!fs17.existsSync(featuresBase)) missingFoundations.push("features/");
5637
5629
  if (!fs17.existsSync(sharedBase)) missingFoundations.push("shared/");
5638
5630
  if (!fs17.existsSync(errorsBase)) missingFoundations.push("errors/");
5639
5631
  if (missingFoundations.length > 0) {
5640
5632
  throw new DependencyRuleError(
5641
- `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/'.`,
5642
5634
  [],
5643
5635
  true
5644
5636
  );
5645
5637
  }
5646
- const baseErrorRelative = lintConfig.baseErrorPath || path26.relative(projectRoot, path26.join(errorsBase, "AppError.ts")).replace(/\\/g, "/");
5647
- const baseErrorAbs = path26.resolve(projectRoot, baseErrorRelative);
5648
5638
  if (!fs17.existsSync(baseErrorAbs)) {
5649
5639
  throw new DependencyRuleError(
5650
- `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.`,
5651
5641
  [],
5652
5642
  true
5653
5643
  );
@@ -5725,7 +5715,7 @@ Code: ${v.code}`;
5725
5715
  code: lineCode,
5726
5716
  ruleId: "E3_PLAIN_ERROR_THROW",
5727
5717
  severity: "error",
5728
- 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.`,
5729
5719
  fixExample: {
5730
5720
  bad: lineCode,
5731
5721
  good: `throw new ${baseErrorClassName}("Something went wrong");`
@@ -5755,7 +5745,7 @@ Code: ${v.code}`;
5755
5745
  code: lineCode,
5756
5746
  ruleId: "E4_MISSING_INHERITANCE",
5757
5747
  severity: "error",
5758
- advice: `Error class '${className}' must extend '${baseErrorClassName}' (or another class that derives from it).`,
5748
+ advice: `Error class '${className}' must extend '${baseErrorClassName}'.`,
5759
5749
  fixExample: {
5760
5750
  bad: lineCode,
5761
5751
  good: `export class ${className} extends ${baseErrorClassName} { ... }`
@@ -5772,7 +5762,7 @@ Code: ${v.code}`;
5772
5762
  code: lineCode,
5773
5763
  ruleId: "E5_NATIVE_ERROR_INHERITANCE",
5774
5764
  severity: "error",
5775
- 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}').`,
5776
5766
  fixExample: {
5777
5767
  bad: lineCode,
5778
5768
  good: `export class ${className} extends ${baseErrorClassName} { ... }`