@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,267 @@
|
|
|
1
|
+
import { Node } from 'ts-morph';
|
|
2
|
+
import { getFunctionBody, findMatchesInNode } from '../helpers/body-traversal.js';
|
|
3
|
+
/**
|
|
4
|
+
* Helper to create a violation from an ArchCall.
|
|
5
|
+
*
|
|
6
|
+
* The `element` field uses the argument-enriched name when
|
|
7
|
+
* `context.identifyByArgument` is set, but **never** elides — exclusion
|
|
8
|
+
* patterns key on the element string, so stability is required.
|
|
9
|
+
*/
|
|
10
|
+
function createCallViolation(archCall, message, context) {
|
|
11
|
+
return {
|
|
12
|
+
rule: context.rule,
|
|
13
|
+
element: archCall.getName({ withArgument: context.identifyByArgument }) ?? '<call>',
|
|
14
|
+
file: archCall.getSourceFile().getFilePath(),
|
|
15
|
+
line: archCall.getStartLineNumber(),
|
|
16
|
+
message,
|
|
17
|
+
because: context.because,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Resolve the name for use in a violation MESSAGE (elision enabled).
|
|
22
|
+
*
|
|
23
|
+
* If `context.identifyByArgument` is set and the indexed argument's
|
|
24
|
+
* `getText()` exceeds 80 characters, the literal portion is elided
|
|
25
|
+
* (`slice(0, 38) + '…' + slice(-38)`) so CI output stays scannable.
|
|
26
|
+
* The element field NEVER elides — see {@link createCallViolation}.
|
|
27
|
+
*/
|
|
28
|
+
function callNameForMessage(archCall, context) {
|
|
29
|
+
return archCall.getName({ withArgument: context.identifyByArgument, elide: true }) ?? '<call>';
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The filtered call set must be empty --- no calls should match the predicates.
|
|
33
|
+
*/
|
|
34
|
+
export function notExist() {
|
|
35
|
+
return {
|
|
36
|
+
description: 'not exist',
|
|
37
|
+
evaluate(elements, context) {
|
|
38
|
+
return elements.map((archCall) => createCallViolation(archCall, `${callNameForMessage(archCall, context)} should not exist`, context));
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Assert that at least one callback argument contains a match.
|
|
44
|
+
*
|
|
45
|
+
* Searches all function-like arguments (ArrowFunction, FunctionExpression)
|
|
46
|
+
* for a node matching the given ExpressionMatcher.
|
|
47
|
+
*/
|
|
48
|
+
export function haveCallbackContaining(matcher) {
|
|
49
|
+
return {
|
|
50
|
+
description: `have callback containing ${matcher.description}`,
|
|
51
|
+
evaluate(elements, context) {
|
|
52
|
+
const violations = [];
|
|
53
|
+
for (const archCall of elements) {
|
|
54
|
+
const found = searchCallbacksFor(archCall, matcher);
|
|
55
|
+
if (!found) {
|
|
56
|
+
violations.push(createCallViolation(archCall, `${callNameForMessage(archCall, context)} does not have a callback containing ${matcher.description}`, context));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return violations;
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Assert that NO callback argument contains a match.
|
|
65
|
+
*
|
|
66
|
+
* Produces one violation per matching node found in any callback.
|
|
67
|
+
*/
|
|
68
|
+
export function notHaveCallbackContaining(matcher) {
|
|
69
|
+
return {
|
|
70
|
+
description: `not have callback containing ${matcher.description}`,
|
|
71
|
+
evaluate(elements, context) {
|
|
72
|
+
const violations = [];
|
|
73
|
+
for (const archCall of elements) {
|
|
74
|
+
// Hoist the enriched name once per archCall — the inner match loop
|
|
75
|
+
// produces multiple violations against the same call, and the
|
|
76
|
+
// literal-shape walk inside getName({...}) is identical for each.
|
|
77
|
+
const callName = callNameForMessage(archCall, context);
|
|
78
|
+
const args = archCall.getArguments();
|
|
79
|
+
for (const arg of args) {
|
|
80
|
+
const body = getFunctionBody(arg);
|
|
81
|
+
if (!body)
|
|
82
|
+
continue;
|
|
83
|
+
const matches = findMatchesInNode(body, matcher);
|
|
84
|
+
for (const match of matches) {
|
|
85
|
+
violations.push(createCallViolation(archCall, `${callName} has callback containing ${matcher.description} at line ${String(match.getStartLineNumber())}`, context));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return violations;
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Search all callback arguments of a call for a matcher hit.
|
|
95
|
+
*/
|
|
96
|
+
function searchCallbacksFor(archCall, matcher) {
|
|
97
|
+
const args = archCall.getArguments();
|
|
98
|
+
for (const arg of args) {
|
|
99
|
+
const body = getFunctionBody(arg);
|
|
100
|
+
if (!body)
|
|
101
|
+
continue;
|
|
102
|
+
const matches = findMatchesInNode(body, matcher);
|
|
103
|
+
if (matches.length > 0)
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Collect property names from an ObjectLiteralExpression node.
|
|
110
|
+
*
|
|
111
|
+
* Handles both PropertyAssignment (`{ schema: {} }`) and
|
|
112
|
+
* ShorthandPropertyAssignment (`{ schema }`).
|
|
113
|
+
*/
|
|
114
|
+
function getObjectLiteralPropertyNames(node) {
|
|
115
|
+
const names = new Set();
|
|
116
|
+
if (!Node.isObjectLiteralExpression(node))
|
|
117
|
+
return names;
|
|
118
|
+
for (const prop of node.getProperties()) {
|
|
119
|
+
if (Node.isPropertyAssignment(prop) || Node.isShorthandPropertyAssignment(prop)) {
|
|
120
|
+
names.add(prop.getName());
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return names;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Assert that at least one object literal argument has ALL named properties.
|
|
127
|
+
*
|
|
128
|
+
* Scans all arguments of each call for ObjectLiteralExpression nodes.
|
|
129
|
+
* Passes if at least one object literal argument contains every
|
|
130
|
+
* specified property name.
|
|
131
|
+
*
|
|
132
|
+
* @throws {Error} if called with zero property names
|
|
133
|
+
*/
|
|
134
|
+
export function haveArgumentWithProperty(...names) {
|
|
135
|
+
if (names.length === 0) {
|
|
136
|
+
throw new Error('haveArgumentWithProperty requires at least one property name');
|
|
137
|
+
}
|
|
138
|
+
const quotedNames = names.map((n) => `"${n}"`).join(', ');
|
|
139
|
+
const description = names.length === 1
|
|
140
|
+
? `have argument with property "${names[0] ?? ''}"`
|
|
141
|
+
: `have argument with properties ${quotedNames}`;
|
|
142
|
+
return {
|
|
143
|
+
description,
|
|
144
|
+
evaluate(elements, context) {
|
|
145
|
+
const violations = [];
|
|
146
|
+
for (const archCall of elements) {
|
|
147
|
+
const args = archCall.getArguments();
|
|
148
|
+
let found = false;
|
|
149
|
+
for (const arg of args) {
|
|
150
|
+
const propNames = getObjectLiteralPropertyNames(arg);
|
|
151
|
+
if (propNames.size > 0 && names.every((name) => propNames.has(name))) {
|
|
152
|
+
found = true;
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (!found) {
|
|
157
|
+
const callName = callNameForMessage(archCall, context);
|
|
158
|
+
violations.push(createCallViolation(archCall, `${callName} has no argument with properties ${quotedNames}`, context));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return violations;
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Assert that NO object literal argument has ANY of the named properties.
|
|
167
|
+
*
|
|
168
|
+
* Scans all arguments of each call for ObjectLiteralExpression nodes.
|
|
169
|
+
* Reports one violation per forbidden property found in any argument.
|
|
170
|
+
*
|
|
171
|
+
* @throws {Error} if called with zero property names
|
|
172
|
+
*/
|
|
173
|
+
export function notHaveArgumentWithProperty(...names) {
|
|
174
|
+
if (names.length === 0) {
|
|
175
|
+
throw new Error('notHaveArgumentWithProperty requires at least one property name');
|
|
176
|
+
}
|
|
177
|
+
const quotedNames = names.map((n) => `"${n}"`).join(', ');
|
|
178
|
+
const description = names.length === 1
|
|
179
|
+
? `not have argument with property "${names[0] ?? ''}"`
|
|
180
|
+
: `not have argument with properties ${quotedNames}`;
|
|
181
|
+
return {
|
|
182
|
+
description,
|
|
183
|
+
evaluate(elements, context) {
|
|
184
|
+
const violations = [];
|
|
185
|
+
for (const archCall of elements) {
|
|
186
|
+
// Hoist: inner nested loops (args × names) can produce multiple
|
|
187
|
+
// violations against the same archCall — same identity work each time.
|
|
188
|
+
const callName = callNameForMessage(archCall, context);
|
|
189
|
+
const args = archCall.getArguments();
|
|
190
|
+
for (const arg of args) {
|
|
191
|
+
const propNames = getObjectLiteralPropertyNames(arg);
|
|
192
|
+
for (const name of names) {
|
|
193
|
+
if (propNames.has(name)) {
|
|
194
|
+
violations.push(createCallViolation(archCall, `${callName} argument has forbidden property "${name}"`, context));
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return violations;
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Assert that at least one argument subtree contains a match.
|
|
205
|
+
*
|
|
206
|
+
* Searches ALL arguments of each call recursively using `findMatchesInNode`.
|
|
207
|
+
* This is a superset of `haveCallbackContaining` — it searches the entire
|
|
208
|
+
* subtree of every argument (object literals, callbacks, nested expressions),
|
|
209
|
+
* not just function-like arguments. Use `haveCallbackContaining` when you
|
|
210
|
+
* only want to search callback bodies.
|
|
211
|
+
*/
|
|
212
|
+
export function haveArgumentContaining(matcher) {
|
|
213
|
+
return {
|
|
214
|
+
description: `have argument containing ${matcher.description}`,
|
|
215
|
+
evaluate(elements, context) {
|
|
216
|
+
const violations = [];
|
|
217
|
+
for (const archCall of elements) {
|
|
218
|
+
const args = archCall.getArguments();
|
|
219
|
+
let found = false;
|
|
220
|
+
for (const arg of args) {
|
|
221
|
+
const matches = findMatchesInNode(arg, matcher);
|
|
222
|
+
if (matches.length > 0) {
|
|
223
|
+
found = true;
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (!found) {
|
|
228
|
+
violations.push(createCallViolation(archCall, `${callNameForMessage(archCall, context)} has no argument containing ${matcher.description}`, context));
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return violations;
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Assert that NO argument subtree contains a match.
|
|
237
|
+
*
|
|
238
|
+
* Searches ALL arguments of each call recursively using `findMatchesInNode`.
|
|
239
|
+
* Produces one violation per matching node found in any argument.
|
|
240
|
+
*
|
|
241
|
+
* This is a superset of `notHaveCallbackContaining` — it searches the entire
|
|
242
|
+
* subtree of every argument (object literals, callbacks, nested expressions),
|
|
243
|
+
* not just function-like arguments. Use `notHaveCallbackContaining` when you
|
|
244
|
+
* only want to search callback bodies.
|
|
245
|
+
*/
|
|
246
|
+
export function notHaveArgumentContaining(matcher) {
|
|
247
|
+
return {
|
|
248
|
+
description: `not have argument containing ${matcher.description}`,
|
|
249
|
+
evaluate(elements, context) {
|
|
250
|
+
const violations = [];
|
|
251
|
+
for (const archCall of elements) {
|
|
252
|
+
// Hoist: inner match loop produces multiple violations against the
|
|
253
|
+
// same archCall — same identity work each time.
|
|
254
|
+
const callName = callNameForMessage(archCall, context);
|
|
255
|
+
const args = archCall.getArguments();
|
|
256
|
+
for (const arg of args) {
|
|
257
|
+
const matches = findMatchesInNode(arg, matcher);
|
|
258
|
+
for (const match of matches) {
|
|
259
|
+
violations.push(createCallViolation(archCall, `${callName} argument contains ${matcher.description} at line ${String(match.getStartLineNumber())}`, context));
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return violations;
|
|
264
|
+
},
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
//# sourceMappingURL=call.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"call.js","sourceRoot":"","sources":["../../src/conditions/call.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Node } from 'ts-morph';
|
|
2
|
+
/**
|
|
3
|
+
* Result of scanning a single catch clause.
|
|
4
|
+
*/
|
|
5
|
+
export interface SilentCatchResult {
|
|
6
|
+
/** The CatchClause node — used for violation line and code frame */
|
|
7
|
+
node: Node;
|
|
8
|
+
/** Human-readable description of why this catch is silent */
|
|
9
|
+
message: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Find catch clauses in the body that don't reference the caught error.
|
|
13
|
+
*
|
|
14
|
+
* A catch clause is "silent" if:
|
|
15
|
+
* 1. It has no binding at all (`catch { ... }`) — no error to reference
|
|
16
|
+
* 2. It has a binding but no Identifier in the block body matches any binding name
|
|
17
|
+
*
|
|
18
|
+
* Uses a simple descendant Identifier walk instead of the Language Service's
|
|
19
|
+
* findReferencesAsNodes() — catch variables are block-scoped so a name match
|
|
20
|
+
* within the block is sufficient. This is faster and avoids edge cases where
|
|
21
|
+
* findReferencesAsNodes() returns zero refs for destructured bindings.
|
|
22
|
+
*
|
|
23
|
+
* **Known limitations (false negatives):**
|
|
24
|
+
* - Variable shadowing: `catch (err) { const err = new Error(); throw err }`
|
|
25
|
+
* — the `err` Identifier matches but refers to the redeclared variable.
|
|
26
|
+
* - Nested catch with same name: `catch (err) { try { } catch (err) { log(err) } }`
|
|
27
|
+
* — the inner `err` usage satisfies the outer check.
|
|
28
|
+
* Both are rare in practice and arguably code smells themselves.
|
|
29
|
+
*/
|
|
30
|
+
export declare function findSilentCatches(body: Node): SilentCatchResult[];
|
|
31
|
+
//# sourceMappingURL=catch-analysis.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catch-analysis.d.ts","sourceRoot":"","sources":["../../src/conditions/catch-analysis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAc,MAAM,UAAU,CAAA;AAE3C;;GAEG;AAEH,MAAM,WAAW,iBAAiB;IAChC,oEAAoE;IACpE,IAAI,EAAE,IAAI,CAAA;IACV,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAA;CAChB;AA8BD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,iBAAiB,EAAE,CAqCjE"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Node, SyntaxKind } from 'ts-morph';
|
|
2
|
+
/**
|
|
3
|
+
* Extract all binding names from a catch variable declaration.
|
|
4
|
+
*
|
|
5
|
+
* Handles simple bindings (`catch (err)`), object destructuring
|
|
6
|
+
* (`catch ({ message, code })`), and array destructuring (`catch ([code, msg])`).
|
|
7
|
+
*/
|
|
8
|
+
function getBindingNames(nameNode) {
|
|
9
|
+
if (Node.isIdentifier(nameNode)) {
|
|
10
|
+
return new Set([nameNode.getText()]);
|
|
11
|
+
}
|
|
12
|
+
if (Node.isObjectBindingPattern(nameNode) || Node.isArrayBindingPattern(nameNode)) {
|
|
13
|
+
const names = new Set();
|
|
14
|
+
for (const element of nameNode.getElements()) {
|
|
15
|
+
if (Node.isBindingElement(element)) {
|
|
16
|
+
const elementName = element.getNameNode();
|
|
17
|
+
if (Node.isIdentifier(elementName)) {
|
|
18
|
+
names.add(elementName.getText());
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return names;
|
|
23
|
+
}
|
|
24
|
+
// Unknown binding pattern — treat as referenced to avoid false positives
|
|
25
|
+
return new Set();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Find catch clauses in the body that don't reference the caught error.
|
|
29
|
+
*
|
|
30
|
+
* A catch clause is "silent" if:
|
|
31
|
+
* 1. It has no binding at all (`catch { ... }`) — no error to reference
|
|
32
|
+
* 2. It has a binding but no Identifier in the block body matches any binding name
|
|
33
|
+
*
|
|
34
|
+
* Uses a simple descendant Identifier walk instead of the Language Service's
|
|
35
|
+
* findReferencesAsNodes() — catch variables are block-scoped so a name match
|
|
36
|
+
* within the block is sufficient. This is faster and avoids edge cases where
|
|
37
|
+
* findReferencesAsNodes() returns zero refs for destructured bindings.
|
|
38
|
+
*
|
|
39
|
+
* **Known limitations (false negatives):**
|
|
40
|
+
* - Variable shadowing: `catch (err) { const err = new Error(); throw err }`
|
|
41
|
+
* — the `err` Identifier matches but refers to the redeclared variable.
|
|
42
|
+
* - Nested catch with same name: `catch (err) { try { } catch (err) { log(err) } }`
|
|
43
|
+
* — the inner `err` usage satisfies the outer check.
|
|
44
|
+
* Both are rare in practice and arguably code smells themselves.
|
|
45
|
+
*/
|
|
46
|
+
export function findSilentCatches(body) {
|
|
47
|
+
const results = [];
|
|
48
|
+
for (const catchClause of body.getDescendantsOfKind(SyntaxKind.CatchClause)) {
|
|
49
|
+
const varDecl = catchClause.getVariableDeclaration();
|
|
50
|
+
if (!varDecl) {
|
|
51
|
+
// catch { ... } — no binding at all, always a violation
|
|
52
|
+
results.push({
|
|
53
|
+
node: catchClause,
|
|
54
|
+
message: 'catch block has no error binding — error is silently discarded',
|
|
55
|
+
});
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
// Collect the binding names to search for
|
|
59
|
+
const bindingNames = getBindingNames(varDecl.getNameNode());
|
|
60
|
+
// No binding names extracted (e.g., unusual pattern) — skip to avoid false positive
|
|
61
|
+
if (bindingNames.size === 0)
|
|
62
|
+
continue;
|
|
63
|
+
// Walk the catch block for Identifier nodes matching any binding name
|
|
64
|
+
const block = catchClause.getBlock();
|
|
65
|
+
const hasReference = block
|
|
66
|
+
.getDescendantsOfKind(SyntaxKind.Identifier)
|
|
67
|
+
.some((id) => bindingNames.has(id.getText()));
|
|
68
|
+
if (!hasReference) {
|
|
69
|
+
const varName = varDecl.getName();
|
|
70
|
+
results.push({
|
|
71
|
+
node: catchClause,
|
|
72
|
+
message: `catch block binds '${varName}' but never references it — error is silently discarded`,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return results;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=catch-analysis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catch-analysis.js","sourceRoot":"","sources":["../../src/conditions/catch-analysis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAa3C;;;;;GAKG;AACH,SAAS,eAAe,CAAC,QAAc;IACrC,IAAI,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChC,OAAO,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;IACtC,CAAC;IAED,IAAI,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,qBAAqB,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClF,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAA;QAC/B,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC;YAC7C,IAAI,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;gBACnC,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,EAAE,CAAA;gBACzC,IAAI,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,EAAE,CAAC;oBACnC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC,CAAA;gBAClC,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;IAED,yEAAyE;IACzE,OAAO,IAAI,GAAG,EAAU,CAAA;AAC1B,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAU;IAC1C,MAAM,OAAO,GAAwB,EAAE,CAAA;IAEvC,KAAK,MAAM,WAAW,IAAI,IAAI,CAAC,oBAAoB,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5E,MAAM,OAAO,GAAG,WAAW,CAAC,sBAAsB,EAAE,CAAA;QAEpD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,wDAAwD;YACxD,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,gEAAgE;aAC1E,CAAC,CAAA;YACF,SAAQ;QACV,CAAC;QAED,0CAA0C;QAC1C,MAAM,YAAY,GAAG,eAAe,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAA;QAE3D,oFAAoF;QACpF,IAAI,YAAY,CAAC,IAAI,KAAK,CAAC;YAAE,SAAQ;QAErC,sEAAsE;QACtE,MAAM,KAAK,GAAG,WAAW,CAAC,QAAQ,EAAE,CAAA;QACpC,MAAM,YAAY,GAAG,KAAK;aACvB,oBAAoB,CAAC,UAAU,CAAC,UAAU,CAAC;aAC3C,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;QAE/C,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,CAAA;YACjC,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,sBAAsB,OAAO,yDAAyD;aAChG,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ClassDeclaration } from 'ts-morph';
|
|
2
|
+
import type { Condition } from '@nielspeter/eess';
|
|
3
|
+
import type { TypeMatcher } from '../helpers/type-matchers.js';
|
|
4
|
+
/**
|
|
5
|
+
* Assert that classes extend the named base class.
|
|
6
|
+
*/
|
|
7
|
+
export declare function shouldExtend(className: string): Condition<ClassDeclaration>;
|
|
8
|
+
/**
|
|
9
|
+
* Assert that classes implement the named interface.
|
|
10
|
+
*/
|
|
11
|
+
export declare function shouldImplement(interfaceName: string): Condition<ClassDeclaration>;
|
|
12
|
+
/**
|
|
13
|
+
* Assert that classes have a method with the given name.
|
|
14
|
+
*/
|
|
15
|
+
export declare function shouldHaveMethodNamed(name: string): Condition<ClassDeclaration>;
|
|
16
|
+
/**
|
|
17
|
+
* Assert that classes do NOT have any methods matching the regex.
|
|
18
|
+
*/
|
|
19
|
+
export declare function shouldNotHaveMethodMatching(regex: RegExp): Condition<ClassDeclaration>;
|
|
20
|
+
/**
|
|
21
|
+
* Assert that at least one parameter across the class's constructors,
|
|
22
|
+
* methods, and set accessors has a type matching the given matcher.
|
|
23
|
+
*
|
|
24
|
+
* Passes when at least one parameter satisfies `matcher`.
|
|
25
|
+
* Reports one violation per class that has no matching parameter.
|
|
26
|
+
*
|
|
27
|
+
* **Scope note:** This scans constructors, methods, AND set accessors.
|
|
28
|
+
* The function-level counterpart (`functions(p).should().acceptParameterOfType(...)`)
|
|
29
|
+
* does NOT scan set accessors because `collectFunctions()` excludes them.
|
|
30
|
+
*/
|
|
31
|
+
export declare function acceptParameterOfType(matcher: TypeMatcher): Condition<ClassDeclaration>;
|
|
32
|
+
export declare function notAcceptParameterOfType(matcher: TypeMatcher): Condition<ClassDeclaration>;
|
|
33
|
+
//# sourceMappingURL=class.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"class.d.ts","sourceRoot":"","sources":["../../src/conditions/class.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAwB,MAAM,UAAU,CAAA;AACtE,OAAO,KAAK,EAAE,SAAS,EAAoB,MAAM,kBAAkB,CAAA;AAInE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AAE9D;;GAEG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAM3E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAMlF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAM/E;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAYtF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAyBvF;AAkDD,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAW1F"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { elementCondition } from './helpers.js';
|
|
2
|
+
import { createViolation, getElementName } from '../core/violation.js';
|
|
3
|
+
/**
|
|
4
|
+
* Assert that classes extend the named base class.
|
|
5
|
+
*/
|
|
6
|
+
export function shouldExtend(className) {
|
|
7
|
+
return elementCondition(`extend "${className}"`, (cls) => cls.getExtends()?.getExpression().getText() === className, (cls) => `${getElementName(cls)} does not extend "${className}"`);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Assert that classes implement the named interface.
|
|
11
|
+
*/
|
|
12
|
+
export function shouldImplement(interfaceName) {
|
|
13
|
+
return elementCondition(`implement "${interfaceName}"`, (cls) => cls.getImplements().some((impl) => impl.getExpression().getText() === interfaceName), (cls) => `${getElementName(cls)} does not implement "${interfaceName}"`);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Assert that classes have a method with the given name.
|
|
17
|
+
*/
|
|
18
|
+
export function shouldHaveMethodNamed(name) {
|
|
19
|
+
return elementCondition(`have method named "${name}"`, (cls) => cls.getMethod(name) !== undefined, (cls) => `${getElementName(cls)} does not have method "${name}"`);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Assert that classes do NOT have any methods matching the regex.
|
|
23
|
+
*/
|
|
24
|
+
export function shouldNotHaveMethodMatching(regex) {
|
|
25
|
+
return elementCondition(`not have methods matching ${String(regex)}`, (cls) => !cls.getMethods().some((m) => regex.test(m.getName())), (cls) => {
|
|
26
|
+
const matching = cls
|
|
27
|
+
.getMethods()
|
|
28
|
+
.filter((m) => regex.test(m.getName()))
|
|
29
|
+
.map((m) => m.getName());
|
|
30
|
+
return `${getElementName(cls)} has methods matching ${String(regex)}: ${matching.join(', ')}`;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Assert that at least one parameter across the class's constructors,
|
|
35
|
+
* methods, and set accessors has a type matching the given matcher.
|
|
36
|
+
*
|
|
37
|
+
* Passes when at least one parameter satisfies `matcher`.
|
|
38
|
+
* Reports one violation per class that has no matching parameter.
|
|
39
|
+
*
|
|
40
|
+
* **Scope note:** This scans constructors, methods, AND set accessors.
|
|
41
|
+
* The function-level counterpart (`functions(p).should().acceptParameterOfType(...)`)
|
|
42
|
+
* does NOT scan set accessors because `collectFunctions()` excludes them.
|
|
43
|
+
*/
|
|
44
|
+
export function acceptParameterOfType(matcher) {
|
|
45
|
+
return {
|
|
46
|
+
description: 'accept parameter of matching type',
|
|
47
|
+
evaluate(elements, context) {
|
|
48
|
+
const violations = [];
|
|
49
|
+
for (const cls of elements) {
|
|
50
|
+
const allParams = [
|
|
51
|
+
...cls.getConstructors().flatMap((c) => c.getParameters()),
|
|
52
|
+
...cls.getMethods().flatMap((m) => m.getParameters()),
|
|
53
|
+
...cls.getSetAccessors().flatMap((s) => s.getParameters()),
|
|
54
|
+
];
|
|
55
|
+
const hasMatch = allParams.some((p) => matcher(p.getType()));
|
|
56
|
+
if (!hasMatch) {
|
|
57
|
+
violations.push(createViolation(cls, `${getElementName(cls)} has no parameter with matching type`, context));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return violations;
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Assert that NO parameter across the class's constructors, methods,
|
|
66
|
+
* and set accessors has a type matching the given matcher.
|
|
67
|
+
*
|
|
68
|
+
* Reports one violation **per parameter** whose type satisfies `matcher`,
|
|
69
|
+
* with actionable messages including the member name and parameter name.
|
|
70
|
+
*
|
|
71
|
+
* **Scope note:** This scans constructors, methods, AND set accessors.
|
|
72
|
+
* The function-level counterpart (`functions(p).should().notAcceptParameterOfType(...)`)
|
|
73
|
+
* does NOT scan set accessors because `collectFunctions()` excludes them.
|
|
74
|
+
*/
|
|
75
|
+
/**
|
|
76
|
+
* Scan parameters of class members (constructors, methods, set accessors) for
|
|
77
|
+
* types matching the given matcher. Returns a violation for each matching parameter.
|
|
78
|
+
*/
|
|
79
|
+
function scanParametersForType(cls, typeMatcher, context) {
|
|
80
|
+
const violations = [];
|
|
81
|
+
const className = getElementName(cls);
|
|
82
|
+
const members = [
|
|
83
|
+
...cls.getConstructors().map((c) => ({ memberName: 'constructor', params: c.getParameters() })),
|
|
84
|
+
...cls.getMethods().map((m) => ({ memberName: m.getName(), params: m.getParameters() })),
|
|
85
|
+
...cls.getSetAccessors().map((s) => ({ memberName: s.getName(), params: s.getParameters() })),
|
|
86
|
+
];
|
|
87
|
+
for (const { memberName, params } of members) {
|
|
88
|
+
for (const param of params) {
|
|
89
|
+
if (typeMatcher(param.getType())) {
|
|
90
|
+
const paramName = param.getName();
|
|
91
|
+
const typeText = param.getType().getText();
|
|
92
|
+
violations.push(createViolation(cls, `${className}.${memberName} parameter "${paramName}" has type "${typeText}"`, context));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return violations;
|
|
97
|
+
}
|
|
98
|
+
export function notAcceptParameterOfType(matcher) {
|
|
99
|
+
return {
|
|
100
|
+
description: 'not accept parameter of matching type',
|
|
101
|
+
evaluate(elements, context) {
|
|
102
|
+
const violations = [];
|
|
103
|
+
for (const cls of elements) {
|
|
104
|
+
violations.push(...scanParametersForType(cls, matcher, context));
|
|
105
|
+
}
|
|
106
|
+
return violations;
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=class.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"class.js","sourceRoot":"","sources":["../../src/conditions/class.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { SourceFile } from 'ts-morph';
|
|
2
|
+
import type { PairCondition } from '../core/pair-condition.js';
|
|
3
|
+
import type { ArchViolation } from '../core/violation.js';
|
|
4
|
+
import type { LayerPair, Layer } from '../models/cross-layer.js';
|
|
5
|
+
/**
|
|
6
|
+
* Every element in the left layer must have at least one match in the right layer.
|
|
7
|
+
*
|
|
8
|
+
* Produces a violation for each left-layer file that has no matching pair.
|
|
9
|
+
* "Match" is determined by the mapping function provided via `.mapping()`.
|
|
10
|
+
*
|
|
11
|
+
* @param layers - The resolved layers, needed to identify unmatched left files
|
|
12
|
+
*/
|
|
13
|
+
export declare function haveMatchingCounterpart(layers: Layer[]): PairCondition;
|
|
14
|
+
/**
|
|
15
|
+
* The matched pair must have consistent exported symbol names.
|
|
16
|
+
*
|
|
17
|
+
* Takes two extractor functions that pull symbol names from each side.
|
|
18
|
+
* Every symbol extracted from the left file must appear in the right file.
|
|
19
|
+
*/
|
|
20
|
+
export declare function haveConsistentExports(extractLeft: (file: SourceFile) => string[], extractRight: (file: SourceFile) => string[]): PairCondition;
|
|
21
|
+
/**
|
|
22
|
+
* Custom pair assertion — shorthand for inline PairCondition.
|
|
23
|
+
*
|
|
24
|
+
* The provided function is called for each pair. Return an `ArchViolation`
|
|
25
|
+
* to signal failure, or `null` if the pair is consistent.
|
|
26
|
+
*/
|
|
27
|
+
export declare function satisfyPairCondition(description: string, fn: (pair: LayerPair) => ArchViolation | null): PairCondition;
|
|
28
|
+
//# sourceMappingURL=cross-layer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross-layer.d.ts","sourceRoot":"","sources":["../../src/conditions/cross-layer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAE9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAA;AAEhE;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,aAAa,CA2CtE;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,MAAM,EAAE,EAC3C,YAAY,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,MAAM,EAAE,GAC3C,aAAa,CA8Bf;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,aAAa,GAAG,IAAI,GAC5C,aAAa,CAcf"}
|