@nielspeter/eess-ts 0.2.0 → 0.4.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/README.md +87 -34
- package/dist/builders/call-rule-builder.d.ts +66 -26
- package/dist/builders/call-rule-builder.d.ts.map +1 -1
- package/dist/builders/call-rule-builder.js +73 -31
- package/dist/builders/call-rule-builder.js.map +1 -1
- package/dist/builders/class-rule-builder.d.ts +125 -26
- package/dist/builders/class-rule-builder.d.ts.map +1 -1
- package/dist/builders/class-rule-builder.js +134 -30
- package/dist/builders/class-rule-builder.js.map +1 -1
- package/dist/builders/correspondence-builder.d.ts +287 -0
- package/dist/builders/correspondence-builder.d.ts.map +1 -0
- package/dist/builders/correspondence-builder.js +393 -0
- package/dist/builders/correspondence-builder.js.map +1 -0
- package/dist/builders/correspondence-findings.d.ts +104 -0
- package/dist/builders/correspondence-findings.d.ts.map +1 -0
- package/dist/builders/correspondence-findings.js +301 -0
- package/dist/builders/correspondence-findings.js.map +1 -0
- package/dist/builders/cross-layer-builder.d.ts +99 -16
- package/dist/builders/cross-layer-builder.d.ts.map +1 -1
- package/dist/builders/cross-layer-builder.js +181 -35
- package/dist/builders/cross-layer-builder.js.map +1 -1
- package/dist/builders/function-rule-builder.d.ts +144 -25
- package/dist/builders/function-rule-builder.d.ts.map +1 -1
- package/dist/builders/function-rule-builder.js +173 -26
- package/dist/builders/function-rule-builder.js.map +1 -1
- package/dist/builders/jsx-rule-builder.d.ts +70 -14
- package/dist/builders/jsx-rule-builder.d.ts.map +1 -1
- package/dist/builders/jsx-rule-builder.js +73 -14
- package/dist/builders/jsx-rule-builder.js.map +1 -1
- package/dist/builders/module-rule-builder.d.ts +2 -2
- package/dist/builders/module-rule-builder.d.ts.map +1 -1
- package/dist/builders/module-rule-builder.js +12 -3
- package/dist/builders/module-rule-builder.js.map +1 -1
- package/dist/builders/scoped-function-rule-builder.d.ts +11 -0
- package/dist/builders/scoped-function-rule-builder.d.ts.map +1 -1
- package/dist/builders/scoped-function-rule-builder.js +12 -0
- package/dist/builders/scoped-function-rule-builder.js.map +1 -1
- package/dist/builders/slice-discovery-message.d.ts +36 -0
- package/dist/builders/slice-discovery-message.d.ts.map +1 -0
- package/dist/builders/slice-discovery-message.js +181 -0
- package/dist/builders/slice-discovery-message.js.map +1 -0
- package/dist/builders/slice-rule-builder.d.ts +151 -12
- package/dist/builders/slice-rule-builder.d.ts.map +1 -1
- package/dist/builders/slice-rule-builder.js +242 -35
- package/dist/builders/slice-rule-builder.js.map +1 -1
- package/dist/builders/type-rule-builder.d.ts +95 -24
- package/dist/builders/type-rule-builder.d.ts.map +1 -1
- package/dist/builders/type-rule-builder.js +105 -29
- package/dist/builders/type-rule-builder.js.map +1 -1
- package/dist/{helpers → builders}/within.d.ts +2 -2
- package/dist/builders/within.d.ts.map +1 -0
- package/dist/{helpers → builders}/within.js +1 -1
- package/dist/builders/within.js.map +1 -0
- package/dist/cli/commands/baseline.d.ts +3 -2
- package/dist/cli/commands/baseline.d.ts.map +1 -1
- package/dist/cli/commands/baseline.js +68 -6
- package/dist/cli/commands/baseline.js.map +1 -1
- package/dist/cli/commands/check.d.ts +7 -2
- package/dist/cli/commands/check.d.ts.map +1 -1
- package/dist/cli/commands/check.js +241 -45
- package/dist/cli/commands/check.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts +29 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +224 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/explain.d.ts +2 -1
- package/dist/cli/commands/explain.d.ts.map +1 -1
- package/dist/cli/commands/explain.js +19 -10
- package/dist/cli/commands/explain.js.map +1 -1
- package/dist/cli/commands/init.d.ts +9 -3
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +162 -137
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/import-rule-module.d.ts +29 -0
- package/dist/cli/import-rule-module.d.ts.map +1 -0
- package/dist/cli/import-rule-module.js +60 -0
- package/dist/cli/import-rule-module.js.map +1 -0
- package/dist/cli/index.d.ts +2 -2
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +98 -33
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/load-rules.d.ts +6 -11
- package/dist/cli/load-rules.d.ts.map +1 -1
- package/dist/cli/load-rules.js +21 -29
- package/dist/cli/load-rules.js.map +1 -1
- package/dist/cli/resolve-config.d.ts.map +1 -1
- package/dist/cli/resolve-config.js +24 -14
- package/dist/cli/resolve-config.js.map +1 -1
- package/dist/cli/rule-file-findings.d.ts +178 -0
- package/dist/cli/rule-file-findings.d.ts.map +1 -0
- package/dist/cli/rule-file-findings.js +293 -0
- package/dist/cli/rule-file-findings.js.map +1 -0
- package/dist/cli/watch.d.ts +20 -7
- package/dist/cli/watch.d.ts.map +1 -1
- package/dist/cli/watch.js +39 -14
- package/dist/cli/watch.js.map +1 -1
- package/dist/conditions/body-analysis-function.d.ts.map +1 -1
- package/dist/conditions/body-analysis-function.js +16 -7
- package/dist/conditions/body-analysis-function.js.map +1 -1
- package/dist/conditions/body-analysis-module.d.ts.map +1 -1
- package/dist/conditions/body-analysis-module.js +14 -9
- package/dist/conditions/body-analysis-module.js.map +1 -1
- package/dist/conditions/body-analysis.d.ts.map +1 -1
- package/dist/conditions/body-analysis.js +16 -7
- package/dist/conditions/body-analysis.js.map +1 -1
- package/dist/conditions/call.d.ts.map +1 -1
- package/dist/conditions/call.js +38 -17
- package/dist/conditions/call.js.map +1 -1
- package/dist/conditions/catch-analysis.d.ts +2 -1
- package/dist/conditions/catch-analysis.d.ts.map +1 -1
- package/dist/conditions/catch-analysis.js.map +1 -1
- package/dist/conditions/cross-layer.d.ts +2 -10
- package/dist/conditions/cross-layer.d.ts.map +1 -1
- package/dist/conditions/cross-layer.js +227 -23
- package/dist/conditions/cross-layer.js.map +1 -1
- package/dist/conditions/dependency.d.ts +35 -6
- package/dist/conditions/dependency.d.ts.map +1 -1
- package/dist/conditions/dependency.js +299 -45
- package/dist/conditions/dependency.js.map +1 -1
- package/dist/conditions/exports.d.ts.map +1 -1
- package/dist/conditions/exports.js +10 -0
- package/dist/conditions/exports.js.map +1 -1
- package/dist/conditions/function.d.ts.map +1 -1
- package/dist/conditions/function.js +19 -5
- package/dist/conditions/function.js.map +1 -1
- package/dist/conditions/helpers.d.ts +2 -1
- package/dist/conditions/helpers.d.ts.map +1 -1
- package/dist/conditions/helpers.js +4 -1
- package/dist/conditions/helpers.js.map +1 -1
- package/dist/conditions/jsx.d.ts.map +1 -1
- package/dist/conditions/jsx.js +7 -2
- package/dist/conditions/jsx.js.map +1 -1
- package/dist/conditions/match-identity.d.ts +43 -0
- package/dist/conditions/match-identity.d.ts.map +1 -0
- package/dist/conditions/match-identity.js +43 -0
- package/dist/conditions/match-identity.js.map +1 -0
- package/dist/conditions/members.d.ts.map +1 -1
- package/dist/conditions/members.js +17 -4
- package/dist/conditions/members.js.map +1 -1
- package/dist/conditions/reverse-dependency.d.ts +18 -5
- package/dist/conditions/reverse-dependency.d.ts.map +1 -1
- package/dist/conditions/reverse-dependency.js +109 -92
- package/dist/conditions/reverse-dependency.js.map +1 -1
- package/dist/conditions/slice.d.ts +86 -2
- package/dist/conditions/slice.d.ts.map +1 -1
- package/dist/conditions/slice.js +234 -53
- package/dist/conditions/slice.js.map +1 -1
- package/dist/conditions/structural.d.ts.map +1 -1
- package/dist/conditions/structural.js +16 -4
- package/dist/conditions/structural.js.map +1 -1
- package/dist/core/check-all.d.ts +19 -0
- package/dist/core/check-all.d.ts.map +1 -0
- package/dist/core/check-all.js +96 -0
- package/dist/core/check-all.js.map +1 -0
- package/dist/core/combinators.d.ts +48 -0
- package/dist/core/combinators.d.ts.map +1 -0
- package/dist/core/combinators.js +56 -0
- package/dist/core/combinators.js.map +1 -0
- package/dist/core/descendant-cache.d.ts +36 -0
- package/dist/core/descendant-cache.d.ts.map +1 -0
- package/dist/core/descendant-cache.js +119 -0
- package/dist/core/descendant-cache.js.map +1 -0
- package/dist/core/diagnose.d.ts +234 -0
- package/dist/core/diagnose.d.ts.map +1 -0
- package/dist/core/diagnose.js +382 -0
- package/dist/core/diagnose.js.map +1 -0
- package/dist/core/disk-set.d.ts +48 -0
- package/dist/core/disk-set.d.ts.map +1 -0
- package/dist/core/disk-set.js +218 -0
- package/dist/core/disk-set.js.map +1 -0
- package/dist/core/element-cache.d.ts +75 -0
- package/dist/core/element-cache.d.ts.map +1 -0
- package/dist/core/element-cache.js +32 -0
- package/dist/core/element-cache.js.map +1 -0
- package/dist/core/empty-project-advice.d.ts +75 -0
- package/dist/core/empty-project-advice.d.ts.map +1 -0
- package/dist/core/empty-project-advice.js +61 -0
- package/dist/core/empty-project-advice.js.map +1 -0
- package/dist/core/exclusion-comments.d.ts +54 -0
- package/dist/core/exclusion-comments.d.ts.map +1 -0
- package/dist/core/exclusion-comments.js +310 -0
- package/dist/core/exclusion-comments.js.map +1 -0
- package/dist/core/execute-rule.d.ts +150 -0
- package/dist/core/execute-rule.d.ts.map +1 -0
- package/dist/core/execute-rule.js +580 -0
- package/dist/core/execute-rule.js.map +1 -0
- package/dist/core/glob-diagnosis.d.ts +78 -0
- package/dist/core/glob-diagnosis.d.ts.map +1 -0
- package/dist/core/glob-diagnosis.js +134 -0
- package/dist/core/glob-diagnosis.js.map +1 -0
- package/dist/core/glob-evaluator.d.ts +48 -0
- package/dist/core/glob-evaluator.d.ts.map +1 -0
- package/dist/core/glob-evaluator.js +89 -0
- package/dist/core/glob-evaluator.js.map +1 -0
- package/dist/core/import-candidates.d.ts +60 -0
- package/dist/core/import-candidates.d.ts.map +1 -0
- package/dist/core/import-candidates.js +93 -0
- package/dist/core/import-candidates.js.map +1 -0
- package/dist/core/import-options.d.ts +55 -2
- package/dist/core/import-options.d.ts.map +1 -1
- package/dist/core/import-options.js +64 -0
- package/dist/core/import-options.js.map +1 -1
- package/dist/core/line-index.d.ts +3 -0
- package/dist/core/line-index.d.ts.map +1 -0
- package/dist/core/line-index.js +229 -0
- package/dist/core/line-index.js.map +1 -0
- package/dist/core/metric-violation.d.ts +86 -0
- package/dist/core/metric-violation.d.ts.map +1 -0
- package/dist/core/metric-violation.js +132 -0
- package/dist/core/metric-violation.js.map +1 -0
- package/dist/core/module-edges.d.ts +361 -0
- package/dist/core/module-edges.d.ts.map +1 -0
- package/dist/core/module-edges.js +592 -0
- package/dist/core/module-edges.js.map +1 -0
- package/dist/core/object-literal-functions.d.ts +42 -0
- package/dist/core/object-literal-functions.d.ts.map +1 -0
- package/dist/core/object-literal-functions.js +75 -0
- package/dist/core/object-literal-functions.js.map +1 -0
- package/dist/core/orphan-exclusions.d.ts +44 -0
- package/dist/core/orphan-exclusions.d.ts.map +1 -0
- package/dist/core/orphan-exclusions.js +214 -0
- package/dist/core/orphan-exclusions.js.map +1 -0
- package/dist/core/pair-condition.d.ts +32 -3
- package/dist/core/pair-condition.d.ts.map +1 -1
- package/dist/core/path-universe.d.ts +54 -0
- package/dist/core/path-universe.d.ts.map +1 -0
- package/dist/core/path-universe.js +65 -0
- package/dist/core/path-universe.js.map +1 -0
- package/dist/core/per-root-compiler-options.d.ts +20 -0
- package/dist/core/per-root-compiler-options.d.ts.map +1 -0
- package/dist/core/per-root-compiler-options.js +57 -0
- package/dist/core/per-root-compiler-options.js.map +1 -0
- package/dist/core/project-relative.d.ts +98 -0
- package/dist/core/project-relative.d.ts.map +1 -0
- package/dist/core/project-relative.js +185 -0
- package/dist/core/project-relative.js.map +1 -0
- package/dist/core/project.d.ts +7 -1
- package/dist/core/project.d.ts.map +1 -1
- package/dist/core/project.js +24 -0
- package/dist/core/project.js.map +1 -1
- package/dist/core/rule-builder.d.ts +282 -0
- package/dist/core/rule-builder.d.ts.map +1 -0
- package/dist/core/rule-builder.js +445 -0
- package/dist/core/rule-builder.js.map +1 -0
- package/dist/core/rule-declaration.d.ts +32 -0
- package/dist/core/rule-declaration.d.ts.map +1 -0
- package/dist/core/rule-declaration.js +126 -0
- package/dist/core/rule-declaration.js.map +1 -0
- package/dist/core/terminal-builder.d.ts +625 -0
- package/dist/core/terminal-builder.d.ts.map +1 -0
- package/dist/core/terminal-builder.js +787 -0
- package/dist/core/terminal-builder.js.map +1 -0
- package/dist/core/terminal-execution.d.ts +23 -0
- package/dist/core/terminal-execution.d.ts.map +1 -0
- package/dist/core/terminal-execution.js +71 -0
- package/dist/core/terminal-execution.js.map +1 -0
- package/dist/core/vacuity-diagnosis.d.ts +103 -0
- package/dist/core/vacuity-diagnosis.d.ts.map +1 -0
- package/dist/core/vacuity-diagnosis.js +415 -0
- package/dist/core/vacuity-diagnosis.js.map +1 -0
- package/dist/core/violation.d.ts +16 -11
- package/dist/core/violation.d.ts.map +1 -1
- package/dist/core/violation.js +33 -13
- package/dist/core/violation.js.map +1 -1
- package/dist/graphql/index.js +1 -1
- package/dist/graphql/index.js.map +1 -1
- package/dist/graphql/resolver-rule-builder.d.ts +98 -23
- package/dist/graphql/resolver-rule-builder.d.ts.map +1 -1
- package/dist/graphql/resolver-rule-builder.js +151 -21
- package/dist/graphql/resolver-rule-builder.js.map +1 -1
- package/dist/graphql/schema-loader.d.ts +21 -0
- package/dist/graphql/schema-loader.d.ts.map +1 -1
- package/dist/graphql/schema-loader.js +81 -12
- package/dist/graphql/schema-loader.js.map +1 -1
- package/dist/graphql/schema-rule-builder.d.ts +57 -20
- package/dist/graphql/schema-rule-builder.d.ts.map +1 -1
- package/dist/graphql/schema-rule-builder.js +101 -25
- package/dist/graphql/schema-rule-builder.js.map +1 -1
- package/dist/helpers/baseline-diagnostics.d.ts +45 -0
- package/dist/helpers/baseline-diagnostics.d.ts.map +1 -0
- package/dist/helpers/baseline-diagnostics.js +168 -0
- package/dist/helpers/baseline-diagnostics.js.map +1 -0
- package/dist/helpers/baseline-generator.d.ts +19 -0
- package/dist/helpers/baseline-generator.d.ts.map +1 -0
- package/dist/helpers/baseline-generator.js +18 -0
- package/dist/helpers/baseline-generator.js.map +1 -0
- package/dist/helpers/baseline.d.ts +336 -0
- package/dist/helpers/baseline.d.ts.map +1 -0
- package/dist/helpers/baseline.js +664 -0
- package/dist/helpers/baseline.js.map +1 -0
- package/dist/helpers/body-traversal.d.ts +27 -2
- package/dist/helpers/body-traversal.d.ts.map +1 -1
- package/dist/helpers/body-traversal.js +122 -16
- package/dist/helpers/body-traversal.js.map +1 -1
- package/dist/helpers/callback-extractor.d.ts.map +1 -1
- package/dist/helpers/callback-extractor.js +48 -47
- package/dist/helpers/callback-extractor.js.map +1 -1
- package/dist/helpers/complexity.d.ts +13 -5
- package/dist/helpers/complexity.d.ts.map +1 -1
- package/dist/helpers/complexity.js +15 -6
- package/dist/helpers/complexity.js.map +1 -1
- package/dist/helpers/diff-aware.d.ts +44 -0
- package/dist/helpers/diff-aware.d.ts.map +1 -0
- package/dist/helpers/diff-aware.js +84 -0
- package/dist/helpers/diff-aware.js.map +1 -0
- package/dist/helpers/matchers.d.ts +68 -7
- package/dist/helpers/matchers.d.ts.map +1 -1
- package/dist/helpers/matchers.js +114 -20
- package/dist/helpers/matchers.js.map +1 -1
- package/dist/helpers/slice-graph.d.ts +100 -8
- package/dist/helpers/slice-graph.d.ts.map +1 -1
- package/dist/helpers/slice-graph.js +126 -34
- package/dist/helpers/slice-graph.js.map +1 -1
- package/dist/helpers/tarjan.d.ts +0 -14
- package/dist/helpers/tarjan.d.ts.map +1 -1
- package/dist/helpers/tarjan.js +29 -16
- package/dist/helpers/tarjan.js.map +1 -1
- package/dist/index.d.ts +56 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +57 -13
- package/dist/index.js.map +1 -1
- package/dist/models/arch-call.d.ts +3 -2
- package/dist/models/arch-call.d.ts.map +1 -1
- package/dist/models/arch-call.js.map +1 -1
- package/dist/models/arch-function.d.ts +28 -6
- package/dist/models/arch-function.d.ts.map +1 -1
- package/dist/models/arch-function.js +106 -3
- package/dist/models/arch-function.js.map +1 -1
- package/dist/models/arch-jsx-element.js +2 -2
- package/dist/models/arch-jsx-element.js.map +1 -1
- package/dist/models/slice.d.ts +33 -9
- package/dist/models/slice.d.ts.map +1 -1
- package/dist/models/slice.js +129 -19
- package/dist/models/slice.js.map +1 -1
- package/dist/predicates/call.d.ts.map +1 -1
- package/dist/predicates/call.js +5 -0
- package/dist/predicates/call.js.map +1 -1
- package/dist/predicates/identity.d.ts +21 -0
- package/dist/predicates/identity.d.ts.map +1 -1
- package/dist/predicates/identity.js +75 -3
- package/dist/predicates/identity.js.map +1 -1
- package/dist/predicates/index.d.ts +1 -1
- package/dist/predicates/index.d.ts.map +1 -1
- package/dist/predicates/index.js +1 -1
- package/dist/predicates/index.js.map +1 -1
- package/dist/predicates/metrics.d.ts +4 -2
- package/dist/predicates/metrics.d.ts.map +1 -1
- package/dist/predicates/metrics.js +4 -2
- package/dist/predicates/metrics.js.map +1 -1
- package/dist/predicates/module.d.ts +4 -12
- package/dist/predicates/module.d.ts.map +1 -1
- package/dist/predicates/module.js +57 -37
- package/dist/predicates/module.js.map +1 -1
- package/dist/presets/agent-guardrails.d.ts +22 -15
- package/dist/presets/agent-guardrails.d.ts.map +1 -1
- package/dist/presets/agent-guardrails.js +124 -19
- package/dist/presets/agent-guardrails.js.map +1 -1
- package/dist/presets/boundaries.d.ts +45 -2
- package/dist/presets/boundaries.d.ts.map +1 -1
- package/dist/presets/boundaries.js +132 -23
- package/dist/presets/boundaries.js.map +1 -1
- package/dist/presets/data-layer.d.ts +22 -2
- package/dist/presets/data-layer.d.ts.map +1 -1
- package/dist/presets/data-layer.js +58 -16
- package/dist/presets/data-layer.js.map +1 -1
- package/dist/presets/index.d.ts +7 -5
- package/dist/presets/index.d.ts.map +1 -1
- package/dist/presets/index.js +9 -3
- package/dist/presets/index.js.map +1 -1
- package/dist/presets/layered.d.ts +46 -2
- package/dist/presets/layered.d.ts.map +1 -1
- package/dist/presets/layered.js +66 -29
- package/dist/presets/layered.js.map +1 -1
- package/dist/presets/recommended.d.ts +80 -9
- package/dist/presets/recommended.d.ts.map +1 -1
- package/dist/presets/recommended.js +25 -23
- package/dist/presets/recommended.js.map +1 -1
- package/dist/presets/shared.d.ts +270 -2
- package/dist/presets/shared.d.ts.map +1 -1
- package/dist/presets/shared.js +338 -4
- package/dist/presets/shared.js.map +1 -1
- package/dist/rules/code-quality.d.ts.map +1 -1
- package/dist/rules/code-quality.js +15 -6
- package/dist/rules/code-quality.js.map +1 -1
- package/dist/rules/hygiene.d.ts +1 -1
- package/dist/rules/hygiene.js +1 -1
- package/dist/rules/metrics-function.d.ts +2 -1
- package/dist/rules/metrics-function.d.ts.map +1 -1
- package/dist/rules/metrics-function.js +33 -6
- package/dist/rules/metrics-function.js.map +1 -1
- package/dist/rules/metrics.d.ts +2 -1
- package/dist/rules/metrics.d.ts.map +1 -1
- package/dist/rules/metrics.js +39 -9
- package/dist/rules/metrics.js.map +1 -1
- package/dist/smells/duplicate-bodies.d.ts +58 -5
- package/dist/smells/duplicate-bodies.d.ts.map +1 -1
- package/dist/smells/duplicate-bodies.js +137 -56
- package/dist/smells/duplicate-bodies.js.map +1 -1
- package/dist/smells/fingerprint.d.ts +8 -1
- package/dist/smells/fingerprint.d.ts.map +1 -1
- package/dist/smells/fingerprint.js +21 -3
- package/dist/smells/fingerprint.js.map +1 -1
- package/dist/smells/inconsistent-siblings.d.ts +128 -7
- package/dist/smells/inconsistent-siblings.d.ts.map +1 -1
- package/dist/smells/inconsistent-siblings.js +288 -86
- package/dist/smells/inconsistent-siblings.js.map +1 -1
- package/dist/smells/sibling-files.d.ts +47 -0
- package/dist/smells/sibling-files.d.ts.map +1 -0
- package/dist/smells/sibling-files.js +104 -0
- package/dist/smells/sibling-files.js.map +1 -0
- package/dist/smells/similar-pairs.d.ts +27 -0
- package/dist/smells/similar-pairs.d.ts.map +1 -0
- package/dist/smells/similar-pairs.js +52 -0
- package/dist/smells/similar-pairs.js.map +1 -0
- package/dist/smells/smell-builder.d.ts +57 -12
- package/dist/smells/smell-builder.d.ts.map +1 -1
- package/dist/smells/smell-builder.js +111 -14
- package/dist/smells/smell-builder.js.map +1 -1
- package/dist/tsconfig/index.d.ts +19 -0
- package/dist/tsconfig/index.d.ts.map +1 -0
- package/dist/tsconfig/index.js +20 -0
- package/dist/tsconfig/index.js.map +1 -0
- package/dist/tsconfig/tsconfig-builder.d.ts +42 -9
- package/dist/tsconfig/tsconfig-builder.d.ts.map +1 -1
- package/dist/tsconfig/tsconfig-builder.js +64 -16
- package/dist/tsconfig/tsconfig-builder.js.map +1 -1
- package/package.json +3 -2
- package/dist/core/module-dependencies.d.ts +0 -28
- package/dist/core/module-dependencies.d.ts.map +0 -1
- package/dist/core/module-dependencies.js +0 -35
- package/dist/core/module-dependencies.js.map +0 -1
- package/dist/helpers/within.d.ts.map +0 -1
- package/dist/helpers/within.js.map +0 -1
|
@@ -1,37 +1,101 @@
|
|
|
1
1
|
import picomatch from 'picomatch';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import { selectionMemo } from '@nielspeter/eess';
|
|
3
4
|
import { SmellBuilder } from './smell-builder.js';
|
|
4
5
|
import { collectFunctions } from '../models/arch-function.js';
|
|
5
|
-
import {
|
|
6
|
+
import { fingerprintAll, findSimilarPairs } from './similar-pairs.js';
|
|
7
|
+
import { relativeToRoot } from '../core/project-relative.js';
|
|
6
8
|
/** Test file patterns for ignoreTests(). */
|
|
7
9
|
const TEST_PATTERNS = ['**/*.test.ts', '**/*.spec.ts', '**/__tests__/**'];
|
|
10
|
+
const selectionOf = selectionMemo();
|
|
8
11
|
export class DuplicateBodiesBuilder extends SmellBuilder {
|
|
9
12
|
_minSimilarity = 0.85;
|
|
13
|
+
_minDistinctVocabulary = 8;
|
|
10
14
|
constructor(project) {
|
|
11
15
|
super(project);
|
|
12
16
|
}
|
|
13
17
|
/** Set the AST similarity threshold. Default: 0.85. */
|
|
14
18
|
withMinSimilarity(threshold) {
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
const next = this.copy();
|
|
20
|
+
next._minSimilarity = threshold;
|
|
21
|
+
return next;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Minimum count of distinct identifier/literal text either body must carry
|
|
25
|
+
* before a pair is even compared — not raw line count, and not similarity.
|
|
26
|
+
* Two bodies can share a syntactic shape for no reason other than the shape
|
|
27
|
+
* being mandated (a wither, a getter, a boilerplate skeleton); below this
|
|
28
|
+
* threshold a "match" carries no information about what the code actually
|
|
29
|
+
* does. Default: 8 — see plan 0103's Phase 0 triage for how it was chosen.
|
|
30
|
+
* Tune down for a codebase with terser naming than this default assumes;
|
|
31
|
+
* tune up if short, low-vocabulary bodies keep surfacing as noise.
|
|
32
|
+
*/
|
|
33
|
+
minDistinctVocabulary(n) {
|
|
34
|
+
const next = this.copy();
|
|
35
|
+
next._minDistinctVocabulary = n;
|
|
36
|
+
return next;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Named by id or by what the detector checks — the inherited version returns
|
|
40
|
+
* the sentinel `'unnamed'`, and `inconsistent-siblings.ts` already carries this
|
|
41
|
+
* override for that reason.
|
|
42
|
+
*
|
|
43
|
+
* It became load-bearing in plan 0099: the floor makes an over-filtered
|
|
44
|
+
* detector FAIL, and `dedupeConfigFindings` keys on `(file, ruleId ?? rule,
|
|
45
|
+
* element)`. With `file: ''` and `'unnamed'` in both other slots, three
|
|
46
|
+
* genuinely different detectors — different similarity, different
|
|
47
|
+
* `ignorePaths` — collapsed into one finding claiming they were "one option"
|
|
48
|
+
* and "one edit". Two were silently discarded and the survivor said
|
|
49
|
+
* `Rule: unnamed`.
|
|
50
|
+
*/
|
|
51
|
+
describeRule() {
|
|
52
|
+
return {
|
|
53
|
+
...super.describeRule(),
|
|
54
|
+
rule: this._metadata?.id ?? this.describe(),
|
|
55
|
+
};
|
|
17
56
|
}
|
|
18
57
|
detect() {
|
|
19
|
-
const functions = this.
|
|
20
|
-
const fingerprinted =
|
|
21
|
-
const pairs =
|
|
58
|
+
const functions = this.selected();
|
|
59
|
+
const fingerprinted = fingerprintAll(functions);
|
|
60
|
+
const pairs = findSimilarPairs(fingerprinted, this._minSimilarity, this._minDistinctVocabulary);
|
|
22
61
|
return this.buildViolations(pairs);
|
|
23
62
|
}
|
|
24
63
|
describe() {
|
|
25
64
|
const scope = this._folders.length > 0 ? this._folders.join(', ') : 'all files';
|
|
26
|
-
|
|
65
|
+
// EVERY narrowing that distinguishes two instances, not just similarity.
|
|
66
|
+
//
|
|
67
|
+
// This is the `Rule:` line a reader sees, and since plan 0099 it is also the
|
|
68
|
+
// dedupe identity for a detector with no `.rule({ id })`. Rendering only
|
|
69
|
+
// folders and similarity meant three detectors differing in `minLines` shared
|
|
70
|
+
// one key: measured, 3 findings collapsed to 1 claiming they were "one edit",
|
|
71
|
+
// and fixing the surviving threshold left the other two dead and green.
|
|
72
|
+
const filters = [
|
|
73
|
+
`minLines >= ${String(this._minLines)}`,
|
|
74
|
+
`minDistinctVocabulary >= ${String(this._minDistinctVocabulary)}`,
|
|
75
|
+
];
|
|
76
|
+
if (this._ignorePaths.length > 0)
|
|
77
|
+
filters.push(`ignoring ${this._ignorePaths.join(', ')}`);
|
|
78
|
+
if (this._ignoreTests)
|
|
79
|
+
filters.push('ignoring tests');
|
|
80
|
+
return (`No duplicate function bodies in ${scope} ` +
|
|
81
|
+
`(similarity >= ${String(this._minSimilarity)}, ${filters.join(', ')})`);
|
|
27
82
|
}
|
|
28
83
|
/** Check if a file path passes all glob-based filters. */
|
|
29
|
-
|
|
30
|
-
|
|
84
|
+
/**
|
|
85
|
+
* The three matcher sets travel together as one `filters` — they are one
|
|
86
|
+
* configuration, and four positional `picomatch.Matcher[]` arguments in a row
|
|
87
|
+
* are exactly the transposition risk the parameter cap exists to prevent.
|
|
88
|
+
*/
|
|
89
|
+
passesFileFilters(filePath, filters, fromRoot) {
|
|
90
|
+
const { folderMatchers, ignoreMatchers, testMatchers } = filters;
|
|
91
|
+
// Both forms, for every set — bug 0036. A project-relative `inFolder()` or
|
|
92
|
+
// `ignorePaths()` glob could never match an absolute path.
|
|
93
|
+
const hits = (ms) => ms.some((m) => m(filePath)) || (fromRoot !== undefined && ms.some((m) => m(fromRoot)));
|
|
94
|
+
if (folderMatchers.length > 0 && !hits(folderMatchers))
|
|
31
95
|
return false;
|
|
32
|
-
if (ignoreMatchers
|
|
96
|
+
if (hits(ignoreMatchers))
|
|
33
97
|
return false;
|
|
34
|
-
if (testMatchers
|
|
98
|
+
if (hits(testMatchers))
|
|
35
99
|
return false;
|
|
36
100
|
return true;
|
|
37
101
|
}
|
|
@@ -44,6 +108,27 @@ export class DuplicateBodiesBuilder extends SmellBuilder {
|
|
|
44
108
|
return lineCount >= this._minLines;
|
|
45
109
|
}
|
|
46
110
|
/** Collect all functions matching folder/path/test filters. */
|
|
111
|
+
/**
|
|
112
|
+
* Bodies entering pairwise comparison — plan 0096, and the ONE method both
|
|
113
|
+
* readers call.
|
|
114
|
+
*
|
|
115
|
+
* The seam is AFTER `minLines` and the path filters: a project can load 300
|
|
116
|
+
* files while every body sits under the threshold, and the count that notices
|
|
117
|
+
* has to be taken where the comparison receives its input, not where the files
|
|
118
|
+
* were read.
|
|
119
|
+
*
|
|
120
|
+
* No fingerprinting to count. `meetsMinLines` already returns false for a
|
|
121
|
+
* bodyless function, so `fingerprintAll(xs).length === xs.length` **always** —
|
|
122
|
+
* fingerprinting to answer "is it zero" is a full AST pass of dead work on
|
|
123
|
+
* what becomes the hot path of every consumer's `diagnose()` call.
|
|
124
|
+
*/
|
|
125
|
+
selected() {
|
|
126
|
+
return selectionOf(this, () => this.collectFilteredFunctions());
|
|
127
|
+
}
|
|
128
|
+
/** Units this detector examined — plan 0096. */
|
|
129
|
+
examinedUnits() {
|
|
130
|
+
return this.selected().length;
|
|
131
|
+
}
|
|
47
132
|
collectFilteredFunctions() {
|
|
48
133
|
const sourceFiles = this.project.getSourceFiles();
|
|
49
134
|
const folderMatchers = this._folders.map((g) => picomatch(g));
|
|
@@ -51,10 +136,16 @@ export class DuplicateBodiesBuilder extends SmellBuilder {
|
|
|
51
136
|
const testMatchers = this._ignoreTests ? TEST_PATTERNS.map((g) => picomatch(g)) : [];
|
|
52
137
|
const allFunctions = [];
|
|
53
138
|
for (const sf of sourceFiles) {
|
|
54
|
-
if (!this.passesFileFilters(sf.getFilePath(), folderMatchers, ignoreMatchers, testMatchers)) {
|
|
139
|
+
if (!this.passesFileFilters(sf.getFilePath(), { folderMatchers, ignoreMatchers, testMatchers }, relativeToRoot(sf, sf.getFilePath(), this.project.tsConfigPath))) {
|
|
55
140
|
continue;
|
|
56
141
|
}
|
|
57
|
-
for
|
|
142
|
+
// Detectors scan for a property of the code, not a user-declared subject
|
|
143
|
+
// set, so they always include object-literal functions. `functions()`
|
|
144
|
+
// keeps that opt-in because widening a selector silently changes every
|
|
145
|
+
// existing rule; a detector has no such contract to break, and a
|
|
146
|
+
// duplicated arrow under an object key — a resolver, a route handler, a
|
|
147
|
+
// reducer case — is exactly the copy-paste rot this exists to find.
|
|
148
|
+
for (const fn of collectFunctions(sf, { includeObjectLiteralFunctions: true })) {
|
|
58
149
|
if (this.meetsMinLines(fn)) {
|
|
59
150
|
allFunctions.push(fn);
|
|
60
151
|
}
|
|
@@ -62,53 +153,27 @@ export class DuplicateBodiesBuilder extends SmellBuilder {
|
|
|
62
153
|
}
|
|
63
154
|
return allFunctions;
|
|
64
155
|
}
|
|
65
|
-
/** Build fingerprints for all collected functions. */
|
|
66
|
-
fingerprintAll(functions) {
|
|
67
|
-
const result = [];
|
|
68
|
-
for (const fn of functions) {
|
|
69
|
-
const body = fn.getBody();
|
|
70
|
-
if (!body)
|
|
71
|
-
continue;
|
|
72
|
-
result.push({ fn, fingerprint: buildFingerprint(body) });
|
|
73
|
-
}
|
|
74
|
-
return result;
|
|
75
|
-
}
|
|
76
|
-
/** Compare all pairs of fingerprints, collect those above threshold. */
|
|
77
|
-
findSimilarPairs(items) {
|
|
78
|
-
const pairs = [];
|
|
79
|
-
for (let i = 0; i < items.length; i++) {
|
|
80
|
-
for (let j = i + 1; j < items.length; j++) {
|
|
81
|
-
const a = items[i];
|
|
82
|
-
const b = items[j];
|
|
83
|
-
if (!a || !b)
|
|
84
|
-
continue;
|
|
85
|
-
// Fast rejection: if node counts differ too much, similarity cannot reach threshold
|
|
86
|
-
const maxCount = Math.max(a.fingerprint.nodeCount, b.fingerprint.nodeCount);
|
|
87
|
-
const minCount = Math.min(a.fingerprint.nodeCount, b.fingerprint.nodeCount);
|
|
88
|
-
if (maxCount > 0 && minCount / maxCount < this._minSimilarity) {
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
const similarity = computeSimilarity(a.fingerprint, b.fingerprint);
|
|
92
|
-
if (similarity >= this._minSimilarity) {
|
|
93
|
-
pairs.push({ a: a.fn, b: b.fn, similarity });
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return pairs;
|
|
98
|
-
}
|
|
99
156
|
/** Build violations from similar pairs. */
|
|
157
|
+
/**
|
|
158
|
+
* Report order: by folder when `.groupByFolder()` asked for it, otherwise the
|
|
159
|
+
* order the pairs were found in.
|
|
160
|
+
*
|
|
161
|
+
* Extracted from {@link buildViolations} so that method is the violation
|
|
162
|
+
* shape and nothing else — presentation order is a separate decision.
|
|
163
|
+
*/
|
|
164
|
+
orderedPairs(pairs) {
|
|
165
|
+
if (!this._groupByFolder)
|
|
166
|
+
return pairs;
|
|
167
|
+
return [...pairs].sort((x, y) => {
|
|
168
|
+
const folderA = path.dirname(x.a.getSourceFile().getFilePath());
|
|
169
|
+
const folderB = path.dirname(y.a.getSourceFile().getFilePath());
|
|
170
|
+
return folderA.localeCompare(folderB);
|
|
171
|
+
});
|
|
172
|
+
}
|
|
100
173
|
buildViolations(pairs) {
|
|
101
174
|
const ruleDescription = this.describe();
|
|
102
175
|
const violations = [];
|
|
103
|
-
|
|
104
|
-
const sortedPairs = this._groupByFolder
|
|
105
|
-
? [...pairs].sort((x, y) => {
|
|
106
|
-
const folderA = path.dirname(x.a.getSourceFile().getFilePath());
|
|
107
|
-
const folderB = path.dirname(y.a.getSourceFile().getFilePath());
|
|
108
|
-
return folderA.localeCompare(folderB);
|
|
109
|
-
})
|
|
110
|
-
: pairs;
|
|
111
|
-
for (const pair of sortedPairs) {
|
|
176
|
+
for (const pair of this.orderedPairs(pairs)) {
|
|
112
177
|
const nameA = pair.a.getName() ?? '<anonymous>';
|
|
113
178
|
const fileA = pair.a.getSourceFile().getFilePath();
|
|
114
179
|
const lineA = pair.a.getStartLineNumber();
|
|
@@ -122,6 +187,22 @@ export class DuplicateBodiesBuilder extends SmellBuilder {
|
|
|
122
187
|
file: fileA,
|
|
123
188
|
line: lineA,
|
|
124
189
|
message: `${nameA} (${fileA}:${String(lineA)}) is ${String(pct)}% similar to ${nameB} (${fileB}:${String(lineB)})`,
|
|
190
|
+
// Which endpoint is "a" comes from the source-file walk order, which is
|
|
191
|
+
// a property of the filesystem: the same pair reports A→B on one
|
|
192
|
+
// machine and B→A on another, and the reported message alone would
|
|
193
|
+
// give them different identities. Sort the endpoints so the pair reads
|
|
194
|
+
// the same either way. Qualified by path — a bare function name is not
|
|
195
|
+
// unique across files — and without the similarity percentage, which
|
|
196
|
+
// drifts as either body is edited.
|
|
197
|
+
//
|
|
198
|
+
// Limitation: two anonymous functions in one file share an endpoint
|
|
199
|
+
// (`<file>#<anonymous>`) and so share an identity. Nothing stable
|
|
200
|
+
// distinguishes them — a line number would, and that is the coordinate
|
|
201
|
+
// dependence being removed. Measured at 0 collisions over 1006 findings
|
|
202
|
+
// on a real codebase; the collision guard in
|
|
203
|
+
// `tests/integration/baseline-portability.test.ts` is what would catch
|
|
204
|
+
// it becoming common.
|
|
205
|
+
identity: `duplicate-pair::${[`${fileA}#${nameA}`, `${fileB}#${nameB}`].sort().join('::')}`,
|
|
125
206
|
because: this._reason,
|
|
126
207
|
});
|
|
127
208
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"duplicate-bodies.js","sourceRoot":"","sources":["../../src/smells/duplicate-bodies.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"duplicate-bodies.js","sourceRoot":"","sources":["../../src/smells/duplicate-bodies.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SyntaxKind, type Node } from 'ts-morph';
|
|
2
2
|
/**
|
|
3
3
|
* Structural fingerprint of a function body.
|
|
4
4
|
* Captures the shape (node kinds, call targets) while ignoring
|
|
@@ -11,6 +11,13 @@ export interface Fingerprint {
|
|
|
11
11
|
readonly calls: readonly string[];
|
|
12
12
|
/** Total AST node count (for line-count filtering) */
|
|
13
13
|
readonly nodeCount: number;
|
|
14
|
+
/**
|
|
15
|
+
* Count of DISTINCT identifier/literal texts in the body — the vocabulary
|
|
16
|
+
* a body actually carries, as opposed to its punctuation/keyword shape.
|
|
17
|
+
* Plan 0103's floor reads this; `computeSimilarity()` does not — see that
|
|
18
|
+
* function's own docs for why.
|
|
19
|
+
*/
|
|
20
|
+
readonly distinctVocabulary: number;
|
|
14
21
|
}
|
|
15
22
|
/**
|
|
16
23
|
* Build a structural fingerprint from a function body AST node.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../../src/smells/fingerprint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../../src/smells/fingerprint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,IAAI,EAAqB,MAAM,UAAU,CAAA;AAgBnE;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,CAAA;IACrC,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,sDAAsD;IACtD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B;;;;;OAKG;IACH,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAA;CACpC;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,WAAW,CAiBxD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,GAAG,MAAM,CAMxE"}
|
|
@@ -1,4 +1,17 @@
|
|
|
1
|
-
import { Node as NodeClass } from 'ts-morph';
|
|
1
|
+
import { SyntaxKind, Node as NodeClass } from 'ts-morph';
|
|
2
|
+
// Deliberately not exhaustive over every text-bearing kind — `TemplateHead`/
|
|
3
|
+
// `TemplateMiddle`/`TemplateTail` (interpolated templates), `BigIntLiteral` and
|
|
4
|
+
// `RegularExpressionLiteral` are omitted. Every omission UNDERcounts vocabulary,
|
|
5
|
+
// which only makes the floor (plan 0103) more conservative — fewer pairs
|
|
6
|
+
// compared, never a false positive from a body that reads as emptier than it
|
|
7
|
+
// is. Widen this set if a real interpolated-template-heavy corpus needs it.
|
|
8
|
+
const TEXT_KINDS = new Set([
|
|
9
|
+
SyntaxKind.Identifier,
|
|
10
|
+
SyntaxKind.PrivateIdentifier,
|
|
11
|
+
SyntaxKind.StringLiteral,
|
|
12
|
+
SyntaxKind.NoSubstitutionTemplateLiteral,
|
|
13
|
+
SyntaxKind.NumericLiteral,
|
|
14
|
+
]);
|
|
2
15
|
/**
|
|
3
16
|
* Build a structural fingerprint from a function body AST node.
|
|
4
17
|
* Walks all descendants, records their SyntaxKind in order,
|
|
@@ -7,13 +20,18 @@ import { Node as NodeClass } from 'ts-morph';
|
|
|
7
20
|
export function buildFingerprint(body) {
|
|
8
21
|
const kinds = [];
|
|
9
22
|
const calls = [];
|
|
23
|
+
const distinct = new Set();
|
|
10
24
|
for (const node of body.getDescendants()) {
|
|
11
|
-
|
|
25
|
+
const kind = node.getKind();
|
|
26
|
+
kinds.push(kind);
|
|
12
27
|
if (NodeClass.isCallExpression(node)) {
|
|
13
28
|
calls.push(node.getExpression().getText().replace(/\?\./g, '.'));
|
|
14
29
|
}
|
|
30
|
+
if (TEXT_KINDS.has(kind)) {
|
|
31
|
+
distinct.add(node.getText());
|
|
32
|
+
}
|
|
15
33
|
}
|
|
16
|
-
return { kinds, calls, nodeCount: kinds.length };
|
|
34
|
+
return { kinds, calls, nodeCount: kinds.length, distinctVocabulary: distinct.size };
|
|
17
35
|
}
|
|
18
36
|
/**
|
|
19
37
|
* Compute similarity between two fingerprints.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../../src/smells/fingerprint.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../../src/smells/fingerprint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,IAAI,IAAI,SAAS,EAAE,MAAM,UAAU,CAAA;AAEnE,6EAA6E;AAC7E,gFAAgF;AAChF,iFAAiF;AACjF,yEAAyE;AACzE,6EAA6E;AAC7E,4EAA4E;AAC5E,MAAM,UAAU,GAAG,IAAI,GAAG,CAAa;IACrC,UAAU,CAAC,UAAU;IACrB,UAAU,CAAC,iBAAiB;IAC5B,UAAU,CAAC,aAAa;IACxB,UAAU,CAAC,6BAA6B;IACxC,UAAU,CAAC,cAAc;CAC1B,CAAC,CAAA;AAuBF;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAU;IACzC,MAAM,KAAK,GAAiB,EAAE,CAAA;IAC9B,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAA;IAElC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC;QACzC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAA;QAC3B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAChB,IAAI,SAAS,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;YACrC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAA;QAClE,CAAC;QACD,IAAI,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAA;QAC9B,CAAC;IACH,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,MAAM,EAAE,kBAAkB,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAA;AACrF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,CAAc,EAAE,CAAc;IAC9D,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,CAAA;IAC5D,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,CAAA;IAE5D,MAAM,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAA;IACvC,OAAO,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;AACvD,CAAC;AAED,oEAAoE;AACpE,SAAS,SAAS,CAAC,CAAoB,EAAE,CAAoB;IAC3D,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAA;IAClB,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAA;IAClB,IAAI,IAAI,GAAG,IAAI,KAAK,CAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAC3C,IAAI,IAAI,GAAG,IAAI,KAAK,CAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAE3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAA;YACjC,MAAM,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;YAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAA;YACjC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;QAChF,CAAC;QACD,CAAC;QAAA,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QAC5B,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACd,CAAC;IAED,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;AACrB,CAAC"}
|
|
@@ -1,21 +1,142 @@
|
|
|
1
|
+
import type { RuleDescription } from '@nielspeter/eess';
|
|
1
2
|
import { SmellBuilder } from './smell-builder.js';
|
|
2
3
|
import type { ExpressionMatcher } from '../helpers/matchers.js';
|
|
3
|
-
import type { ArchViolation } from '
|
|
4
|
+
import type { ArchViolation } from '@nielspeter/eess';
|
|
4
5
|
import type { ArchProject } from '../core/project.js';
|
|
5
6
|
export declare class InconsistentSiblingsBuilder extends SmellBuilder {
|
|
6
7
|
private _pattern?;
|
|
7
8
|
constructor(project: ArchProject);
|
|
8
9
|
/** The pattern that most siblings should follow. */
|
|
9
10
|
forPattern(matcher: ExpressionMatcher): this;
|
|
10
|
-
/**
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Sibling files in folders large enough to be compared — plan 0096, and the
|
|
13
|
+
* ONE method both readers call.
|
|
14
|
+
*
|
|
15
|
+
* The `>= 2` threshold lives HERE rather than in `detect()`'s loop, which is
|
|
16
|
+
* what makes this a shared derivation instead of two that agree by luck.
|
|
17
|
+
* Filtering before the caller's sort is safe: `groupFilesByFolder()` returns
|
|
18
|
+
* insertion order and `detect()` sorts by folder name, a total order, so
|
|
19
|
+
* removing entries cannot reorder the survivors.
|
|
20
|
+
*/
|
|
21
|
+
private selected;
|
|
22
|
+
/**
|
|
23
|
+
* Units this detector examined — plan 0096: sibling files in folders large
|
|
24
|
+
* enough to be compared.
|
|
25
|
+
*
|
|
26
|
+
* Counted in units ITERATED, never in pattern matches: a tripwire that
|
|
27
|
+
* examines every sibling and matches none has non-empty evidence, which is the
|
|
28
|
+
* 0.34.0 carve-out this must not break.
|
|
29
|
+
*/
|
|
30
|
+
examinedUnits(): number;
|
|
31
|
+
/**
|
|
32
|
+
* Pure recomputation of the corpus split — never accumulated on `this`. It is
|
|
33
|
+
* the SINGLE source the finding's message, the gate, and the diagnostic preview
|
|
34
|
+
* all read, so the preview and the finding cannot diverge, and calling it twice
|
|
35
|
+
* cannot double-count (each call recomputes). Mirrors `examinedUnits()`: one
|
|
36
|
+
* derivation, not an instance field.
|
|
37
|
+
*
|
|
38
|
+
* `canFireSoon` is true when any folder is at or within ONE edit of a majority —
|
|
39
|
+
* such a folder can fire, so it is not inert even though it does not fire today.
|
|
40
|
+
*
|
|
41
|
+
* The GUARD lives here, not at the emit site. A preview read through this
|
|
42
|
+
* accessor can then never report on a rule that can fire: a healthy control
|
|
43
|
+
* (majority present, `editsToMajority <= 1`) gets `canFireSoon = true`, and the
|
|
44
|
+
* hook below returns the empty string for it. The check-time emit and the
|
|
45
|
+
* diagnostic preview share this one predicate by construction.
|
|
46
|
+
*/
|
|
47
|
+
private inertAssessment;
|
|
14
48
|
/** Build violations for non-matching files in a folder where the majority matches. */
|
|
49
|
+
/**
|
|
50
|
+
* The two description strings travel together as one `describe` — adjacent
|
|
51
|
+
* positional strings are the transposition the parameter cap guards against,
|
|
52
|
+
* and these two read alike.
|
|
53
|
+
*/
|
|
15
54
|
private buildFolderViolations;
|
|
55
|
+
/**
|
|
56
|
+
* Whether this rule states an assertion at all — the assertion gate's question.
|
|
57
|
+
*
|
|
58
|
+
* True once a condition has been added.
|
|
59
|
+
*
|
|
60
|
+
* Overrides the `TerminalBuilder` default (`true`), whose JSDoc carries the
|
|
61
|
+
* contract and the reason this is public rather than protected.
|
|
62
|
+
*/
|
|
63
|
+
assertsSomething(): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Named by id or by what the detector checks — the inherited version says
|
|
66
|
+
* 'unnamed'. Uses `describe()` rather than a call-site locator for the same
|
|
67
|
+
* reason as `SliceRuleBuilder`: `explain --format agent` reads this field.
|
|
68
|
+
*/
|
|
69
|
+
/**
|
|
70
|
+
* This detector counts sibling FILES, not function bodies — plan 0099.
|
|
71
|
+
*
|
|
72
|
+
* It inherited `SmellBuilder`'s noun while `examinedUnits()` sums
|
|
73
|
+
* `files.length`, so the message read "examined 0 function bodies" for a
|
|
74
|
+
* file-counting detector: the category error this plan exists to remove, in the
|
|
75
|
+
* family sitting directly under the override.
|
|
76
|
+
*/
|
|
77
|
+
protected examinedUnitNoun(): string;
|
|
78
|
+
/**
|
|
79
|
+
* A structural description of this rule without executing it — what `explain`
|
|
80
|
+
* prints and what the ADR/citation gates read.
|
|
81
|
+
*/
|
|
82
|
+
describeRule(): RuleDescription;
|
|
83
|
+
/**
|
|
84
|
+
* The remedy for this builder's assertion-less state, as one string.
|
|
85
|
+
*
|
|
86
|
+
* One channel, so `diagnose()`'s advice and the finding's own message cannot
|
|
87
|
+
* disagree. Overrides `TerminalBuilder`'s generic text with wording specific to
|
|
88
|
+
* what this builder is missing.
|
|
89
|
+
*/
|
|
90
|
+
assertionAdvice(): string;
|
|
91
|
+
/** The file-selection facts `sibling-files.ts` needs, stated as a value. */
|
|
92
|
+
private scope;
|
|
16
93
|
protected detect(): ArchViolation[];
|
|
94
|
+
/**
|
|
95
|
+
* The `DiagnosableRule` hook — public, no-arg, exactly the shape the
|
|
96
|
+
* interface requires. Recomputes `inertAssessment()` fresh, so `diagnose()`
|
|
97
|
+
* on a builder that never ran `check()` still gets truthful numbers.
|
|
98
|
+
*/
|
|
99
|
+
inertAdvice(): string;
|
|
100
|
+
/**
|
|
101
|
+
* THE single derivation for both surfaces, and the guard. Returns the empty
|
|
102
|
+
* string unless the rule is genuinely inert (`matching > 0 && !canFireSoon &&
|
|
103
|
+
* !declaresEmpty()`), so a healthy control (majority present, within one edit
|
|
104
|
+
* of one, or declared empty) gets `''` and diagnose() reports nothing for it.
|
|
105
|
+
* Both `inertAdvice()` above and `detect()`'s emit call this with an
|
|
106
|
+
* `Assessment` — the SAME guard and the SAME message either way, so the
|
|
107
|
+
* preview and the finding cannot diverge.
|
|
108
|
+
*
|
|
109
|
+
* `!this.declaresEmpty()` lives HERE, not only in `inertEmitEnabled()` (review:
|
|
110
|
+
* architect) — a declared-empty rule reports its expiry, not the inert finding,
|
|
111
|
+
* on BOTH surfaces, so `diagnose()`'s preview and `check()`'s eventual failure
|
|
112
|
+
* name the same cause for the same rule state. Before this fix the two clauses
|
|
113
|
+
* were split across two functions and only the emit path read the declaration,
|
|
114
|
+
* so a rule carrying `.expectEmpty()` could preview one cause via `diagnose()`
|
|
115
|
+
* and fail with a different one via `check()` — the exact drift this shared-
|
|
116
|
+
* derivation design exists to make impossible "by construction".
|
|
117
|
+
*/
|
|
118
|
+
private inertAdviceFor;
|
|
119
|
+
private inertViolation;
|
|
120
|
+
/**
|
|
121
|
+
* The pure version gate — nothing else. The `_expectEmpty` precedence
|
|
122
|
+
* (`!this.declaresEmpty()`) moved into `inertAdviceFor()` above, so it applies
|
|
123
|
+
* identically to `diagnose()`'s preview and to this emit path; this function's
|
|
124
|
+
* only job is "has the N+1 release happened yet."
|
|
125
|
+
*
|
|
126
|
+
* `INERT_FINDING_EMIT` is deliberately a bare, non-exported module `const` —
|
|
127
|
+
* not an env var, constructor option, or per-project override. The
|
|
128
|
+
* `bypassFilters: true` / unsuppressable design above depends on there being
|
|
129
|
+
* no configuration surface a future contributor could "helpfully" expose,
|
|
130
|
+
* which would undermine it silently.
|
|
131
|
+
*
|
|
132
|
+
* `protected`, not `private` — a test-only subclass overrides this to exercise
|
|
133
|
+
* the emit path (`inertViolation()`, `inertElement()`, the `detect()` branch
|
|
134
|
+
* that pushes them) before the N+1 flip ships, so that path is not shipped
|
|
135
|
+
* with zero test coverage merely because the real gate is off today (review:
|
|
136
|
+
* testing). See `tests/smells/inconsistent-siblings.test.ts`'s
|
|
137
|
+
* `EmittingSiblings` subclass.
|
|
138
|
+
*/
|
|
139
|
+
protected inertEmitEnabled(): boolean;
|
|
17
140
|
protected describe(): string;
|
|
18
|
-
/** Group source files by parent folder, applying all filters. */
|
|
19
|
-
private groupFilesByFolder;
|
|
20
141
|
}
|
|
21
142
|
//# sourceMappingURL=inconsistent-siblings.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inconsistent-siblings.d.ts","sourceRoot":"","sources":["../../src/smells/inconsistent-siblings.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"inconsistent-siblings.d.ts","sourceRoot":"","sources":["../../src/smells/inconsistent-siblings.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAyBrD,qBAAa,2BAA4B,SAAQ,YAAY;IAC3D,OAAO,CAAC,QAAQ,CAAC,CAAmB;gBAExB,OAAO,EAAE,WAAW;IAIhC,oDAAoD;IACpD,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI;IAM5C;;;;;;;;;OASG;IACH,OAAO,CAAC,QAAQ;IAMhB;;;;;;;OAOG;IACH,aAAa,IAAI,MAAM;IAIvB;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,eAAe;IAuCvB,sFAAsF;IACtF;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IA8B7B;;;;;;;OAOG;IACM,gBAAgB,IAAI,OAAO;IAIpC;;;;OAIG;IACH;;;;;;;OAOG;cACgB,gBAAgB,IAAI,MAAM;IAI7C;;;OAGG;IACM,YAAY,IAAI,eAAe;IAOxC;;;;;;OAMG;IACM,eAAe,IAAI,MAAM;IAOlC,4EAA4E;IAC5E,OAAO,CAAC,KAAK;IAWb,SAAS,CAAC,MAAM,IAAI,aAAa,EAAE;IA8DnC;;;;OAIG;IACH,WAAW,IAAI,MAAM;IAMrB;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,cAAc;IA2BtB;;;;;;;;;;;;;;;;;;OAkBG;IACH,SAAS,CAAC,gBAAgB,IAAI,OAAO;IAIrC,SAAS,CAAC,QAAQ,IAAI,MAAM;CAI7B"}
|