@nielspeter/eess-ts 0.1.0
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/LICENSE +21 -0
- package/README.md +364 -0
- package/dist/builders/call-rule-builder.d.ts +199 -0
- package/dist/builders/call-rule-builder.d.ts.map +1 -0
- package/dist/builders/call-rule-builder.js +254 -0
- package/dist/builders/call-rule-builder.js.map +1 -0
- package/dist/builders/class-rule-builder.d.ts +136 -0
- package/dist/builders/class-rule-builder.d.ts.map +1 -0
- package/dist/builders/class-rule-builder.js +253 -0
- package/dist/builders/class-rule-builder.js.map +1 -0
- package/dist/builders/cross-layer-builder.d.ts +96 -0
- package/dist/builders/cross-layer-builder.d.ts.map +1 -0
- package/dist/builders/cross-layer-builder.js +172 -0
- package/dist/builders/cross-layer-builder.js.map +1 -0
- package/dist/builders/function-rule-builder.d.ts +198 -0
- package/dist/builders/function-rule-builder.d.ts.map +1 -0
- package/dist/builders/function-rule-builder.js +287 -0
- package/dist/builders/function-rule-builder.js.map +1 -0
- package/dist/builders/jsx-rule-builder.d.ts +113 -0
- package/dist/builders/jsx-rule-builder.d.ts.map +1 -0
- package/dist/builders/jsx-rule-builder.js +150 -0
- package/dist/builders/jsx-rule-builder.js.map +1 -0
- package/dist/builders/module-rule-builder.d.ts +159 -0
- package/dist/builders/module-rule-builder.d.ts.map +1 -0
- package/dist/builders/module-rule-builder.js +237 -0
- package/dist/builders/module-rule-builder.js.map +1 -0
- package/dist/builders/scoped-function-rule-builder.d.ts +21 -0
- package/dist/builders/scoped-function-rule-builder.d.ts.map +1 -0
- package/dist/builders/scoped-function-rule-builder.js +26 -0
- package/dist/builders/scoped-function-rule-builder.js.map +1 -0
- package/dist/builders/slice-rule-builder.d.ts +85 -0
- package/dist/builders/slice-rule-builder.d.ts.map +1 -0
- package/dist/builders/slice-rule-builder.js +134 -0
- package/dist/builders/slice-rule-builder.js.map +1 -0
- package/dist/builders/type-rule-builder.d.ts +103 -0
- package/dist/builders/type-rule-builder.d.ts.map +1 -0
- package/dist/builders/type-rule-builder.js +170 -0
- package/dist/builders/type-rule-builder.js.map +1 -0
- package/dist/cli/bin.d.ts +3 -0
- package/dist/cli/bin.d.ts.map +1 -0
- package/dist/cli/bin.js +4 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/commands/baseline.d.ts +11 -0
- package/dist/cli/commands/baseline.d.ts.map +1 -0
- package/dist/cli/commands/baseline.js +16 -0
- package/dist/cli/commands/baseline.js.map +1 -0
- package/dist/cli/commands/check.d.ts +21 -0
- package/dist/cli/commands/check.d.ts.map +1 -0
- package/dist/cli/commands/check.js +94 -0
- package/dist/cli/commands/check.js.map +1 -0
- package/dist/cli/commands/explain.d.ts +9 -0
- package/dist/cli/commands/explain.d.ts.map +1 -0
- package/dist/cli/commands/explain.js +49 -0
- package/dist/cli/commands/explain.js.map +1 -0
- package/dist/cli/config.d.ts +31 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +20 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/index.d.ts +21 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +168 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/load-rules.d.ts +20 -0
- package/dist/cli/load-rules.d.ts.map +1 -0
- package/dist/cli/load-rules.js +97 -0
- package/dist/cli/load-rules.js.map +1 -0
- package/dist/cli/resolve-config.d.ts +11 -0
- package/dist/cli/resolve-config.d.ts.map +1 -0
- package/dist/cli/resolve-config.js +61 -0
- package/dist/cli/resolve-config.js.map +1 -0
- package/dist/cli/watch.d.ts +49 -0
- package/dist/cli/watch.d.ts.map +1 -0
- package/dist/cli/watch.js +138 -0
- package/dist/cli/watch.js.map +1 -0
- package/dist/conditions/body-analysis-function.d.ts +23 -0
- package/dist/conditions/body-analysis-function.d.ts.map +1 -0
- package/dist/conditions/body-analysis-function.js +103 -0
- package/dist/conditions/body-analysis-function.js.map +1 -0
- package/dist/conditions/body-analysis-module.d.ts +27 -0
- package/dist/conditions/body-analysis-module.d.ts.map +1 -0
- package/dist/conditions/body-analysis-module.js +99 -0
- package/dist/conditions/body-analysis-module.js.map +1 -0
- package/dist/conditions/body-analysis.d.ts +34 -0
- package/dist/conditions/body-analysis.d.ts.map +1 -0
- package/dist/conditions/body-analysis.js +95 -0
- package/dist/conditions/body-analysis.js.map +1 -0
- package/dist/conditions/call.d.ts +62 -0
- package/dist/conditions/call.d.ts.map +1 -0
- package/dist/conditions/call.js +267 -0
- package/dist/conditions/call.js.map +1 -0
- package/dist/conditions/catch-analysis.d.ts +31 -0
- package/dist/conditions/catch-analysis.d.ts.map +1 -0
- package/dist/conditions/catch-analysis.js +78 -0
- package/dist/conditions/catch-analysis.js.map +1 -0
- package/dist/conditions/class.d.ts +33 -0
- package/dist/conditions/class.d.ts.map +1 -0
- package/dist/conditions/class.js +110 -0
- package/dist/conditions/class.js.map +1 -0
- package/dist/conditions/cross-layer.d.ts +28 -0
- package/dist/conditions/cross-layer.d.ts.map +1 -0
- package/dist/conditions/cross-layer.js +105 -0
- package/dist/conditions/cross-layer.js.map +1 -0
- package/dist/conditions/dependency.d.ts +73 -0
- package/dist/conditions/dependency.d.ts.map +1 -0
- package/dist/conditions/dependency.js +177 -0
- package/dist/conditions/dependency.js.map +1 -0
- package/dist/conditions/exports.d.ts +33 -0
- package/dist/conditions/exports.d.ts.map +1 -0
- package/dist/conditions/exports.js +101 -0
- package/dist/conditions/exports.js.map +1 -0
- package/dist/conditions/function.d.ts +79 -0
- package/dist/conditions/function.d.ts.map +1 -0
- package/dist/conditions/function.js +167 -0
- package/dist/conditions/function.js.map +1 -0
- package/dist/conditions/helpers.d.ts +14 -0
- package/dist/conditions/helpers.d.ts.map +1 -0
- package/dist/conditions/helpers.js +26 -0
- package/dist/conditions/helpers.js.map +1 -0
- package/dist/conditions/jsx.d.ts +40 -0
- package/dist/conditions/jsx.d.ts.map +1 -0
- package/dist/conditions/jsx.js +133 -0
- package/dist/conditions/jsx.js.map +1 -0
- package/dist/conditions/members.d.ts +74 -0
- package/dist/conditions/members.d.ts.map +1 -0
- package/dist/conditions/members.js +224 -0
- package/dist/conditions/members.js.map +1 -0
- package/dist/conditions/pattern.d.ts +20 -0
- package/dist/conditions/pattern.d.ts.map +1 -0
- package/dist/conditions/pattern.js +108 -0
- package/dist/conditions/pattern.js.map +1 -0
- package/dist/conditions/reverse-dependency.d.ts +28 -0
- package/dist/conditions/reverse-dependency.d.ts.map +1 -0
- package/dist/conditions/reverse-dependency.js +275 -0
- package/dist/conditions/reverse-dependency.js.map +1 -0
- package/dist/conditions/slice.d.ts +49 -0
- package/dist/conditions/slice.d.ts.map +1 -0
- package/dist/conditions/slice.js +153 -0
- package/dist/conditions/slice.js.map +1 -0
- package/dist/conditions/structural.d.ts +58 -0
- package/dist/conditions/structural.d.ts.map +1 -0
- package/dist/conditions/structural.js +102 -0
- package/dist/conditions/structural.js.map +1 -0
- package/dist/conditions/type-level.d.ts +29 -0
- package/dist/conditions/type-level.d.ts.map +1 -0
- package/dist/conditions/type-level.js +48 -0
- package/dist/conditions/type-level.js.map +1 -0
- package/dist/core/import-options.d.ts +32 -0
- package/dist/core/import-options.d.ts.map +1 -0
- package/dist/core/import-options.js +29 -0
- package/dist/core/import-options.js.map +1 -0
- package/dist/core/module-dependencies.d.ts +28 -0
- package/dist/core/module-dependencies.d.ts.map +1 -0
- package/dist/core/module-dependencies.js +35 -0
- package/dist/core/module-dependencies.js.map +1 -0
- package/dist/core/pair-condition.d.ts +10 -0
- package/dist/core/pair-condition.d.ts.map +1 -0
- package/dist/core/pair-condition.js +2 -0
- package/dist/core/pair-condition.js.map +1 -0
- package/dist/core/project.d.ts +68 -0
- package/dist/core/project.d.ts.map +1 -0
- package/dist/core/project.js +127 -0
- package/dist/core/project.js.map +1 -0
- package/dist/core/type-matcher.d.ts +10 -0
- package/dist/core/type-matcher.d.ts.map +1 -0
- package/dist/core/type-matcher.js +2 -0
- package/dist/core/type-matcher.js.map +1 -0
- package/dist/core/violation.d.ts +38 -0
- package/dist/core/violation.d.ts.map +1 -0
- package/dist/core/violation.js +130 -0
- package/dist/core/violation.js.map +1 -0
- package/dist/graphql/index.d.ts +76 -0
- package/dist/graphql/index.d.ts.map +1 -0
- package/dist/graphql/index.js +108 -0
- package/dist/graphql/index.js.map +1 -0
- package/dist/graphql/resolver-rule-builder.d.ts +75 -0
- package/dist/graphql/resolver-rule-builder.d.ts.map +1 -0
- package/dist/graphql/resolver-rule-builder.js +146 -0
- package/dist/graphql/resolver-rule-builder.js.map +1 -0
- package/dist/graphql/schema-conditions.d.ts +31 -0
- package/dist/graphql/schema-conditions.d.ts.map +1 -0
- package/dist/graphql/schema-conditions.js +119 -0
- package/dist/graphql/schema-conditions.js.map +1 -0
- package/dist/graphql/schema-loader.d.ts +75 -0
- package/dist/graphql/schema-loader.d.ts.map +1 -0
- package/dist/graphql/schema-loader.js +113 -0
- package/dist/graphql/schema-loader.js.map +1 -0
- package/dist/graphql/schema-predicates.d.ts +42 -0
- package/dist/graphql/schema-predicates.d.ts.map +1 -0
- package/dist/graphql/schema-predicates.js +74 -0
- package/dist/graphql/schema-predicates.js.map +1 -0
- package/dist/graphql/schema-rule-builder.d.ts +74 -0
- package/dist/graphql/schema-rule-builder.d.ts.map +1 -0
- package/dist/graphql/schema-rule-builder.js +188 -0
- package/dist/graphql/schema-rule-builder.js.map +1 -0
- package/dist/helpers/body-traversal.d.ts +58 -0
- package/dist/helpers/body-traversal.d.ts.map +1 -0
- package/dist/helpers/body-traversal.js +180 -0
- package/dist/helpers/body-traversal.js.map +1 -0
- package/dist/helpers/callback-extractor.d.ts +28 -0
- package/dist/helpers/callback-extractor.d.ts.map +1 -0
- package/dist/helpers/callback-extractor.js +159 -0
- package/dist/helpers/callback-extractor.js.map +1 -0
- package/dist/helpers/complexity.d.ts +26 -0
- package/dist/helpers/complexity.d.ts.map +1 -0
- package/dist/helpers/complexity.js +64 -0
- package/dist/helpers/complexity.js.map +1 -0
- package/dist/helpers/matchers.d.ts +206 -0
- package/dist/helpers/matchers.d.ts.map +1 -0
- package/dist/helpers/matchers.js +470 -0
- package/dist/helpers/matchers.js.map +1 -0
- package/dist/helpers/pattern.d.ts +37 -0
- package/dist/helpers/pattern.d.ts.map +1 -0
- package/dist/helpers/pattern.js +22 -0
- package/dist/helpers/pattern.js.map +1 -0
- package/dist/helpers/slice-graph.d.ts +32 -0
- package/dist/helpers/slice-graph.d.ts.map +1 -0
- package/dist/helpers/slice-graph.js +89 -0
- package/dist/helpers/slice-graph.js.map +1 -0
- package/dist/helpers/tarjan.d.ts +21 -0
- package/dist/helpers/tarjan.d.ts.map +1 -0
- package/dist/helpers/tarjan.js +71 -0
- package/dist/helpers/tarjan.js.map +1 -0
- package/dist/helpers/type-matchers.d.ts +67 -0
- package/dist/helpers/type-matchers.d.ts.map +1 -0
- package/dist/helpers/type-matchers.js +108 -0
- package/dist/helpers/type-matchers.js.map +1 -0
- package/dist/helpers/within.d.ts +41 -0
- package/dist/helpers/within.d.ts.map +1 -0
- package/dist/helpers/within.js +32 -0
- package/dist/helpers/within.js.map +1 -0
- package/dist/index.d.ts +101 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +116 -0
- package/dist/index.js.map +1 -0
- package/dist/models/arch-call.d.ts +83 -0
- package/dist/models/arch-call.d.ts.map +1 -0
- package/dist/models/arch-call.js +90 -0
- package/dist/models/arch-call.js.map +1 -0
- package/dist/models/arch-function.d.ts +76 -0
- package/dist/models/arch-function.d.ts.map +1 -0
- package/dist/models/arch-function.js +122 -0
- package/dist/models/arch-function.js.map +1 -0
- package/dist/models/arch-jsx-element.d.ts +75 -0
- package/dist/models/arch-jsx-element.d.ts.map +1 -0
- package/dist/models/arch-jsx-element.js +231 -0
- package/dist/models/arch-jsx-element.js.map +1 -0
- package/dist/models/cross-layer.d.ts +15 -0
- package/dist/models/cross-layer.d.ts.map +1 -0
- package/dist/models/cross-layer.js +2 -0
- package/dist/models/cross-layer.js.map +1 -0
- package/dist/models/slice.d.ts +60 -0
- package/dist/models/slice.d.ts.map +1 -0
- package/dist/models/slice.js +89 -0
- package/dist/models/slice.js.map +1 -0
- package/dist/predicates/call.d.ts +49 -0
- package/dist/predicates/call.d.ts.map +1 -0
- package/dist/predicates/call.js +115 -0
- package/dist/predicates/call.js.map +1 -0
- package/dist/predicates/class.d.ts +42 -0
- package/dist/predicates/class.d.ts.map +1 -0
- package/dist/predicates/class.js +83 -0
- package/dist/predicates/class.js.map +1 -0
- package/dist/predicates/function.d.ts +81 -0
- package/dist/predicates/function.d.ts.map +1 -0
- package/dist/predicates/function.js +157 -0
- package/dist/predicates/function.js.map +1 -0
- package/dist/predicates/identity.d.ts +55 -0
- package/dist/predicates/identity.d.ts.map +1 -0
- package/dist/predicates/identity.js +96 -0
- package/dist/predicates/identity.js.map +1 -0
- package/dist/predicates/index.d.ts +4 -0
- package/dist/predicates/index.d.ts.map +1 -0
- package/dist/predicates/index.js +3 -0
- package/dist/predicates/index.js.map +1 -0
- package/dist/predicates/jsx.d.ts +41 -0
- package/dist/predicates/jsx.d.ts.map +1 -0
- package/dist/predicates/jsx.js +84 -0
- package/dist/predicates/jsx.js.map +1 -0
- package/dist/predicates/metrics.d.ts +30 -0
- package/dist/predicates/metrics.d.ts.map +1 -0
- package/dist/predicates/metrics.js +65 -0
- package/dist/predicates/metrics.js.map +1 -0
- package/dist/predicates/module.d.ts +44 -0
- package/dist/predicates/module.d.ts.map +1 -0
- package/dist/predicates/module.js +70 -0
- package/dist/predicates/module.js.map +1 -0
- package/dist/predicates/type.d.ts +48 -0
- package/dist/predicates/type.d.ts.map +1 -0
- package/dist/predicates/type.js +107 -0
- package/dist/predicates/type.js.map +1 -0
- package/dist/presets/boundaries.d.ts +19 -0
- package/dist/presets/boundaries.d.ts.map +1 -0
- package/dist/presets/boundaries.js +93 -0
- package/dist/presets/boundaries.js.map +1 -0
- package/dist/presets/data-layer.d.ts +20 -0
- package/dist/presets/data-layer.d.ts.map +1 -0
- package/dist/presets/data-layer.js +30 -0
- package/dist/presets/data-layer.js.map +1 -0
- package/dist/presets/index.d.ts +9 -0
- package/dist/presets/index.d.ts.map +1 -0
- package/dist/presets/index.js +5 -0
- package/dist/presets/index.js.map +1 -0
- package/dist/presets/layered.d.ts +21 -0
- package/dist/presets/layered.d.ts.map +1 -0
- package/dist/presets/layered.js +103 -0
- package/dist/presets/layered.js.map +1 -0
- package/dist/presets/shared.d.ts +3 -0
- package/dist/presets/shared.d.ts.map +1 -0
- package/dist/presets/shared.js +5 -0
- package/dist/presets/shared.js.map +1 -0
- package/dist/rules/architecture.d.ts +10 -0
- package/dist/rules/architecture.d.ts.map +1 -0
- package/dist/rules/architecture.js +14 -0
- package/dist/rules/architecture.js.map +1 -0
- package/dist/rules/code-quality.d.ts +55 -0
- package/dist/rules/code-quality.d.ts.map +1 -0
- package/dist/rules/code-quality.js +116 -0
- package/dist/rules/code-quality.js.map +1 -0
- package/dist/rules/dependencies.d.ts +32 -0
- package/dist/rules/dependencies.d.ts.map +1 -0
- package/dist/rules/dependencies.js +37 -0
- package/dist/rules/dependencies.js.map +1 -0
- package/dist/rules/errors.d.ts +31 -0
- package/dist/rules/errors.d.ts.map +1 -0
- package/dist/rules/errors.js +97 -0
- package/dist/rules/errors.js.map +1 -0
- package/dist/rules/hygiene.d.ts +54 -0
- package/dist/rules/hygiene.d.ts.map +1 -0
- package/dist/rules/hygiene.js +62 -0
- package/dist/rules/hygiene.js.map +1 -0
- package/dist/rules/metrics-function.d.ts +45 -0
- package/dist/rules/metrics-function.d.ts.map +1 -0
- package/dist/rules/metrics-function.js +87 -0
- package/dist/rules/metrics-function.js.map +1 -0
- package/dist/rules/metrics.d.ts +64 -0
- package/dist/rules/metrics.d.ts.map +1 -0
- package/dist/rules/metrics.js +157 -0
- package/dist/rules/metrics.js.map +1 -0
- package/dist/rules/naming.d.ts +24 -0
- package/dist/rules/naming.d.ts.map +1 -0
- package/dist/rules/naming.js +51 -0
- package/dist/rules/naming.js.map +1 -0
- package/dist/rules/security.d.ts +59 -0
- package/dist/rules/security.d.ts.map +1 -0
- package/dist/rules/security.js +92 -0
- package/dist/rules/security.js.map +1 -0
- package/dist/rules/typescript.d.ts +73 -0
- package/dist/rules/typescript.d.ts.map +1 -0
- package/dist/rules/typescript.js +105 -0
- package/dist/rules/typescript.js.map +1 -0
- package/dist/smells/duplicate-bodies.d.ts +24 -0
- package/dist/smells/duplicate-bodies.d.ts.map +1 -0
- package/dist/smells/duplicate-bodies.js +131 -0
- package/dist/smells/duplicate-bodies.js.map +1 -0
- package/dist/smells/fingerprint.d.ts +27 -0
- package/dist/smells/fingerprint.d.ts.map +1 -0
- package/dist/smells/fingerprint.js +50 -0
- package/dist/smells/fingerprint.js.map +1 -0
- package/dist/smells/inconsistent-siblings.d.ts +21 -0
- package/dist/smells/inconsistent-siblings.d.ts.map +1 -0
- package/dist/smells/inconsistent-siblings.js +135 -0
- package/dist/smells/inconsistent-siblings.js.map +1 -0
- package/dist/smells/index.d.ts +12 -0
- package/dist/smells/index.d.ts.map +1 -0
- package/dist/smells/index.js +15 -0
- package/dist/smells/index.js.map +1 -0
- package/dist/smells/smell-builder.d.ts +37 -0
- package/dist/smells/smell-builder.d.ts.map +1 -0
- package/dist/smells/smell-builder.js +51 -0
- package/dist/smells/smell-builder.js.map +1 -0
- package/package.json +121 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { not } from '@nielspeter/eess';
|
|
2
|
+
import { resideInFolder as resideInFolderPredicate } from '../predicates/identity.js';
|
|
3
|
+
import { slices } from '../builders/slice-rule-builder.js';
|
|
4
|
+
import { modules } from '../builders/module-rule-builder.js';
|
|
5
|
+
import { dispatchRule, validateOverrides, finishPreset } from './shared.js';
|
|
6
|
+
const RULE_IDS = [
|
|
7
|
+
'preset/layered/layer-order',
|
|
8
|
+
'preset/layered/no-cycles',
|
|
9
|
+
'preset/layered/innermost-isolation',
|
|
10
|
+
'preset/layered/type-imports-only',
|
|
11
|
+
'preset/layered/restricted-packages',
|
|
12
|
+
];
|
|
13
|
+
/**
|
|
14
|
+
* Collect violations for type-import-only rules on specified layers.
|
|
15
|
+
*/
|
|
16
|
+
function applyTypeImportRules(p, typeImportsAllowed, layerGlobs, overrides) {
|
|
17
|
+
const violations = [];
|
|
18
|
+
for (const layerGlob of typeImportsAllowed) {
|
|
19
|
+
const otherLayerGlobs = layerGlobs.filter((g) => g !== layerGlob);
|
|
20
|
+
if (otherLayerGlobs.length > 0) {
|
|
21
|
+
violations.push(...dispatchRule(modules(p)
|
|
22
|
+
.that()
|
|
23
|
+
.resideInFolder(layerGlob)
|
|
24
|
+
.should()
|
|
25
|
+
.onlyHaveTypeImportsFrom(...otherLayerGlobs), 'preset/layered/type-imports-only', 'warn', overrides));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return violations;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Collect violations for restricted-package rules.
|
|
32
|
+
*/
|
|
33
|
+
function applyRestrictedPackages(p, restrictedPackages, overrides) {
|
|
34
|
+
// Invert: for each package, find which layers are allowed
|
|
35
|
+
const packageToAllowed = new Map();
|
|
36
|
+
for (const [layerGlob, packages] of Object.entries(restrictedPackages)) {
|
|
37
|
+
for (const pkg of packages) {
|
|
38
|
+
const existing = packageToAllowed.get(pkg);
|
|
39
|
+
if (existing) {
|
|
40
|
+
existing.push(layerGlob);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
packageToAllowed.set(pkg, [layerGlob]);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const violations = [];
|
|
48
|
+
for (const [pkg, allowedLayers] of packageToAllowed) {
|
|
49
|
+
// Modules NOT in any allowed layer must not import this package
|
|
50
|
+
const builder = modules(p).that();
|
|
51
|
+
for (const allowedGlob of allowedLayers) {
|
|
52
|
+
builder.satisfy(not(resideInFolderPredicate(allowedGlob)));
|
|
53
|
+
}
|
|
54
|
+
violations.push(...dispatchRule(builder.should().notImportFrom(pkg), 'preset/layered/restricted-packages', 'error', overrides));
|
|
55
|
+
}
|
|
56
|
+
return violations;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Enforce a layered architecture: dependency direction, cycle freedom,
|
|
60
|
+
* and optional package restrictions.
|
|
61
|
+
*/
|
|
62
|
+
export function layeredArchitecture(p, options) {
|
|
63
|
+
const overrides = options.overrides;
|
|
64
|
+
validateOverrides(overrides, [...RULE_IDS]);
|
|
65
|
+
const layerNames = Object.keys(options.layers);
|
|
66
|
+
const layerGlobs = Object.values(options.layers);
|
|
67
|
+
const sharedGlobs = options.shared ?? [];
|
|
68
|
+
const violations = [];
|
|
69
|
+
// --- Layer order (slices) ---
|
|
70
|
+
const layerDef = {};
|
|
71
|
+
for (const [name, glob] of Object.entries(options.layers)) {
|
|
72
|
+
layerDef[name] = glob;
|
|
73
|
+
}
|
|
74
|
+
violations.push(...dispatchRule(slices(p)
|
|
75
|
+
.assignedFrom(layerDef)
|
|
76
|
+
.should()
|
|
77
|
+
.respectLayerOrder(...layerNames), 'preset/layered/layer-order', 'error', overrides));
|
|
78
|
+
// --- No cycles ---
|
|
79
|
+
violations.push(...dispatchRule(slices(p).assignedFrom(layerDef).should().beFreeOfCycles(), 'preset/layered/no-cycles', 'error', overrides));
|
|
80
|
+
// --- Innermost isolation (strict mode) ---
|
|
81
|
+
if (options.strict && layerNames.length > 0) {
|
|
82
|
+
const innermostName = layerNames[layerNames.length - 1];
|
|
83
|
+
const innermostGlob = innermostName !== undefined ? options.layers[innermostName] : undefined;
|
|
84
|
+
if (innermostName && innermostGlob) {
|
|
85
|
+
const allowedGlobs = [innermostGlob, ...sharedGlobs];
|
|
86
|
+
violations.push(...dispatchRule(modules(p)
|
|
87
|
+
.that()
|
|
88
|
+
.resideInFolder(innermostGlob)
|
|
89
|
+
.should()
|
|
90
|
+
.onlyImportFrom(...allowedGlobs), 'preset/layered/innermost-isolation', 'error', overrides));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// --- Type imports only for specified layers ---
|
|
94
|
+
if (options.typeImportsAllowed && options.typeImportsAllowed.length > 0) {
|
|
95
|
+
violations.push(...applyTypeImportRules(p, options.typeImportsAllowed, layerGlobs, overrides));
|
|
96
|
+
}
|
|
97
|
+
// --- Restricted packages ---
|
|
98
|
+
if (options.restrictedPackages) {
|
|
99
|
+
violations.push(...applyRestrictedPackages(p, options.restrictedPackages, overrides));
|
|
100
|
+
}
|
|
101
|
+
return finishPreset(violations, options);
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=layered.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layered.js","sourceRoot":"","sources":["../../src/presets/layered.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/presets/shared.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AACnG,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// The preset-dispatch infrastructure is dialect-independent and now lives in the
|
|
2
|
+
// kernel (@nielspeter/eess). Re-exported here so existing preset imports
|
|
3
|
+
// (`./shared.js`) keep working unchanged.
|
|
4
|
+
export { dispatchRule, validateOverrides, throwIfViolations, finishPreset } from '@nielspeter/eess';
|
|
5
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/presets/shared.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,yEAAyE;AACzE,0CAA0C;AAC1C,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ClassDeclaration } from 'ts-morph';
|
|
2
|
+
import type { Condition } from '@nielspeter/eess';
|
|
3
|
+
import type { ArchFunction } from '../models/arch-function.js';
|
|
4
|
+
/**
|
|
5
|
+
* Function body must contain at least one call matching the pattern.
|
|
6
|
+
* Use to enforce that a layer actually delegates to its dependency.
|
|
7
|
+
*/
|
|
8
|
+
export declare function mustCall(pattern: RegExp): Condition<ArchFunction>;
|
|
9
|
+
export declare function classMustCall(pattern: RegExp): Condition<ClassDeclaration>;
|
|
10
|
+
//# sourceMappingURL=architecture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"architecture.d.ts","sourceRoot":"","sources":["../../src/rules/architecture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAK9D;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC,YAAY,CAAC,CAEjE;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAE1E"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { call } from '../helpers/matchers.js';
|
|
2
|
+
import { classContain } from '../conditions/body-analysis.js';
|
|
3
|
+
import { functionContain } from '../conditions/body-analysis-function.js';
|
|
4
|
+
/**
|
|
5
|
+
* Function body must contain at least one call matching the pattern.
|
|
6
|
+
* Use to enforce that a layer actually delegates to its dependency.
|
|
7
|
+
*/
|
|
8
|
+
export function mustCall(pattern) {
|
|
9
|
+
return functionContain(call(pattern));
|
|
10
|
+
}
|
|
11
|
+
export function classMustCall(pattern) {
|
|
12
|
+
return classContain(call(pattern));
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=architecture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"architecture.js","sourceRoot":"","sources":["../../src/rules/architecture.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAA;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAA;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAA;AAEzE;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,OAAe;IACtC,OAAO,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAA;AACvC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAe;IAC3C,OAAO,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAA;AACpC,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { ClassDeclaration } from 'ts-morph';
|
|
2
|
+
import type { Condition } from '@nielspeter/eess';
|
|
3
|
+
/**
|
|
4
|
+
* All public methods must have JSDoc comments.
|
|
5
|
+
*
|
|
6
|
+
* Methods with no explicit scope or scope 'public' are checked.
|
|
7
|
+
* Private and protected methods are skipped.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* import { requireJsDocOnPublicMethods } from '@nielspeter/eess-ts/rules/code-quality'
|
|
11
|
+
*
|
|
12
|
+
* classes(p).that().areExported()
|
|
13
|
+
* .should().satisfy(requireJsDocOnPublicMethods())
|
|
14
|
+
* .because('public API must be documented')
|
|
15
|
+
* .check()
|
|
16
|
+
*/
|
|
17
|
+
export declare function requireJsDocOnPublicMethods(): Condition<ClassDeclaration>;
|
|
18
|
+
/**
|
|
19
|
+
* Classes must not have public non-static mutable fields.
|
|
20
|
+
*
|
|
21
|
+
* Static readonly fields (constants) are allowed.
|
|
22
|
+
* Use private fields with getters/setters instead.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* import { noPublicFields } from '@nielspeter/eess-ts/rules/code-quality'
|
|
27
|
+
*
|
|
28
|
+
* classes(p).that().resideInFolder('src/domain/')
|
|
29
|
+
* .should().satisfy(noPublicFields())
|
|
30
|
+
* .because('encapsulate state behind methods')
|
|
31
|
+
* .check()
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare function noPublicFields(): Condition<ClassDeclaration>;
|
|
35
|
+
/**
|
|
36
|
+
* Method bodies must not contain magic numbers.
|
|
37
|
+
*
|
|
38
|
+
* Numbers 0, 1, -1, 2, 10, 100 are allowed by default.
|
|
39
|
+
* Configure with options.allowed to customize.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* import { noMagicNumbers } from '@nielspeter/eess-ts/rules/code-quality'
|
|
43
|
+
*
|
|
44
|
+
* classes(p).that().haveNameEndingWith('Service')
|
|
45
|
+
* .should().satisfy(noMagicNumbers())
|
|
46
|
+
* .because('extract constants for readability')
|
|
47
|
+
* .warn()
|
|
48
|
+
*
|
|
49
|
+
* // Custom allowed list
|
|
50
|
+
* classes(p).should().satisfy(noMagicNumbers({ allowed: [0, 1, -1, 200, 404] })).warn()
|
|
51
|
+
*/
|
|
52
|
+
export declare function noMagicNumbers(options?: {
|
|
53
|
+
allowed?: number[];
|
|
54
|
+
}): Condition<ClassDeclaration>;
|
|
55
|
+
//# sourceMappingURL=code-quality.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-quality.d.ts","sourceRoot":"","sources":["../../src/rules/code-quality.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAChD,OAAO,KAAK,EAAE,SAAS,EAAoB,MAAM,kBAAkB,CAAA;AAInE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,2BAA2B,IAAI,SAAS,CAAC,gBAAgB,CAAC,CAuBzE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,IAAI,SAAS,CAAC,gBAAgB,CAAC,CA2B5D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,SAAS,CAAC,gBAAgB,CAAC,CA8B5F"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { SyntaxKind } from 'ts-morph';
|
|
2
|
+
import { createViolation } from '../core/violation.js';
|
|
3
|
+
/**
|
|
4
|
+
* All public methods must have JSDoc comments.
|
|
5
|
+
*
|
|
6
|
+
* Methods with no explicit scope or scope 'public' are checked.
|
|
7
|
+
* Private and protected methods are skipped.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* import { requireJsDocOnPublicMethods } from '@nielspeter/eess-ts/rules/code-quality'
|
|
11
|
+
*
|
|
12
|
+
* classes(p).that().areExported()
|
|
13
|
+
* .should().satisfy(requireJsDocOnPublicMethods())
|
|
14
|
+
* .because('public API must be documented')
|
|
15
|
+
* .check()
|
|
16
|
+
*/
|
|
17
|
+
export function requireJsDocOnPublicMethods() {
|
|
18
|
+
return {
|
|
19
|
+
description: 'have JSDoc on all public methods',
|
|
20
|
+
evaluate(elements, context) {
|
|
21
|
+
const violations = [];
|
|
22
|
+
for (const cls of elements) {
|
|
23
|
+
for (const method of cls.getMethods()) {
|
|
24
|
+
const scope = method.getScope();
|
|
25
|
+
const isPublic = scope === undefined || String(scope) === 'public';
|
|
26
|
+
if (isPublic && method.getJsDocs().length === 0) {
|
|
27
|
+
violations.push(createViolation(method, `${cls.getName() ?? '<anonymous>'}.${method.getName()} is public but has no JSDoc`, context));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return violations;
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Classes must not have public non-static mutable fields.
|
|
37
|
+
*
|
|
38
|
+
* Static readonly fields (constants) are allowed.
|
|
39
|
+
* Use private fields with getters/setters instead.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* import { noPublicFields } from '@nielspeter/eess-ts/rules/code-quality'
|
|
44
|
+
*
|
|
45
|
+
* classes(p).that().resideInFolder('src/domain/')
|
|
46
|
+
* .should().satisfy(noPublicFields())
|
|
47
|
+
* .because('encapsulate state behind methods')
|
|
48
|
+
* .check()
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export function noPublicFields() {
|
|
52
|
+
return {
|
|
53
|
+
description: 'have no public mutable fields',
|
|
54
|
+
evaluate(elements, context) {
|
|
55
|
+
const violations = [];
|
|
56
|
+
for (const cls of elements) {
|
|
57
|
+
for (const prop of cls.getProperties()) {
|
|
58
|
+
// ES #private fields are private by name — they carry no scope
|
|
59
|
+
// modifier, so getScope() reports public (dogfood finding, plan 0060)
|
|
60
|
+
if (prop.getName().startsWith('#'))
|
|
61
|
+
continue;
|
|
62
|
+
const scope = prop.getScope();
|
|
63
|
+
if (scope !== undefined && String(scope) !== 'public')
|
|
64
|
+
continue;
|
|
65
|
+
// Allow static readonly (constants)
|
|
66
|
+
if (prop.isStatic() && prop.isReadonly())
|
|
67
|
+
continue;
|
|
68
|
+
violations.push(createViolation(prop, `${cls.getName() ?? '<anonymous>'}.${prop.getName()} is a public field — use private + getter/setter`, context));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return violations;
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Method bodies must not contain magic numbers.
|
|
77
|
+
*
|
|
78
|
+
* Numbers 0, 1, -1, 2, 10, 100 are allowed by default.
|
|
79
|
+
* Configure with options.allowed to customize.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* import { noMagicNumbers } from '@nielspeter/eess-ts/rules/code-quality'
|
|
83
|
+
*
|
|
84
|
+
* classes(p).that().haveNameEndingWith('Service')
|
|
85
|
+
* .should().satisfy(noMagicNumbers())
|
|
86
|
+
* .because('extract constants for readability')
|
|
87
|
+
* .warn()
|
|
88
|
+
*
|
|
89
|
+
* // Custom allowed list
|
|
90
|
+
* classes(p).should().satisfy(noMagicNumbers({ allowed: [0, 1, -1, 200, 404] })).warn()
|
|
91
|
+
*/
|
|
92
|
+
export function noMagicNumbers(options) {
|
|
93
|
+
const allowedSet = new Set(options?.allowed ?? [0, 1, -1, 2, 10, 100]);
|
|
94
|
+
return {
|
|
95
|
+
description: 'have no magic numbers in method bodies',
|
|
96
|
+
evaluate(elements, context) {
|
|
97
|
+
const violations = [];
|
|
98
|
+
for (const cls of elements) {
|
|
99
|
+
for (const method of cls.getMethods()) {
|
|
100
|
+
const body = method.getBody();
|
|
101
|
+
if (!body)
|
|
102
|
+
continue;
|
|
103
|
+
const literals = body.getDescendantsOfKind(SyntaxKind.NumericLiteral);
|
|
104
|
+
for (const lit of literals) {
|
|
105
|
+
const value = Number(lit.getText());
|
|
106
|
+
if (!allowedSet.has(value)) {
|
|
107
|
+
violations.push(createViolation(lit, `${cls.getName() ?? '<anonymous>'}.${method.getName()} contains magic number ${String(value)} — extract to a named constant`, context));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return violations;
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=code-quality.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-quality.js","sourceRoot":"","sources":["../../src/rules/code-quality.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { SourceFile } from 'ts-morph';
|
|
2
|
+
import type { Condition } from '@nielspeter/eess';
|
|
3
|
+
/**
|
|
4
|
+
* Module must only import from allowed paths.
|
|
5
|
+
*
|
|
6
|
+
* Convenience wrapper around the onlyImportFrom condition.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* modules(p).that().resideInFolder('** /domain/** ')
|
|
10
|
+
* .should().satisfy(onlyDependOn('** /domain/** ', '** /shared/** '))
|
|
11
|
+
* .check()
|
|
12
|
+
*/
|
|
13
|
+
export declare function onlyDependOn(...globs: string[]): Condition<SourceFile>;
|
|
14
|
+
/**
|
|
15
|
+
* Module must not import from forbidden paths.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* modules(p).that().resideInFolder('** /domain/** ')
|
|
19
|
+
* .should().satisfy(mustNotDependOn('** /infrastructure/** '))
|
|
20
|
+
* .check()
|
|
21
|
+
*/
|
|
22
|
+
export declare function mustNotDependOn(...globs: string[]): Condition<SourceFile>;
|
|
23
|
+
/**
|
|
24
|
+
* Imports from specific paths must be type-only.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* modules(p).that().resideInFolder('** /services/** ')
|
|
28
|
+
* .should().satisfy(typeOnlyFrom('** /domain/** '))
|
|
29
|
+
* .check()
|
|
30
|
+
*/
|
|
31
|
+
export declare function typeOnlyFrom(...globs: string[]): Condition<SourceFile>;
|
|
32
|
+
//# sourceMappingURL=dependencies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependencies.d.ts","sourceRoot":"","sources":["../../src/rules/dependencies.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAC1C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAGjD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,UAAU,CAAC,CAEtE;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,UAAU,CAAC,CAEzE;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,UAAU,CAAC,CAEtE"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { onlyImportFrom, notImportFrom, onlyHaveTypeImportsFrom } from '../conditions/dependency.js';
|
|
2
|
+
/**
|
|
3
|
+
* Module must only import from allowed paths.
|
|
4
|
+
*
|
|
5
|
+
* Convenience wrapper around the onlyImportFrom condition.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* modules(p).that().resideInFolder('** /domain/** ')
|
|
9
|
+
* .should().satisfy(onlyDependOn('** /domain/** ', '** /shared/** '))
|
|
10
|
+
* .check()
|
|
11
|
+
*/
|
|
12
|
+
export function onlyDependOn(...globs) {
|
|
13
|
+
return onlyImportFrom(...globs);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Module must not import from forbidden paths.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* modules(p).that().resideInFolder('** /domain/** ')
|
|
20
|
+
* .should().satisfy(mustNotDependOn('** /infrastructure/** '))
|
|
21
|
+
* .check()
|
|
22
|
+
*/
|
|
23
|
+
export function mustNotDependOn(...globs) {
|
|
24
|
+
return notImportFrom(...globs);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Imports from specific paths must be type-only.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* modules(p).that().resideInFolder('** /services/** ')
|
|
31
|
+
* .should().satisfy(typeOnlyFrom('** /domain/** '))
|
|
32
|
+
* .check()
|
|
33
|
+
*/
|
|
34
|
+
export function typeOnlyFrom(...globs) {
|
|
35
|
+
return onlyHaveTypeImportsFrom(...globs);
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=dependencies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependencies.js","sourceRoot":"","sources":["../../src/rules/dependencies.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAA;AAEpG;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY,CAAC,GAAG,KAAe;IAC7C,OAAO,cAAc,CAAC,GAAG,KAAK,CAAC,CAAA;AACjC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,GAAG,KAAe;IAChD,OAAO,aAAa,CAAC,GAAG,KAAK,CAAC,CAAA;AAChC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,GAAG,KAAe;IAC7C,OAAO,uBAAuB,CAAC,GAAG,KAAK,CAAC,CAAA;AAC1C,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ClassDeclaration, SourceFile } from 'ts-morph';
|
|
2
|
+
import type { Condition } from '@nielspeter/eess';
|
|
3
|
+
import type { ArchFunction } from '../models/arch-function.js';
|
|
4
|
+
/**
|
|
5
|
+
* No throwing generic Error — use typed domain errors instead.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* classes(p).that().extend('BaseService')
|
|
9
|
+
* .should().satisfy(noGenericErrors())
|
|
10
|
+
* .because('use DomainError, NotFoundError, etc.')
|
|
11
|
+
* .check()
|
|
12
|
+
*/
|
|
13
|
+
export declare function noGenericErrors(): Condition<ClassDeclaration>;
|
|
14
|
+
/**
|
|
15
|
+
* No throwing TypeError — usually indicates a programming error, not a domain error.
|
|
16
|
+
*/
|
|
17
|
+
export declare function noTypeErrors(): Condition<ClassDeclaration>;
|
|
18
|
+
export declare function functionNoGenericErrors(): Condition<ArchFunction>;
|
|
19
|
+
export declare function functionNoTypeErrors(): Condition<ArchFunction>;
|
|
20
|
+
/**
|
|
21
|
+
* Catch blocks in class methods, constructors, getters, and setters
|
|
22
|
+
* must reference the caught error variable.
|
|
23
|
+
*
|
|
24
|
+
* Detects catch blocks that silently discard errors — no logging,
|
|
25
|
+
* no rethrowing, no passing to another function. A common source of
|
|
26
|
+
* hidden production bugs.
|
|
27
|
+
*/
|
|
28
|
+
export declare function noSilentCatch(): Condition<ClassDeclaration>;
|
|
29
|
+
export declare function functionNoSilentCatch(): Condition<ArchFunction>;
|
|
30
|
+
export declare function moduleNoSilentCatch(): Condition<SourceFile>;
|
|
31
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/rules/errors.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAoB,MAAM,kBAAkB,CAAA;AAGnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAM9D;;;;;;;;GAQG;AACH,wBAAgB,eAAe,IAAI,SAAS,CAAC,gBAAgB,CAAC,CAE7D;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,SAAS,CAAC,gBAAgB,CAAC,CAE1D;AAID,wBAAgB,uBAAuB,IAAI,SAAS,CAAC,YAAY,CAAC,CAEjE;AAED,wBAAgB,oBAAoB,IAAI,SAAS,CAAC,YAAY,CAAC,CAE9D;AAID;;;;;;;GAOG;AACH,wBAAgB,aAAa,IAAI,SAAS,CAAC,gBAAgB,CAAC,CAuB3D;AAED,wBAAgB,qBAAqB,IAAI,SAAS,CAAC,YAAY,CAAC,CAe/D;AAED,wBAAgB,mBAAmB,IAAI,SAAS,CAAC,UAAU,CAAC,CAa3D"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { Node } from 'ts-morph';
|
|
2
|
+
import { createViolation } from '../core/violation.js';
|
|
3
|
+
import { newExpr } from '../helpers/matchers.js';
|
|
4
|
+
import { classNotContain } from '../conditions/body-analysis.js';
|
|
5
|
+
import { functionNotContain } from '../conditions/body-analysis-function.js';
|
|
6
|
+
import { findSilentCatches } from '../conditions/catch-analysis.js';
|
|
7
|
+
/**
|
|
8
|
+
* No throwing generic Error — use typed domain errors instead.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* classes(p).that().extend('BaseService')
|
|
12
|
+
* .should().satisfy(noGenericErrors())
|
|
13
|
+
* .because('use DomainError, NotFoundError, etc.')
|
|
14
|
+
* .check()
|
|
15
|
+
*/
|
|
16
|
+
export function noGenericErrors() {
|
|
17
|
+
return classNotContain(newExpr('Error'));
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* No throwing TypeError — usually indicates a programming error, not a domain error.
|
|
21
|
+
*/
|
|
22
|
+
export function noTypeErrors() {
|
|
23
|
+
return classNotContain(newExpr('TypeError'));
|
|
24
|
+
}
|
|
25
|
+
// ─── Function variants ────────────────────────────────────────────
|
|
26
|
+
export function functionNoGenericErrors() {
|
|
27
|
+
return functionNotContain(newExpr('Error'));
|
|
28
|
+
}
|
|
29
|
+
export function functionNoTypeErrors() {
|
|
30
|
+
return functionNotContain(newExpr('TypeError'));
|
|
31
|
+
}
|
|
32
|
+
// ─── Silent catch detection ──────────────────────────────────────
|
|
33
|
+
/**
|
|
34
|
+
* Catch blocks in class methods, constructors, getters, and setters
|
|
35
|
+
* must reference the caught error variable.
|
|
36
|
+
*
|
|
37
|
+
* Detects catch blocks that silently discard errors — no logging,
|
|
38
|
+
* no rethrowing, no passing to another function. A common source of
|
|
39
|
+
* hidden production bugs.
|
|
40
|
+
*/
|
|
41
|
+
export function noSilentCatch() {
|
|
42
|
+
return {
|
|
43
|
+
description: 'not have silent catch blocks (catch must reference the error)',
|
|
44
|
+
evaluate(elements, context) {
|
|
45
|
+
const violations = [];
|
|
46
|
+
for (const cls of elements) {
|
|
47
|
+
const members = [
|
|
48
|
+
...cls.getMethods(),
|
|
49
|
+
...cls.getConstructors(),
|
|
50
|
+
...cls.getGetAccessors(),
|
|
51
|
+
...cls.getSetAccessors(),
|
|
52
|
+
];
|
|
53
|
+
for (const member of members) {
|
|
54
|
+
const body = member.getBody();
|
|
55
|
+
if (!body)
|
|
56
|
+
continue;
|
|
57
|
+
for (const result of findSilentCatches(body)) {
|
|
58
|
+
violations.push(createViolation(result.node, result.message, context));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return violations;
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
export function functionNoSilentCatch() {
|
|
67
|
+
return {
|
|
68
|
+
description: 'not have silent catch blocks (catch must reference the error)',
|
|
69
|
+
evaluate(elements, context) {
|
|
70
|
+
const violations = [];
|
|
71
|
+
for (const fn of elements) {
|
|
72
|
+
const body = fn.getBody();
|
|
73
|
+
if (!body || !Node.isBlock(body))
|
|
74
|
+
continue;
|
|
75
|
+
for (const result of findSilentCatches(body)) {
|
|
76
|
+
violations.push(createViolation(result.node, result.message, context));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return violations;
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export function moduleNoSilentCatch() {
|
|
84
|
+
return {
|
|
85
|
+
description: 'not have silent catch blocks (catch must reference the error)',
|
|
86
|
+
evaluate(elements, context) {
|
|
87
|
+
const violations = [];
|
|
88
|
+
for (const sf of elements) {
|
|
89
|
+
for (const result of findSilentCatches(sf)) {
|
|
90
|
+
violations.push(createViolation(result.node, result.message, context));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return violations;
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/rules/errors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { SourceFile } from 'ts-morph';
|
|
2
|
+
import type { Condition } from '@nielspeter/eess';
|
|
3
|
+
import type { ArchFunction } from '../models/arch-function.js';
|
|
4
|
+
/**
|
|
5
|
+
* Module must be imported by at least one other module.
|
|
6
|
+
* Detects dead/orphaned files that nobody references.
|
|
7
|
+
*
|
|
8
|
+
* Exclude entry points (index.ts, main.ts) via .excluding().
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* modules(p)
|
|
12
|
+
* .that().resideInFolder('src/**')
|
|
13
|
+
* .should().satisfy(noDeadModules())
|
|
14
|
+
* .excluding('index.ts', 'main.ts')
|
|
15
|
+
* .check()
|
|
16
|
+
*/
|
|
17
|
+
export declare function noDeadModules(): Condition<SourceFile>;
|
|
18
|
+
/**
|
|
19
|
+
* Every exported symbol must be referenced by at least one other file.
|
|
20
|
+
* Detects exports that bloat the public API without consumers.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* modules(p)
|
|
24
|
+
* .that().resideInFolder('src/**')
|
|
25
|
+
* .should().satisfy(noUnusedExports())
|
|
26
|
+
* .check()
|
|
27
|
+
*/
|
|
28
|
+
export declare function noUnusedExports(): Condition<SourceFile>;
|
|
29
|
+
/**
|
|
30
|
+
* No stub or deferred-work comments in function bodies.
|
|
31
|
+
* Catches common markers (see STUB_PATTERNS) and phrases like
|
|
32
|
+
* "not implemented" or "coming soon".
|
|
33
|
+
*
|
|
34
|
+
* Pass a custom pattern to override the defaults.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* functions(p)
|
|
38
|
+
* .that().resideInFolder('src/**')
|
|
39
|
+
* .should().satisfy(noStubComments())
|
|
40
|
+
* .check()
|
|
41
|
+
*/
|
|
42
|
+
export declare function noStubComments(pattern?: RegExp): Condition<ArchFunction>;
|
|
43
|
+
/**
|
|
44
|
+
* Functions must not have empty bodies.
|
|
45
|
+
* An empty function compiles and passes type checks but does nothing.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* functions(p)
|
|
49
|
+
* .that().resideInFolder('src/**')
|
|
50
|
+
* .should().satisfy(noEmptyBodies())
|
|
51
|
+
* .check()
|
|
52
|
+
*/
|
|
53
|
+
export declare function noEmptyBodies(): Condition<ArchFunction>;
|
|
54
|
+
//# sourceMappingURL=hygiene.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hygiene.d.ts","sourceRoot":"","sources":["../../src/rules/hygiene.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAC1C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAQ9D;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,IAAI,SAAS,CAAC,UAAU,CAAC,CAErD;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,IAAI,SAAS,CAAC,UAAU,CAAC,CAEvD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,MAAsB,GAAG,SAAS,CAAC,YAAY,CAAC,CAEvF;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,IAAI,SAAS,CAAC,YAAY,CAAC,CAEvD"}
|