@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/index.js CHANGED
@@ -191,20 +191,20 @@ function getConfiguredSharedDir(projectRoot, flags) {
191
191
  return path26.join(projectRoot, "shared");
192
192
  }
193
193
  function loadLintConfig(projectRoot) {
194
- const configPath = path26.join(projectRoot, "mason-lint.config.json");
195
- if (fs17.existsSync(configPath)) {
196
- try {
197
- return JSON.parse(fs17.readFileSync(configPath, "utf-8"));
198
- } catch {
199
- }
194
+ const masonConfig = loadMasonConfig(projectRoot);
195
+ if (masonConfig) {
196
+ return {
197
+ baseErrorPath: masonConfig.paths?.baseError,
198
+ paths: masonConfig.paths
199
+ };
200
200
  }
201
201
  return {};
202
202
  }
203
203
  function getResolvedLintPaths(projectRoot, config) {
204
204
  const masonConfig = loadMasonConfig(projectRoot);
205
- const configuredFeatures = config.paths?.features ?? masonConfig?.paths?.features;
206
- const configuredShared = config.paths?.shared ?? masonConfig?.paths?.shared;
207
- const configuredErrors = config.paths?.errors;
205
+ const configuredFeatures = config?.paths?.features ?? masonConfig?.paths?.features;
206
+ const configuredShared = config?.paths?.shared ?? masonConfig?.paths?.shared;
207
+ const configuredErrors = config?.paths?.errors ?? masonConfig?.paths?.errors;
208
208
  const resolveBase = (configuredPath, defaultSrc, defaultRoot) => {
209
209
  if (configuredPath !== void 0) {
210
210
  return path26.resolve(projectRoot, configuredPath);
@@ -4914,19 +4914,43 @@ function scanDirFiles(dir, projectRoot) {
4914
4914
  }
4915
4915
  return files;
4916
4916
  }
4917
+ function resolveLintEnvironment(projectRoot) {
4918
+ const config = loadMasonConfig(projectRoot);
4919
+ const resolveDir = (configured, defaultSrc, defaultRoot) => {
4920
+ if (configured !== void 0) {
4921
+ return path26.resolve(projectRoot, configured);
4922
+ }
4923
+ const srcPath = path26.join(projectRoot, defaultSrc);
4924
+ if (fs17.existsSync(srcPath)) return srcPath;
4925
+ const rootPath = path26.join(projectRoot, defaultRoot);
4926
+ if (fs17.existsSync(rootPath)) return rootPath;
4927
+ return srcPath;
4928
+ };
4929
+ const featuresBase = resolveDir(config?.paths?.features, "src/features", "features");
4930
+ const sharedBase = resolveDir(config?.paths?.shared, "src/shared", "shared");
4931
+ const errorsBase = resolveDir(config?.paths?.errors, "src/errors", "errors");
4932
+ 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";
4933
+ const baseErrorAbs = path26.resolve(
4934
+ projectRoot,
4935
+ config?.paths?.baseError || defaultBaseErrorRelative
4936
+ );
4937
+ return { featuresBase, sharedBase, errorsBase, baseErrorAbs };
4938
+ }
4917
4939
  function classifyFile(fullPathAbs, featuresBaseAbs, sharedBaseAbs, errorsBaseAbs) {
4918
4940
  if (!sharedBaseAbs || !errorsBaseAbs) {
4919
- const paths = getResolvedLintPaths(featuresBaseAbs, loadLintConfig(featuresBaseAbs));
4920
- featuresBaseAbs = paths.featuresBase;
4921
- sharedBaseAbs = paths.sharedBase;
4922
- errorsBaseAbs = paths.errorsBase;
4941
+ const env = resolveLintEnvironment(featuresBaseAbs);
4942
+ featuresBaseAbs = env.featuresBase;
4943
+ sharedBaseAbs = env.sharedBase;
4944
+ errorsBaseAbs = env.errorsBase;
4923
4945
  }
4924
4946
  const normFullPath = path26.resolve(fullPathAbs);
4925
4947
  const normErrorsBase = path26.resolve(errorsBaseAbs);
4926
4948
  const normSharedBase = path26.resolve(sharedBaseAbs);
4927
4949
  const normFeaturesBase = path26.resolve(featuresBaseAbs);
4928
- const relErrors = path26.relative(normErrorsBase, normFullPath).replace(/\\/g, "/");
4929
- if (!relErrors.startsWith("..") && !path26.isAbsolute(relErrors)) {
4950
+ const isUnder = (base, target) => {
4951
+ return target === base || target.startsWith(base + path26.sep);
4952
+ };
4953
+ if (isUnder(normErrorsBase, normFullPath)) {
4930
4954
  return {
4931
4955
  moduleType: "error",
4932
4956
  moduleName: "global-errors",
@@ -4934,26 +4958,26 @@ function classifyFile(fullPathAbs, featuresBaseAbs, sharedBaseAbs, errorsBaseAbs
4934
4958
  layer: "domain"
4935
4959
  };
4936
4960
  }
4937
- const relShared = path26.relative(normSharedBase, normFullPath).replace(/\\/g, "/");
4938
- if (!relShared.startsWith("..") && !path26.isAbsolute(relShared)) {
4939
- const parts = relShared.split("/").filter(Boolean);
4961
+ if (isUnder(normSharedBase, normFullPath)) {
4962
+ const rel = path26.relative(normSharedBase, normFullPath).replace(/\\/g, "/");
4963
+ const parts = rel.split("/").filter(Boolean);
4940
4964
  if (parts.length >= 1) {
4941
4965
  const moduleName = parts[0];
4942
- const rest = parts.slice(1).join("/");
4966
+ const subfolder = parts[1];
4943
4967
  let layer = "root";
4944
- if (rest.startsWith("domain/") || rest === "domain" || rest.startsWith("errors/") || rest === "errors") {
4968
+ if (subfolder === "domain" || subfolder === "errors") {
4945
4969
  layer = "domain";
4946
- } else if (rest.startsWith("ports/") || rest === "ports") {
4970
+ } else if (subfolder === "ports") {
4947
4971
  layer = "ports";
4948
- } else if (rest.startsWith("infrastructure/") || rest === "infrastructure") {
4972
+ } else if (subfolder === "infrastructure") {
4949
4973
  layer = "infrastructure";
4950
4974
  }
4951
4975
  return { moduleType: "shared", moduleName, feature: moduleName, layer };
4952
4976
  }
4953
4977
  }
4954
- const relFeatures = path26.relative(normFeaturesBase, normFullPath).replace(/\\/g, "/");
4955
- if (!relFeatures.startsWith("..") && !path26.isAbsolute(relFeatures)) {
4956
- const parts = relFeatures.split("/").filter(Boolean);
4978
+ if (isUnder(normFeaturesBase, normFullPath)) {
4979
+ const rel = path26.relative(normFeaturesBase, normFullPath).replace(/\\/g, "/");
4980
+ const parts = rel.split("/").filter(Boolean);
4957
4981
  if (parts.length >= 2) {
4958
4982
  const moduleName = parts[0];
4959
4983
  const subfolder = parts[1];
@@ -4966,7 +4990,7 @@ function classifyFile(fullPathAbs, featuresBaseAbs, sharedBaseAbs, errorsBaseAbs
4966
4990
  layer = "services";
4967
4991
  } else if (subfolder === "infrastructure") {
4968
4992
  layer = "infrastructure";
4969
- } else if (subfolder === "pxExpress" || subfolder === "presentation" || subfolder === "handlers" || subfolder.startsWith("px")) {
4993
+ } else if (subfolder.startsWith("px") || subfolder === "presentation" || subfolder === "handlers" || subfolder === "transformers") {
4970
4994
  layer = "presentation";
4971
4995
  }
4972
4996
  return { moduleType: "feature", moduleName, feature: moduleName, layer };
@@ -4995,10 +5019,10 @@ function classifyTarget(specifier, sourceFileAbs, projectRoot, featuresBaseAbs,
4995
5019
  return { isExternal: true, isDiFramework: false };
4996
5020
  }
4997
5021
  if (!featuresBaseAbs || !sharedBaseAbs || !errorsBaseAbs) {
4998
- const paths = getResolvedLintPaths(projectRoot, loadLintConfig(projectRoot));
4999
- featuresBaseAbs = featuresBaseAbs || paths.featuresBase;
5000
- sharedBaseAbs = sharedBaseAbs || paths.sharedBase;
5001
- errorsBaseAbs = errorsBaseAbs || paths.errorsBase;
5022
+ const env = resolveLintEnvironment(projectRoot);
5023
+ featuresBaseAbs = featuresBaseAbs || env.featuresBase;
5024
+ sharedBaseAbs = sharedBaseAbs || env.sharedBase;
5025
+ errorsBaseAbs = errorsBaseAbs || env.errorsBase;
5002
5026
  }
5003
5027
  const isGlobalConfig = specifier === "@configs" || specifier.startsWith("@configs/") || specifier === "@/configs" || specifier.startsWith("@/configs/") || specifier === "~/configs" || specifier.startsWith("~/configs/") || specifier === "configs" || specifier.startsWith("configs/");
5004
5028
  let targetAbs = null;
@@ -5639,24 +5663,21 @@ function lintCodebase(options = {}) {
5639
5663
  const startTime = Date.now();
5640
5664
  const projectRoot = options.projectRoot || findProjectRoot(options.targetDir || process.cwd());
5641
5665
  const failFast = !options.complete;
5642
- const lintConfig = loadLintConfig(projectRoot);
5643
- const { featuresBase, sharedBase, errorsBase } = getResolvedLintPaths(projectRoot, lintConfig);
5666
+ const { featuresBase, sharedBase, errorsBase, baseErrorAbs } = resolveLintEnvironment(projectRoot);
5644
5667
  const missingFoundations = [];
5645
5668
  if (!fs17.existsSync(featuresBase)) missingFoundations.push("features/");
5646
5669
  if (!fs17.existsSync(sharedBase)) missingFoundations.push("shared/");
5647
5670
  if (!fs17.existsSync(errorsBase)) missingFoundations.push("errors/");
5648
5671
  if (missingFoundations.length > 0) {
5649
5672
  throw new DependencyRuleError(
5650
- `Project Structure Violation: Missing required foundational directories: ${missingFoundations.join(", ")}. Every project must contain 'features/', 'shared/', and 'errors/'.`,
5673
+ `Project Structure Violation: Missing required foundational directories: ${missingFoundations.join(", ")}. Every architecture must contain 'features/', 'shared/', and 'errors/'.`,
5651
5674
  [],
5652
5675
  true
5653
5676
  );
5654
5677
  }
5655
- const baseErrorRelative = lintConfig.baseErrorPath || path26.relative(projectRoot, path26.join(errorsBase, "AppError.ts")).replace(/\\/g, "/");
5656
- const baseErrorAbs = path26.resolve(projectRoot, baseErrorRelative);
5657
5678
  if (!fs17.existsSync(baseErrorAbs)) {
5658
5679
  throw new DependencyRuleError(
5659
- `Project Structure Violation: Base error class not found at '${baseErrorRelative}'. Create this file or update 'baseErrorPath' in mason-lint.config.json.`,
5680
+ `Project Structure Violation: Base error class not found at '${path26.relative(projectRoot, baseErrorAbs).replace(/\\/g, "/")}'. Configure paths.baseError in mason.config.json.`,
5660
5681
  [],
5661
5682
  true
5662
5683
  );
@@ -5734,7 +5755,7 @@ Code: ${v.code}`;
5734
5755
  code: lineCode,
5735
5756
  ruleId: "E3_PLAIN_ERROR_THROW",
5736
5757
  severity: "error",
5737
- advice: `Throwing plain 'Error' is prohibited. You must throw '${baseErrorClassName}' or a domain-specific error class that inherits from it.`,
5758
+ advice: `Throwing plain 'Error' is prohibited. You must throw '${baseErrorClassName}' or a custom error class that inherits from it.`,
5738
5759
  fixExample: {
5739
5760
  bad: lineCode,
5740
5761
  good: `throw new ${baseErrorClassName}("Something went wrong");`
@@ -5764,7 +5785,7 @@ Code: ${v.code}`;
5764
5785
  code: lineCode,
5765
5786
  ruleId: "E4_MISSING_INHERITANCE",
5766
5787
  severity: "error",
5767
- advice: `Error class '${className}' must extend '${baseErrorClassName}' (or another class that derives from it).`,
5788
+ advice: `Error class '${className}' must extend '${baseErrorClassName}'.`,
5768
5789
  fixExample: {
5769
5790
  bad: lineCode,
5770
5791
  good: `export class ${className} extends ${baseErrorClassName} { ... }`
@@ -5781,7 +5802,7 @@ Code: ${v.code}`;
5781
5802
  code: lineCode,
5782
5803
  ruleId: "E5_NATIVE_ERROR_INHERITANCE",
5783
5804
  severity: "error",
5784
- advice: `Error class '${className}' extends the native 'Error'. It must extend your base error class ('${baseErrorClassName}').`,
5805
+ advice: `Error class '${className}' extends native 'Error'. It must extend your configured base error class ('${baseErrorClassName}').`,
5785
5806
  fixExample: {
5786
5807
  bad: lineCode,
5787
5808
  good: `export class ${className} extends ${baseErrorClassName} { ... }`