@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.
- package/dist/bin.cjs +184 -3
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +184 -3
- package/dist/bin.js.map +1 -1
- package/dist/core/lintEngine.d.ts +1 -0
- package/dist/core/lintEngine.d.ts.map +1 -1
- package/dist/index.cjs +185 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +185 -4
- package/dist/index.js.map +1 -1
- package/dist/types/lint.d.ts +5 -2
- package/dist/types/lint.d.ts.map +1 -1
- package/dist/utils/config.d.ts +5 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -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":"AAEA,OAAO,KAAK,EACV,sBAAsB,EAEtB,yBAAyB,EACzB,SAAS,EACT,WAAW,EACX,WAAW,EAEX,UAAU,EAEV,SAAS,EACV,MAAM,kBAAkB,CAAC;
|
|
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;
|