@solid-stack/mason 1.0.32 → 1.0.33

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.
@@ -8,6 +8,7 @@ export interface TargetInfo {
8
8
  isExternal: boolean;
9
9
  isDiFramework: boolean;
10
10
  isGlobalConfig?: boolean | undefined;
11
+ isGlobalError?: boolean | undefined;
11
12
  targetFeature?: string | undefined;
12
13
  targetLayer?: LayerType | undefined;
13
14
  targetSubfolder?: string | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"lintEngine.d.ts","sourceRoot":"","sources":["../../src/core/lintEngine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"lintEngine.d.ts","sourceRoot":"","sources":["../../src/core/lintEngine.ts"],"names":[],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -219,6 +219,16 @@ function getConfiguredSharedDir(projectRoot, flags) {
219
219
  }
220
220
  return path2__default.default.join(projectRoot, "shared");
221
221
  }
222
+ function loadLintConfig(projectRoot) {
223
+ const configPath = path2__default.default.join(projectRoot, "mason-lint.config.json");
224
+ if (fs4__default.default.existsSync(configPath)) {
225
+ try {
226
+ return JSON.parse(fs4__default.default.readFileSync(configPath, "utf-8"));
227
+ } catch {
228
+ }
229
+ }
230
+ return { baseErrorPath: "src/errors/AppError.ts" };
231
+ }
222
232
 
223
233
  // src/utils/project.ts
224
234
  function findProjectRoot(startDir = process.cwd()) {
@@ -4946,6 +4956,15 @@ function classifyFile(fullPath, projectRoot) {
4946
4956
  }
4947
4957
  return { moduleType: "shared", moduleName, feature: moduleName, layer };
4948
4958
  }
4959
+ const errorMatch = rel.match(/(?:^|\/)(?:src\/)?errors(?:\/(.*))?$/);
4960
+ if (errorMatch) {
4961
+ return {
4962
+ moduleType: "error",
4963
+ moduleName: "global-errors",
4964
+ feature: "global-errors",
4965
+ layer: "domain"
4966
+ };
4967
+ }
4949
4968
  return {};
4950
4969
  }
4951
4970
  function classifyTarget(specifier, sourceFileAbs, projectRoot) {
@@ -4971,15 +4990,28 @@ function classifyTarget(specifier, sourceFileAbs, projectRoot) {
4971
4990
  resolvedRel = specifier.replace(/^[@~]\//, "src/");
4972
4991
  } else if (specifier === "@configs" || specifier.startsWith("@configs/")) {
4973
4992
  resolvedRel = "src/" + specifier.slice(1);
4993
+ } else if (specifier.startsWith("@/errors/") || specifier.startsWith("~/errors/") || specifier === "@/errors" || specifier === "~/errors") {
4994
+ resolvedRel = specifier.replace(/^[@~]\//, "src/");
4995
+ } else if (specifier === "@errors" || specifier.startsWith("@errors/")) {
4996
+ resolvedRel = "src/" + specifier.slice(1);
4974
4997
  } else if (specifier.startsWith("@/") || specifier.startsWith("~/")) {
4975
4998
  resolvedRel = "src/" + specifier.slice(2);
4976
- } else if (specifier.startsWith("features/") || specifier.startsWith("shared/") || specifier.startsWith("configs/") || specifier === "configs") {
4999
+ } else if (specifier.startsWith("features/") || specifier.startsWith("shared/") || specifier.startsWith("configs/") || specifier === "configs" || specifier.startsWith("errors/") || specifier === "errors") {
4977
5000
  resolvedRel = specifier;
4978
5001
  }
4979
5002
  if (!resolvedRel) {
4980
5003
  return { isExternal: true, isDiFramework: false };
4981
5004
  }
4982
5005
  const isGlobalConfig = resolvedRel.startsWith("src/configs/") || resolvedRel === "src/configs" || resolvedRel.startsWith("configs/") || resolvedRel === "configs";
5006
+ const isGlobalError = resolvedRel.startsWith("src/errors/") || resolvedRel === "src/errors" || resolvedRel.startsWith("errors/") || resolvedRel === "errors";
5007
+ if (isGlobalError) {
5008
+ return {
5009
+ isExternal: false,
5010
+ isDiFramework: false,
5011
+ isGlobalError: true,
5012
+ isTargetError: true
5013
+ };
5014
+ }
4983
5015
  const featMatch = resolvedRel.match(/(?:^|\/)(?:src\/)?features\/([^/]+)\/([^/]+)(?:\/(.*))?$/);
4984
5016
  if (featMatch && featMatch[1] && featMatch[2]) {
4985
5017
  const targetFeature = featMatch[1];
@@ -5520,11 +5552,45 @@ function lintCodebase(options = {}) {
5520
5552
  const startTime = Date.now();
5521
5553
  const projectRoot = options.projectRoot || findProjectRoot(options.targetDir || process.cwd());
5522
5554
  const failFast = !options.complete;
5555
+ const lintConfig = loadLintConfig(projectRoot);
5556
+ const baseErrorRelative = lintConfig.baseErrorPath || "src/errors/AppError.ts";
5557
+ const baseErrorAbs = path2__default.default.resolve(projectRoot, baseErrorRelative);
5558
+ const featuresBase = resolveFeaturesDir(projectRoot);
5559
+ const sharedBase = resolveSharedDir(projectRoot);
5560
+ let errorsBase = path2__default.default.join(projectRoot, "src/errors");
5561
+ if (!fs4__default.default.existsSync(errorsBase) && fs4__default.default.existsSync(path2__default.default.join(projectRoot, "errors"))) {
5562
+ errorsBase = path2__default.default.join(projectRoot, "errors");
5563
+ }
5564
+ const missingFoundations = [];
5565
+ if (!fs4__default.default.existsSync(featuresBase)) missingFoundations.push("features/");
5566
+ if (!fs4__default.default.existsSync(sharedBase)) missingFoundations.push("shared/");
5567
+ if (!fs4__default.default.existsSync(errorsBase)) missingFoundations.push("errors/");
5568
+ if (missingFoundations.length > 0) {
5569
+ throw new DependencyRuleError(
5570
+ `Project Structure Violation: Missing required foundational directories: ${missingFoundations.join(", ")}. Every project must contain 'features/', 'shared/', and 'errors/'.`,
5571
+ [],
5572
+ true
5573
+ );
5574
+ }
5575
+ if (!fs4__default.default.existsSync(baseErrorAbs)) {
5576
+ throw new DependencyRuleError(
5577
+ `Project Structure Violation: Base error class not found at '${baseErrorRelative}'. Create this file or update 'baseErrorPath' in mason-lint.config.json.`,
5578
+ [],
5579
+ true
5580
+ );
5581
+ }
5582
+ const baseErrorContent = fs4__default.default.readFileSync(baseErrorAbs, "utf-8");
5583
+ const baseClassMatch = baseErrorContent.match(
5584
+ /(?:export\s+(?:default\s+)?)?(?:abstract\s+)?class\s+([A-Za-z0-9_]+)/
5585
+ );
5586
+ const baseErrorClassName = baseClassMatch ? baseClassMatch[1] : "AppError";
5523
5587
  const features = discoverAllFeatures(projectRoot);
5524
5588
  const sharedModules = discoverAllShared(projectRoot);
5589
+ const errorModule = { name: "global-errors", dir: errorsBase, type: "error" };
5525
5590
  const allModules = [
5526
5591
  ...features.map((f) => ({ ...f, type: "feature" })),
5527
- ...sharedModules.map((s) => ({ ...s, type: "shared" }))
5592
+ ...sharedModules.map((s) => ({ ...s, type: "shared" })),
5593
+ errorModule
5528
5594
  ];
5529
5595
  const graph = new FeatureDependencyGraph();
5530
5596
  const allViolations = [];
@@ -5554,7 +5620,7 @@ Code: ${v.code}`;
5554
5620
  scannedFilesCount: 0,
5555
5621
  passed: true,
5556
5622
  violations: [],
5557
- layersChecked: mod.type === "feature" ? ["domain", "useCases", "services", "infrastructure", "presentation"] : ["domain", "ports", "infrastructure", "root"]
5623
+ layersChecked: mod.type === "feature" ? ["domain", "useCases", "services", "infrastructure", "presentation"] : mod.type === "shared" ? ["domain", "ports", "infrastructure", "root"] : ["domain"]
5558
5624
  });
5559
5625
  }
5560
5626
  for (const mod of allModules) {
@@ -5569,6 +5635,121 @@ Code: ${v.code}`;
5569
5635
  const statements = extractImportStatements(content);
5570
5636
  const baseName = path2__default.default.basename(file);
5571
5637
  const isBarrel = baseName === "index.ts" || baseName === "index.js";
5638
+ const throwErrorRegex = /\bthrow\s+(?:new\s+)?Error\s*\(/g;
5639
+ let throwMatch;
5640
+ while ((throwMatch = throwErrorRegex.exec(content)) !== null) {
5641
+ const charIndex = throwMatch.index;
5642
+ const lineNum = content.substring(0, charIndex).split("\n").length;
5643
+ const lineCode = content.split(/\r?\n/)[lineNum - 1]?.trim() || throwMatch[0];
5644
+ if (lineCode.startsWith("//")) continue;
5645
+ addViolation({
5646
+ feature: moduleName,
5647
+ layer,
5648
+ file,
5649
+ relativePath: relPath,
5650
+ line: lineNum,
5651
+ category: "Plain Error Throw Violation",
5652
+ code: lineCode,
5653
+ ruleId: "E3_PLAIN_ERROR_THROW",
5654
+ severity: "error",
5655
+ advice: `Throwing plain 'Error' is prohibited. You must throw '${baseErrorClassName}' or a domain-specific error class that inherits from it.`,
5656
+ fixExample: {
5657
+ bad: lineCode,
5658
+ good: `throw new ${baseErrorClassName}("Something went wrong");`
5659
+ }
5660
+ });
5661
+ }
5662
+ 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");
5663
+ const isBaseErrorFile = path2__default.default.resolve(file) === path2__default.default.resolve(baseErrorAbs);
5664
+ if (isErrorFile && !isBaseErrorFile) {
5665
+ const classRegex = /(?:export\s+(?:default\s+)?)?(?:abstract\s+)?class\s+([A-Za-z0-9_]+)(?:<[^>]+>)?(?:\s+extends\s+([A-Za-z0-9_]+))?/g;
5666
+ let classMatch;
5667
+ while ((classMatch = classRegex.exec(content)) !== null) {
5668
+ const className = classMatch[1];
5669
+ const extendsName = classMatch[2];
5670
+ const charIndex = classMatch.index;
5671
+ const lineNum = content.substring(0, charIndex).split("\n").length;
5672
+ const lineCode = content.split(/\r?\n/)[lineNum - 1]?.trim() || classMatch[0];
5673
+ if (lineCode.startsWith("//")) continue;
5674
+ if (!extendsName) {
5675
+ addViolation({
5676
+ feature: moduleName,
5677
+ layer,
5678
+ file,
5679
+ relativePath: relPath,
5680
+ line: lineNum,
5681
+ category: "Error Inheritance Violation",
5682
+ code: lineCode,
5683
+ ruleId: "E4_MISSING_INHERITANCE",
5684
+ severity: "error",
5685
+ advice: `Error class '${className}' must extend '${baseErrorClassName}' (or another class that derives from it).`,
5686
+ fixExample: {
5687
+ bad: lineCode,
5688
+ good: `export class ${className} extends ${baseErrorClassName} { ... }`
5689
+ }
5690
+ });
5691
+ } else if (extendsName === "Error") {
5692
+ addViolation({
5693
+ feature: moduleName,
5694
+ layer,
5695
+ file,
5696
+ relativePath: relPath,
5697
+ line: lineNum,
5698
+ category: "Error Inheritance Violation",
5699
+ code: lineCode,
5700
+ ruleId: "E5_NATIVE_ERROR_INHERITANCE",
5701
+ severity: "error",
5702
+ advice: `Error class '${className}' extends the native 'Error'. It must extend your base error class ('${baseErrorClassName}').`,
5703
+ fixExample: {
5704
+ bad: lineCode,
5705
+ good: `export class ${className} extends ${baseErrorClassName} { ... }`
5706
+ }
5707
+ });
5708
+ }
5709
+ }
5710
+ }
5711
+ if (moduleType === "error") {
5712
+ for (const stmt of statements) {
5713
+ const target = classifyTarget(stmt.specifier, file, projectRoot);
5714
+ if (target.targetFeature) {
5715
+ addViolation({
5716
+ feature: "global-errors",
5717
+ layer: "domain",
5718
+ file,
5719
+ relativePath: relPath,
5720
+ line: stmt.line,
5721
+ category: "Global Error Purity Violation",
5722
+ code: stmt.rawCode,
5723
+ ruleId: "E1_FEATURE_DEPENDENCY",
5724
+ severity: "error",
5725
+ advice: `Global errors must not depend on features ('${target.targetFeature}'). Global errors represent pure domain or system states.`,
5726
+ fixExample: {
5727
+ bad: stmt.rawCode,
5728
+ good: "// Global errors must not reference specific features. Keep error types pure."
5729
+ }
5730
+ });
5731
+ }
5732
+ if (target.targetSharedModule && !target.isSharedDomain) {
5733
+ addViolation({
5734
+ feature: "global-errors",
5735
+ layer: "domain",
5736
+ file,
5737
+ relativePath: relPath,
5738
+ line: stmt.line,
5739
+ category: "Global Error Purity Violation",
5740
+ code: stmt.rawCode,
5741
+ ruleId: "E2_SHARED_NON_DOMAIN",
5742
+ severity: "error",
5743
+ advice: `Global errors can only depend on shared domain elements (e.g., value objects). They cannot depend on shared ports or infrastructure.`,
5744
+ fixExample: {
5745
+ bad: stmt.rawCode,
5746
+ good: "// Depend only on pure domain types from shared modules."
5747
+ }
5748
+ });
5749
+ }
5750
+ }
5751
+ continue;
5752
+ }
5572
5753
  if (moduleType === "shared") {
5573
5754
  if (layer === "domain") {
5574
5755
  const lines = content.split(/\r?\n/);
@@ -6658,6 +6839,7 @@ exports.listExistingFeatures = listExistingFeatures;
6658
6839
  exports.listExistingShared = listExistingShared;
6659
6840
  exports.listUseCases = listUseCases;
6660
6841
  exports.loadInterfaceHierarchy = loadInterfaceHierarchy;
6842
+ exports.loadLintConfig = loadLintConfig;
6661
6843
  exports.loadMasonConfig = loadMasonConfig;
6662
6844
  exports.loadTemplate = loadTemplate;
6663
6845
  exports.normalizeRegistryUrl = normalizeRegistryUrl;