@opensip-tools/fitness 1.0.4
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/.turbo/turbo-build.log +4 -0
- package/.turbo/turbo-typecheck.log +4 -0
- package/LICENSE +21 -0
- package/dist/__tests__/gate.test.d.ts +13 -0
- package/dist/__tests__/gate.test.d.ts.map +1 -0
- package/dist/__tests__/gate.test.js +422 -0
- package/dist/__tests__/gate.test.js.map +1 -0
- package/dist/__tests__/sarif.test.d.ts +2 -0
- package/dist/__tests__/sarif.test.d.ts.map +1 -0
- package/dist/__tests__/sarif.test.js +169 -0
- package/dist/__tests__/sarif.test.js.map +1 -0
- package/dist/cli/dashboard.d.ts +6 -0
- package/dist/cli/dashboard.d.ts.map +1 -0
- package/dist/cli/dashboard.js +77 -0
- package/dist/cli/dashboard.js.map +1 -0
- package/dist/cli/fit.d.ts +37 -0
- package/dist/cli/fit.d.ts.map +1 -0
- package/dist/cli/fit.js +539 -0
- package/dist/cli/fit.js.map +1 -0
- package/dist/cli/list-checks.d.ts +6 -0
- package/dist/cli/list-checks.d.ts.map +1 -0
- package/dist/cli/list-checks.js +23 -0
- package/dist/cli/list-checks.js.map +1 -0
- package/dist/cli/list-recipes.d.ts +6 -0
- package/dist/cli/list-recipes.d.ts.map +1 -0
- package/dist/cli/list-recipes.js +31 -0
- package/dist/cli/list-recipes.js.map +1 -0
- package/dist/framework/__tests__/ast-utilities.test.d.ts +2 -0
- package/dist/framework/__tests__/ast-utilities.test.d.ts.map +1 -0
- package/dist/framework/__tests__/ast-utilities.test.js +153 -0
- package/dist/framework/__tests__/ast-utilities.test.js.map +1 -0
- package/dist/framework/__tests__/check-config.test.d.ts +2 -0
- package/dist/framework/__tests__/check-config.test.d.ts.map +1 -0
- package/dist/framework/__tests__/check-config.test.js +56 -0
- package/dist/framework/__tests__/check-config.test.js.map +1 -0
- package/dist/framework/__tests__/command-executor.test.d.ts +2 -0
- package/dist/framework/__tests__/command-executor.test.d.ts.map +1 -0
- package/dist/framework/__tests__/command-executor.test.js +71 -0
- package/dist/framework/__tests__/command-executor.test.js.map +1 -0
- package/dist/framework/__tests__/content-filter-dispatch.test.d.ts +2 -0
- package/dist/framework/__tests__/content-filter-dispatch.test.d.ts.map +1 -0
- package/dist/framework/__tests__/content-filter-dispatch.test.js +104 -0
- package/dist/framework/__tests__/content-filter-dispatch.test.js.map +1 -0
- package/dist/framework/__tests__/content-filter.test.d.ts +2 -0
- package/dist/framework/__tests__/content-filter.test.d.ts.map +1 -0
- package/dist/framework/__tests__/content-filter.test.js +126 -0
- package/dist/framework/__tests__/content-filter.test.js.map +1 -0
- package/dist/framework/__tests__/define-check.test.d.ts +2 -0
- package/dist/framework/__tests__/define-check.test.d.ts.map +1 -0
- package/dist/framework/__tests__/define-check.test.js +155 -0
- package/dist/framework/__tests__/define-check.test.js.map +1 -0
- package/dist/framework/__tests__/directive-inventory.test.d.ts +2 -0
- package/dist/framework/__tests__/directive-inventory.test.d.ts.map +1 -0
- package/dist/framework/__tests__/directive-inventory.test.js +44 -0
- package/dist/framework/__tests__/directive-inventory.test.js.map +1 -0
- package/dist/framework/__tests__/execution-context.test.d.ts +2 -0
- package/dist/framework/__tests__/execution-context.test.d.ts.map +1 -0
- package/dist/framework/__tests__/execution-context.test.js +62 -0
- package/dist/framework/__tests__/execution-context.test.js.map +1 -0
- package/dist/framework/__tests__/file-accessor.test.d.ts +2 -0
- package/dist/framework/__tests__/file-accessor.test.d.ts.map +1 -0
- package/dist/framework/__tests__/file-accessor.test.js +106 -0
- package/dist/framework/__tests__/file-accessor.test.js.map +1 -0
- package/dist/framework/__tests__/file-cache.test.d.ts +2 -0
- package/dist/framework/__tests__/file-cache.test.d.ts.map +1 -0
- package/dist/framework/__tests__/file-cache.test.js +122 -0
- package/dist/framework/__tests__/file-cache.test.js.map +1 -0
- package/dist/framework/__tests__/import-graph.test.d.ts +15 -0
- package/dist/framework/__tests__/import-graph.test.d.ts.map +1 -0
- package/dist/framework/__tests__/import-graph.test.js +164 -0
- package/dist/framework/__tests__/import-graph.test.js.map +1 -0
- package/dist/framework/__tests__/path-matcher.test.d.ts +2 -0
- package/dist/framework/__tests__/path-matcher.test.d.ts.map +1 -0
- package/dist/framework/__tests__/path-matcher.test.js +113 -0
- package/dist/framework/__tests__/path-matcher.test.js.map +1 -0
- package/dist/framework/__tests__/register-helpers.test.d.ts +2 -0
- package/dist/framework/__tests__/register-helpers.test.d.ts.map +1 -0
- package/dist/framework/__tests__/register-helpers.test.js +42 -0
- package/dist/framework/__tests__/register-helpers.test.js.map +1 -0
- package/dist/framework/__tests__/registry.test.d.ts +2 -0
- package/dist/framework/__tests__/registry.test.d.ts.map +1 -0
- package/dist/framework/__tests__/registry.test.js +208 -0
- package/dist/framework/__tests__/registry.test.js.map +1 -0
- package/dist/framework/__tests__/result-builder.test.d.ts +2 -0
- package/dist/framework/__tests__/result-builder.test.d.ts.map +1 -0
- package/dist/framework/__tests__/result-builder.test.js +153 -0
- package/dist/framework/__tests__/result-builder.test.js.map +1 -0
- package/dist/framework/__tests__/scope-resolver.test.d.ts +2 -0
- package/dist/framework/__tests__/scope-resolver.test.d.ts.map +1 -0
- package/dist/framework/__tests__/scope-resolver.test.js +140 -0
- package/dist/framework/__tests__/scope-resolver.test.js.map +1 -0
- package/dist/framework/__tests__/severity-mapping.test.d.ts +2 -0
- package/dist/framework/__tests__/severity-mapping.test.d.ts.map +1 -0
- package/dist/framework/__tests__/severity-mapping.test.js +42 -0
- package/dist/framework/__tests__/severity-mapping.test.js.map +1 -0
- package/dist/framework/__tests__/strip-literals.test.d.ts +2 -0
- package/dist/framework/__tests__/strip-literals.test.d.ts.map +1 -0
- package/dist/framework/__tests__/strip-literals.test.js +87 -0
- package/dist/framework/__tests__/strip-literals.test.js.map +1 -0
- package/dist/framework/abortable-exec.d.ts +34 -0
- package/dist/framework/abortable-exec.d.ts.map +1 -0
- package/dist/framework/abortable-exec.js +136 -0
- package/dist/framework/abortable-exec.js.map +1 -0
- package/dist/framework/ast-utilities.d.ts +41 -0
- package/dist/framework/ast-utilities.d.ts.map +1 -0
- package/dist/framework/ast-utilities.js +106 -0
- package/dist/framework/ast-utilities.js.map +1 -0
- package/dist/framework/check-config.d.ts +171 -0
- package/dist/framework/check-config.d.ts.map +1 -0
- package/dist/framework/check-config.js +114 -0
- package/dist/framework/check-config.js.map +1 -0
- package/dist/framework/check-types.d.ts +57 -0
- package/dist/framework/check-types.d.ts.map +1 -0
- package/dist/framework/check-types.js +35 -0
- package/dist/framework/check-types.js.map +1 -0
- package/dist/framework/command-executor.d.ts +25 -0
- package/dist/framework/command-executor.d.ts.map +1 -0
- package/dist/framework/command-executor.js +63 -0
- package/dist/framework/command-executor.js.map +1 -0
- package/dist/framework/constants.d.ts +9 -0
- package/dist/framework/constants.d.ts.map +1 -0
- package/dist/framework/constants.js +16 -0
- package/dist/framework/constants.js.map +1 -0
- package/dist/framework/content-filter.d.ts +33 -0
- package/dist/framework/content-filter.d.ts.map +1 -0
- package/dist/framework/content-filter.js +236 -0
- package/dist/framework/content-filter.js.map +1 -0
- package/dist/framework/define-check.d.ts +38 -0
- package/dist/framework/define-check.d.ts.map +1 -0
- package/dist/framework/define-check.js +252 -0
- package/dist/framework/define-check.js.map +1 -0
- package/dist/framework/directive-inventory.d.ts +34 -0
- package/dist/framework/directive-inventory.d.ts.map +1 -0
- package/dist/framework/directive-inventory.js +77 -0
- package/dist/framework/directive-inventory.js.map +1 -0
- package/dist/framework/directive-parsing.d.ts +20 -0
- package/dist/framework/directive-parsing.d.ts.map +1 -0
- package/dist/framework/directive-parsing.js +121 -0
- package/dist/framework/directive-parsing.js.map +1 -0
- package/dist/framework/execution-context.d.ts +95 -0
- package/dist/framework/execution-context.d.ts.map +1 -0
- package/dist/framework/execution-context.js +122 -0
- package/dist/framework/execution-context.js.map +1 -0
- package/dist/framework/file-accessor.d.ts +20 -0
- package/dist/framework/file-accessor.d.ts.map +1 -0
- package/dist/framework/file-accessor.js +122 -0
- package/dist/framework/file-accessor.js.map +1 -0
- package/dist/framework/file-cache.d.ts +70 -0
- package/dist/framework/file-cache.d.ts.map +1 -0
- package/dist/framework/file-cache.js +178 -0
- package/dist/framework/file-cache.js.map +1 -0
- package/dist/framework/file-type-filter.d.ts +11 -0
- package/dist/framework/file-type-filter.d.ts.map +1 -0
- package/dist/framework/file-type-filter.js +21 -0
- package/dist/framework/file-type-filter.js.map +1 -0
- package/dist/framework/ignore-processing.d.ts +22 -0
- package/dist/framework/ignore-processing.d.ts.map +1 -0
- package/dist/framework/ignore-processing.js +241 -0
- package/dist/framework/ignore-processing.js.map +1 -0
- package/dist/framework/import-graph.d.ts +51 -0
- package/dist/framework/import-graph.d.ts.map +1 -0
- package/dist/framework/import-graph.js +216 -0
- package/dist/framework/import-graph.js.map +1 -0
- package/dist/framework/memory-profiler.d.ts +53 -0
- package/dist/framework/memory-profiler.d.ts.map +1 -0
- package/dist/framework/memory-profiler.js +92 -0
- package/dist/framework/memory-profiler.js.map +1 -0
- package/dist/framework/parse-cache.d.ts +23 -0
- package/dist/framework/parse-cache.d.ts.map +1 -0
- package/dist/framework/parse-cache.js +37 -0
- package/dist/framework/parse-cache.js.map +1 -0
- package/dist/framework/path-matcher.d.ts +86 -0
- package/dist/framework/path-matcher.d.ts.map +1 -0
- package/dist/framework/path-matcher.js +138 -0
- package/dist/framework/path-matcher.js.map +1 -0
- package/dist/framework/register-helpers.d.ts +10 -0
- package/dist/framework/register-helpers.d.ts.map +1 -0
- package/dist/framework/register-helpers.js +17 -0
- package/dist/framework/register-helpers.js.map +1 -0
- package/dist/framework/registry.d.ts +41 -0
- package/dist/framework/registry.d.ts.map +1 -0
- package/dist/framework/registry.js +103 -0
- package/dist/framework/registry.js.map +1 -0
- package/dist/framework/result-builder.d.ts +74 -0
- package/dist/framework/result-builder.d.ts.map +1 -0
- package/dist/framework/result-builder.js +154 -0
- package/dist/framework/result-builder.js.map +1 -0
- package/dist/framework/scope-resolver.d.ts +23 -0
- package/dist/framework/scope-resolver.d.ts.map +1 -0
- package/dist/framework/scope-resolver.js +201 -0
- package/dist/framework/scope-resolver.js.map +1 -0
- package/dist/framework/severity-mapping.d.ts +13 -0
- package/dist/framework/severity-mapping.d.ts.map +1 -0
- package/dist/framework/severity-mapping.js +51 -0
- package/dist/framework/severity-mapping.js.map +1 -0
- package/dist/framework/strip-literals.d.ts +48 -0
- package/dist/framework/strip-literals.d.ts.map +1 -0
- package/dist/framework/strip-literals.js +188 -0
- package/dist/framework/strip-literals.js.map +1 -0
- package/dist/gate.d.ts +74 -0
- package/dist/gate.d.ts.map +1 -0
- package/dist/gate.js +257 -0
- package/dist/gate.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/plugins/__tests__/check-package-discovery.test.d.ts +2 -0
- package/dist/plugins/__tests__/check-package-discovery.test.d.ts.map +1 -0
- package/dist/plugins/__tests__/check-package-discovery.test.js +170 -0
- package/dist/plugins/__tests__/check-package-discovery.test.js.map +1 -0
- package/dist/plugins/__tests__/lang-domain.test.d.ts +2 -0
- package/dist/plugins/__tests__/lang-domain.test.d.ts.map +1 -0
- package/dist/plugins/__tests__/lang-domain.test.js +171 -0
- package/dist/plugins/__tests__/lang-domain.test.js.map +1 -0
- package/dist/plugins/__tests__/loader.test.d.ts +2 -0
- package/dist/plugins/__tests__/loader.test.d.ts.map +1 -0
- package/dist/plugins/__tests__/loader.test.js +194 -0
- package/dist/plugins/__tests__/loader.test.js.map +1 -0
- package/dist/plugins/check-package-discovery.d.ts +73 -0
- package/dist/plugins/check-package-discovery.d.ts.map +1 -0
- package/dist/plugins/check-package-discovery.js +212 -0
- package/dist/plugins/check-package-discovery.js.map +1 -0
- package/dist/plugins/loader.d.ts +31 -0
- package/dist/plugins/loader.d.ts.map +1 -0
- package/dist/plugins/loader.js +290 -0
- package/dist/plugins/loader.js.map +1 -0
- package/dist/plugins/types.d.ts +23 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +9 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/recipes/__tests__/built-in-recipes.test.d.ts +2 -0
- package/dist/recipes/__tests__/built-in-recipes.test.d.ts.map +1 -0
- package/dist/recipes/__tests__/built-in-recipes.test.js +93 -0
- package/dist/recipes/__tests__/built-in-recipes.test.js.map +1 -0
- package/dist/recipes/__tests__/check-config.test.d.ts +5 -0
- package/dist/recipes/__tests__/check-config.test.d.ts.map +1 -0
- package/dist/recipes/__tests__/check-config.test.js +37 -0
- package/dist/recipes/__tests__/check-config.test.js.map +1 -0
- package/dist/recipes/__tests__/check-resolution.test.d.ts +2 -0
- package/dist/recipes/__tests__/check-resolution.test.d.ts.map +1 -0
- package/dist/recipes/__tests__/check-resolution.test.js +135 -0
- package/dist/recipes/__tests__/check-resolution.test.js.map +1 -0
- package/dist/recipes/__tests__/registry.test.d.ts +2 -0
- package/dist/recipes/__tests__/registry.test.d.ts.map +1 -0
- package/dist/recipes/__tests__/registry.test.js +97 -0
- package/dist/recipes/__tests__/registry.test.js.map +1 -0
- package/dist/recipes/__tests__/retry.test.d.ts +2 -0
- package/dist/recipes/__tests__/retry.test.d.ts.map +1 -0
- package/dist/recipes/__tests__/retry.test.js +75 -0
- package/dist/recipes/__tests__/retry.test.js.map +1 -0
- package/dist/recipes/__tests__/service.test.d.ts +11 -0
- package/dist/recipes/__tests__/service.test.d.ts.map +1 -0
- package/dist/recipes/__tests__/service.test.js +482 -0
- package/dist/recipes/__tests__/service.test.js.map +1 -0
- package/dist/recipes/built-in-recipes.d.ts +14 -0
- package/dist/recipes/built-in-recipes.d.ts.map +1 -0
- package/dist/recipes/built-in-recipes.js +247 -0
- package/dist/recipes/built-in-recipes.js.map +1 -0
- package/dist/recipes/check-config.d.ts +40 -0
- package/dist/recipes/check-config.d.ts.map +1 -0
- package/dist/recipes/check-config.js +61 -0
- package/dist/recipes/check-config.js.map +1 -0
- package/dist/recipes/check-resolution.d.ts +21 -0
- package/dist/recipes/check-resolution.d.ts.map +1 -0
- package/dist/recipes/check-resolution.js +121 -0
- package/dist/recipes/check-resolution.js.map +1 -0
- package/dist/recipes/check-result-processor.d.ts +51 -0
- package/dist/recipes/check-result-processor.d.ts.map +1 -0
- package/dist/recipes/check-result-processor.js +158 -0
- package/dist/recipes/check-result-processor.js.map +1 -0
- package/dist/recipes/parallel-execution.d.ts +33 -0
- package/dist/recipes/parallel-execution.d.ts.map +1 -0
- package/dist/recipes/parallel-execution.js +142 -0
- package/dist/recipes/parallel-execution.js.map +1 -0
- package/dist/recipes/registry.d.ts +81 -0
- package/dist/recipes/registry.d.ts.map +1 -0
- package/dist/recipes/registry.js +131 -0
- package/dist/recipes/registry.js.map +1 -0
- package/dist/recipes/retry.d.ts +25 -0
- package/dist/recipes/retry.d.ts.map +1 -0
- package/dist/recipes/retry.js +44 -0
- package/dist/recipes/retry.js.map +1 -0
- package/dist/recipes/sequential-execution.d.ts +10 -0
- package/dist/recipes/sequential-execution.d.ts.map +1 -0
- package/dist/recipes/sequential-execution.js +122 -0
- package/dist/recipes/sequential-execution.js.map +1 -0
- package/dist/recipes/service-types.d.ts +84 -0
- package/dist/recipes/service-types.d.ts.map +1 -0
- package/dist/recipes/service-types.js +8 -0
- package/dist/recipes/service-types.js.map +1 -0
- package/dist/recipes/service.d.ts +71 -0
- package/dist/recipes/service.d.ts.map +1 -0
- package/dist/recipes/service.js +331 -0
- package/dist/recipes/service.js.map +1 -0
- package/dist/recipes/types.d.ts +154 -0
- package/dist/recipes/types.d.ts.map +1 -0
- package/dist/recipes/types.js +54 -0
- package/dist/recipes/types.js.map +1 -0
- package/dist/sarif.d.ts +34 -0
- package/dist/sarif.d.ts.map +1 -0
- package/dist/sarif.js +192 -0
- package/dist/sarif.js.map +1 -0
- package/dist/signalers/__tests__/loader.test.d.ts +2 -0
- package/dist/signalers/__tests__/loader.test.d.ts.map +1 -0
- package/dist/signalers/__tests__/loader.test.js +74 -0
- package/dist/signalers/__tests__/loader.test.js.map +1 -0
- package/dist/signalers/index.d.ts +8 -0
- package/dist/signalers/index.d.ts.map +1 -0
- package/dist/signalers/index.js +9 -0
- package/dist/signalers/index.js.map +1 -0
- package/dist/signalers/loader.d.ts +24 -0
- package/dist/signalers/loader.d.ts.map +1 -0
- package/dist/signalers/loader.js +108 -0
- package/dist/signalers/loader.js.map +1 -0
- package/dist/signalers/schema.d.ts +288 -0
- package/dist/signalers/schema.d.ts.map +1 -0
- package/dist/signalers/schema.js +99 -0
- package/dist/signalers/schema.js.map +1 -0
- package/dist/signalers/types.d.ts +13 -0
- package/dist/signalers/types.d.ts.map +1 -0
- package/dist/signalers/types.js +5 -0
- package/dist/signalers/types.js.map +1 -0
- package/dist/targets/__tests__/loader.test.d.ts +2 -0
- package/dist/targets/__tests__/loader.test.d.ts.map +1 -0
- package/dist/targets/__tests__/loader.test.js +127 -0
- package/dist/targets/__tests__/loader.test.js.map +1 -0
- package/dist/targets/__tests__/resolver.test.d.ts +2 -0
- package/dist/targets/__tests__/resolver.test.d.ts.map +1 -0
- package/dist/targets/__tests__/resolver.test.js +54 -0
- package/dist/targets/__tests__/resolver.test.js.map +1 -0
- package/dist/targets/__tests__/target-registry.test.d.ts +2 -0
- package/dist/targets/__tests__/target-registry.test.d.ts.map +1 -0
- package/dist/targets/__tests__/target-registry.test.js +89 -0
- package/dist/targets/__tests__/target-registry.test.js.map +1 -0
- package/dist/targets/index.d.ts +10 -0
- package/dist/targets/index.d.ts.map +1 -0
- package/dist/targets/index.js +12 -0
- package/dist/targets/index.js.map +1 -0
- package/dist/targets/loader.d.ts +19 -0
- package/dist/targets/loader.d.ts.map +1 -0
- package/dist/targets/loader.js +159 -0
- package/dist/targets/loader.js.map +1 -0
- package/dist/targets/resolver.d.ts +19 -0
- package/dist/targets/resolver.d.ts.map +1 -0
- package/dist/targets/resolver.js +37 -0
- package/dist/targets/resolver.js.map +1 -0
- package/dist/targets/target-registry.d.ts +61 -0
- package/dist/targets/target-registry.d.ts.map +1 -0
- package/dist/targets/target-registry.js +93 -0
- package/dist/targets/target-registry.js.map +1 -0
- package/dist/targets/types.d.ts +85 -0
- package/dist/targets/types.d.ts.map +1 -0
- package/dist/targets/types.js +5 -0
- package/dist/targets/types.js.map +1 -0
- package/dist/tool.d.ts +17 -0
- package/dist/tool.d.ts.map +1 -0
- package/dist/tool.js +282 -0
- package/dist/tool.js.map +1 -0
- package/dist/types/findings.d.ts +117 -0
- package/dist/types/findings.d.ts.map +1 -0
- package/dist/types/findings.js +93 -0
- package/dist/types/findings.js.map +1 -0
- package/dist/types/severity.d.ts +15 -0
- package/dist/types/severity.d.ts.map +1 -0
- package/dist/types/severity.js +36 -0
- package/dist/types/severity.js.map +1 -0
- package/package.json +45 -0
- package/src/__tests__/gate.test.ts +537 -0
- package/src/__tests__/sarif.test.ts +201 -0
- package/src/cli/dashboard.ts +93 -0
- package/src/cli/fit.ts +612 -0
- package/src/cli/list-checks.ts +32 -0
- package/src/cli/list-recipes.ts +38 -0
- package/src/framework/__tests__/ast-utilities.test.ts +157 -0
- package/src/framework/__tests__/check-config.test.ts +65 -0
- package/src/framework/__tests__/command-executor.test.ts +79 -0
- package/src/framework/__tests__/content-filter-dispatch.test.ts +132 -0
- package/src/framework/__tests__/content-filter.test.ts +136 -0
- package/src/framework/__tests__/define-check.test.ts +180 -0
- package/src/framework/__tests__/directive-inventory.test.ts +53 -0
- package/src/framework/__tests__/execution-context.test.ts +80 -0
- package/src/framework/__tests__/file-accessor.test.ts +121 -0
- package/src/framework/__tests__/file-cache.test.ts +142 -0
- package/src/framework/__tests__/import-graph.test.ts +282 -0
- package/src/framework/__tests__/path-matcher.test.ts +130 -0
- package/src/framework/__tests__/register-helpers.test.ts +51 -0
- package/src/framework/__tests__/registry.test.ts +243 -0
- package/src/framework/__tests__/result-builder.test.ts +178 -0
- package/src/framework/__tests__/scope-resolver.test.ts +208 -0
- package/src/framework/__tests__/severity-mapping.test.ts +50 -0
- package/src/framework/__tests__/strip-literals.test.ts +109 -0
- package/src/framework/abortable-exec.ts +177 -0
- package/src/framework/ast-utilities.ts +112 -0
- package/src/framework/check-config.ts +339 -0
- package/src/framework/check-types.ts +77 -0
- package/src/framework/command-executor.ts +100 -0
- package/src/framework/constants.ts +16 -0
- package/src/framework/content-filter.ts +288 -0
- package/src/framework/define-check.ts +336 -0
- package/src/framework/directive-inventory.ts +110 -0
- package/src/framework/directive-parsing.ts +152 -0
- package/src/framework/execution-context.ts +247 -0
- package/src/framework/file-accessor.ts +171 -0
- package/src/framework/file-cache.ts +220 -0
- package/src/framework/file-type-filter.ts +25 -0
- package/src/framework/ignore-processing.ts +350 -0
- package/src/framework/import-graph.ts +280 -0
- package/src/framework/memory-profiler.ts +145 -0
- package/src/framework/parse-cache.ts +38 -0
- package/src/framework/path-matcher.ts +191 -0
- package/src/framework/register-helpers.ts +20 -0
- package/src/framework/registry.ts +125 -0
- package/src/framework/result-builder.ts +225 -0
- package/src/framework/scope-resolver.ts +262 -0
- package/src/framework/severity-mapping.ts +56 -0
- package/src/framework/strip-literals.ts +200 -0
- package/src/gate.ts +337 -0
- package/src/index.ts +110 -0
- package/src/plugins/__tests__/check-package-discovery.test.ts +204 -0
- package/src/plugins/__tests__/lang-domain.test.ts +198 -0
- package/src/plugins/__tests__/loader.test.ts +226 -0
- package/src/plugins/check-package-discovery.ts +242 -0
- package/src/plugins/loader.ts +327 -0
- package/src/plugins/types.ts +25 -0
- package/src/recipes/__tests__/built-in-recipes.test.ts +107 -0
- package/src/recipes/__tests__/check-config.test.ts +51 -0
- package/src/recipes/__tests__/check-resolution.test.ts +185 -0
- package/src/recipes/__tests__/registry.test.ts +115 -0
- package/src/recipes/__tests__/retry.test.ts +83 -0
- package/src/recipes/__tests__/service.test.ts +572 -0
- package/src/recipes/built-in-recipes.ts +273 -0
- package/src/recipes/check-config.ts +64 -0
- package/src/recipes/check-resolution.ts +169 -0
- package/src/recipes/check-result-processor.ts +258 -0
- package/src/recipes/parallel-execution.ts +220 -0
- package/src/recipes/registry.ts +192 -0
- package/src/recipes/retry.ts +69 -0
- package/src/recipes/sequential-execution.ts +139 -0
- package/src/recipes/service-types.ts +105 -0
- package/src/recipes/service.ts +400 -0
- package/src/recipes/types.ts +247 -0
- package/src/sarif.ts +232 -0
- package/src/signalers/__tests__/loader.test.ts +99 -0
- package/src/signalers/index.ts +9 -0
- package/src/signalers/loader.ts +141 -0
- package/src/signalers/schema.ts +117 -0
- package/src/signalers/types.ts +15 -0
- package/src/targets/__tests__/loader.test.ts +170 -0
- package/src/targets/__tests__/resolver.test.ts +74 -0
- package/src/targets/__tests__/target-registry.test.ts +103 -0
- package/src/targets/index.ts +13 -0
- package/src/targets/loader.ts +214 -0
- package/src/targets/resolver.ts +44 -0
- package/src/targets/target-registry.ts +111 -0
- package/src/targets/types.ts +89 -0
- package/src/tool.ts +302 -0
- package/src/types/findings.ts +239 -0
- package/src/types/severity.ts +39 -0
- package/tsconfig.json +8 -0
- package/vitest.config.ts +33 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
// @fitness-ignore-file public-api-jsdoc -- internal framework module; public API documented at package level
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview In-memory file cache for fitness checks
|
|
4
|
+
*
|
|
5
|
+
* Simple file content cache with optional prewarming.
|
|
6
|
+
* Used by all checks during a run for efficient file access.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import * as fs from 'node:fs/promises'
|
|
10
|
+
import * as path from 'node:path'
|
|
11
|
+
|
|
12
|
+
import { ValidationError } from '@opensip-tools/core'
|
|
13
|
+
import { glob } from 'glob'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Prewarm statistics.
|
|
17
|
+
*/
|
|
18
|
+
interface PrewarmStats {
|
|
19
|
+
/** Number of files loaded */
|
|
20
|
+
readonly filesLoaded: number
|
|
21
|
+
/** Duration in milliseconds */
|
|
22
|
+
readonly durationMs: number
|
|
23
|
+
/** Total bytes loaded */
|
|
24
|
+
readonly totalBytes: number
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Simple in-memory file cache.
|
|
29
|
+
*
|
|
30
|
+
* Usage:
|
|
31
|
+
* 1. Call prewarm() before running checks (loads file contents)
|
|
32
|
+
* 2. Use get() to read file contents (falls back to disk if not cached)
|
|
33
|
+
* 3. Call clear() after checks complete
|
|
34
|
+
*/
|
|
35
|
+
const PREWARM_BATCH_SIZE = 100
|
|
36
|
+
|
|
37
|
+
class FileCache {
|
|
38
|
+
private readonly cache = new Map<string, string>()
|
|
39
|
+
private _prewarmed = false
|
|
40
|
+
private _cleared = false
|
|
41
|
+
private _autoClearTimer: ReturnType<typeof setTimeout> | null = null
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Prewarm the cache by loading all files matching patterns.
|
|
45
|
+
* @param cwd - Working directory for file resolution
|
|
46
|
+
* @param patterns - Glob patterns to prewarm file contents for
|
|
47
|
+
* @returns Prewarm statistics
|
|
48
|
+
*/
|
|
49
|
+
async prewarm(cwd: string, patterns: readonly string[]): Promise<PrewarmStats> {
|
|
50
|
+
const start = Date.now()
|
|
51
|
+
let totalBytes = 0
|
|
52
|
+
|
|
53
|
+
// Find all matching files for content caching
|
|
54
|
+
const allFiles = new Set<string>()
|
|
55
|
+
for (const pattern of patterns) {
|
|
56
|
+
// @fitness-ignore-next-line performance-anti-patterns -- sequential glob calls: each pattern must resolve before deduplication
|
|
57
|
+
const files = await glob(pattern, {
|
|
58
|
+
cwd,
|
|
59
|
+
absolute: true,
|
|
60
|
+
nodir: true,
|
|
61
|
+
ignore: ['**/node_modules/**', '**/dist/**', '**/.git/**'],
|
|
62
|
+
})
|
|
63
|
+
for (const file of files) {
|
|
64
|
+
allFiles.add(file)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Load file contents in parallel batches
|
|
69
|
+
const files = [...allFiles]
|
|
70
|
+
|
|
71
|
+
for (let i = 0; i < files.length; i += PREWARM_BATCH_SIZE) {
|
|
72
|
+
const batch = files.slice(i, i + PREWARM_BATCH_SIZE)
|
|
73
|
+
// @fitness-ignore-next-line performance-anti-patterns -- intentional batching: limits concurrent file reads to control memory pressure
|
|
74
|
+
const results = await Promise.allSettled(
|
|
75
|
+
batch.map(async (filePath) => {
|
|
76
|
+
const stats = await fs.stat(filePath)
|
|
77
|
+
if (stats.isDirectory()) {
|
|
78
|
+
return null
|
|
79
|
+
}
|
|
80
|
+
const content = await fs.readFile(filePath, 'utf8')
|
|
81
|
+
return { filePath, content }
|
|
82
|
+
}),
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
for (const result of results) {
|
|
86
|
+
if (result.status === 'fulfilled' && result.value !== null) {
|
|
87
|
+
this.cache.set(result.value.filePath, result.value.content)
|
|
88
|
+
totalBytes += result.value.content.length
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
this._prewarmed = true
|
|
94
|
+
this._cleared = false
|
|
95
|
+
this.scheduleAutoClear()
|
|
96
|
+
const durationMs = Date.now() - start
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
filesLoaded: this.cache.size,
|
|
100
|
+
durationMs,
|
|
101
|
+
totalBytes,
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Get file content from cache, falling back to disk if not cached.
|
|
107
|
+
* @throws {Error} If the path is a directory instead of a file
|
|
108
|
+
*/
|
|
109
|
+
/** Synchronously check if a file is in cache. Returns content or undefined. */
|
|
110
|
+
getCached(filePath: string): string | undefined {
|
|
111
|
+
const absolutePath = path.isAbsolute(filePath) ? filePath : path.resolve(filePath)
|
|
112
|
+
return this.cache.get(absolutePath)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async get(filePath: string): Promise<string> {
|
|
116
|
+
const absolutePath = path.isAbsolute(filePath) ? filePath : path.resolve(filePath)
|
|
117
|
+
|
|
118
|
+
const cached = this.cache.get(absolutePath)
|
|
119
|
+
if (cached !== undefined) {
|
|
120
|
+
return cached
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const stats = await fs.stat(absolutePath)
|
|
124
|
+
if (stats.isDirectory()) {
|
|
125
|
+
// @fitness-ignore-next-line result-pattern-consistency -- internal method, exceptions propagate to public Result boundary
|
|
126
|
+
throw new ValidationError(`Cannot read directory as file: ${absolutePath}`, { code: 'VALIDATION.FITNESS.DIRECTORY_AS_FILE' })
|
|
127
|
+
}
|
|
128
|
+
const content = await fs.readFile(absolutePath, 'utf8')
|
|
129
|
+
|
|
130
|
+
this.cache.set(absolutePath, content)
|
|
131
|
+
|
|
132
|
+
return content
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Check if a file exists (in cache or on disk).
|
|
137
|
+
*/
|
|
138
|
+
async exists(filePath: string): Promise<boolean> {
|
|
139
|
+
const absolutePath = path.isAbsolute(filePath) ? filePath : path.resolve(filePath)
|
|
140
|
+
|
|
141
|
+
if (this.cache.has(absolutePath)) {
|
|
142
|
+
return true
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
await fs.access(absolutePath)
|
|
147
|
+
return true
|
|
148
|
+
} catch {
|
|
149
|
+
// @swallow-ok File access check failed — treat as not accessible
|
|
150
|
+
return false
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Clear the cache. Must be called after checks complete.
|
|
156
|
+
*/
|
|
157
|
+
clear(): void {
|
|
158
|
+
this.cache.clear()
|
|
159
|
+
this._prewarmed = false
|
|
160
|
+
this._cleared = true
|
|
161
|
+
if (this._autoClearTimer) {
|
|
162
|
+
clearTimeout(this._autoClearTimer)
|
|
163
|
+
this._autoClearTimer = null
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Get all cached file paths.
|
|
169
|
+
* Returns the paths of all files loaded during prewarm or on-demand reads.
|
|
170
|
+
*/
|
|
171
|
+
paths(): readonly string[] {
|
|
172
|
+
return [...this.cache.keys()].sort()
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Get cache statistics.
|
|
177
|
+
*/
|
|
178
|
+
/** Auto-clear after timeout to prevent memory leaks from missed lifecycle cleanup */
|
|
179
|
+
private scheduleAutoClear(): void {
|
|
180
|
+
if (this._autoClearTimer) {
|
|
181
|
+
clearTimeout(this._autoClearTimer)
|
|
182
|
+
}
|
|
183
|
+
this._autoClearTimer = setTimeout(() => {
|
|
184
|
+
if (this.cache.size > 0) {
|
|
185
|
+
this.clear()
|
|
186
|
+
}
|
|
187
|
+
}, 10 * 60 * 1000) // 10 minutes
|
|
188
|
+
// Unref so the timer doesn't keep the process alive
|
|
189
|
+
this._autoClearTimer.unref()
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
get stats(): {
|
|
193
|
+
size: number
|
|
194
|
+
prewarmed: boolean
|
|
195
|
+
cleared: boolean
|
|
196
|
+
} {
|
|
197
|
+
return {
|
|
198
|
+
size: this.cache.size,
|
|
199
|
+
prewarmed: this._prewarmed,
|
|
200
|
+
cleared: this._cleared,
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Shared file cache instance.
|
|
207
|
+
*/
|
|
208
|
+
export const fileCache = new FileCache()
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Default patterns to prewarm for fitness checks.
|
|
212
|
+
*/
|
|
213
|
+
export const DEFAULT_PREWARM_PATTERNS = [
|
|
214
|
+
'**/*.ts',
|
|
215
|
+
'**/*.tsx',
|
|
216
|
+
'**/*.js',
|
|
217
|
+
'**/*.jsx',
|
|
218
|
+
'**/*.json',
|
|
219
|
+
'**/*.md',
|
|
220
|
+
] as const
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview File type filtering for per-check file extension matching
|
|
3
|
+
*
|
|
4
|
+
* Filters matched files by extension based on a check's declared fileTypes.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as path from 'node:path'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Filter files by extension based on a check's declared fileTypes.
|
|
11
|
+
* If fileTypes is undefined or empty, returns all files (universal).
|
|
12
|
+
*/
|
|
13
|
+
export function filterFilesByType(
|
|
14
|
+
files: readonly string[],
|
|
15
|
+
fileTypes: readonly string[] | undefined,
|
|
16
|
+
): string[] {
|
|
17
|
+
if (!fileTypes || fileTypes.length === 0) {
|
|
18
|
+
return [...files]
|
|
19
|
+
}
|
|
20
|
+
const extensions = new Set(fileTypes)
|
|
21
|
+
return files.filter((f) => {
|
|
22
|
+
const ext = path.extname(f).slice(1) // remove leading dot
|
|
23
|
+
return extensions.has(ext)
|
|
24
|
+
})
|
|
25
|
+
}
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
// @fitness-ignore-file batch-operation-limits -- iterates bounded collections (config entries, registry items, or small analysis results)
|
|
2
|
+
// @fitness-ignore-file concurrency-safety -- Single-threaded Node.js; Map-based caches are safe without synchronization
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Ignore directive processing for fitness checks
|
|
5
|
+
*
|
|
6
|
+
* Filters signals based on file-level and line-level ignore directives.
|
|
7
|
+
* Signals pointing at lines that contain @fitness-ignore directives are
|
|
8
|
+
* never suppressed — this prevents recursive suppression loops where
|
|
9
|
+
* directive-auditing checks would otherwise flag their own suppressions.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { logger } from '@opensip-tools/core'
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
import { countErrors, countWarnings } from '../types/severity.js'
|
|
16
|
+
|
|
17
|
+
import { extractGroup, isWeakReason, parseDirectiveLine } from './directive-inventory.js'
|
|
18
|
+
import { parseFileIgnoreDirective, parseIgnoreDirectives } from './directive-parsing.js'
|
|
19
|
+
import { fileCache } from './file-cache.js'
|
|
20
|
+
|
|
21
|
+
import type { DirectiveEntry } from './directive-inventory.js'
|
|
22
|
+
import type { CheckResult } from '../types/findings.js'
|
|
23
|
+
import type { Signal } from '@opensip-tools/core'
|
|
24
|
+
|
|
25
|
+
// =============================================================================
|
|
26
|
+
// DIRECTIVE LINE DETECTION
|
|
27
|
+
// =============================================================================
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Scan file content and return the set of 1-based line numbers that contain
|
|
31
|
+
* @fitness-ignore directives. These lines are framework infrastructure and
|
|
32
|
+
* must never be suppressed by other directives (prevents recursive loops).
|
|
33
|
+
*/
|
|
34
|
+
function findDirectiveLines(content: string): Set<number> {
|
|
35
|
+
const directiveLines = new Set<number>()
|
|
36
|
+
const lines = content.split('\n')
|
|
37
|
+
for (const [i, line] of lines.entries()) {
|
|
38
|
+
const trimmed = (line ?? '').trimStart()
|
|
39
|
+
if (
|
|
40
|
+
(trimmed.startsWith('//') || trimmed.startsWith('/*')) &&
|
|
41
|
+
trimmed.includes('@fitness-ignore')
|
|
42
|
+
) {
|
|
43
|
+
directiveLines.add(i + 1)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return directiveLines
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// =============================================================================
|
|
50
|
+
// FILE IGNORE STATUS PROCESSING
|
|
51
|
+
// =============================================================================
|
|
52
|
+
|
|
53
|
+
/** Cached per-file results from directive scanning. */
|
|
54
|
+
interface FileIgnoreInfo {
|
|
55
|
+
fileIgnored: boolean
|
|
56
|
+
ignoredLines: Set<number> | null
|
|
57
|
+
directiveLines: Set<number>
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Processes file ignore status and caches the result.
|
|
62
|
+
*/
|
|
63
|
+
async function processFileIgnoreStatus(
|
|
64
|
+
filePath: string,
|
|
65
|
+
checkId: string,
|
|
66
|
+
fileIgnoreCache: Map<string, boolean>,
|
|
67
|
+
lineIgnoreCache: Map<string, Set<number>>,
|
|
68
|
+
directiveLineCache?: Map<string, Set<number>>,
|
|
69
|
+
): Promise<FileIgnoreInfo> {
|
|
70
|
+
// in-memory: single-threaded Node.js access pattern
|
|
71
|
+
const fileIgnored = fileIgnoreCache.get(filePath)
|
|
72
|
+
|
|
73
|
+
if (fileIgnored !== undefined) {
|
|
74
|
+
return {
|
|
75
|
+
fileIgnored,
|
|
76
|
+
ignoredLines: lineIgnoreCache.get(filePath) ?? null,
|
|
77
|
+
directiveLines: directiveLineCache?.get(filePath) ?? new Set(),
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const content = await fileCache.get(filePath)
|
|
83
|
+
const isIgnored = parseFileIgnoreDirective(content, checkId)
|
|
84
|
+
fileIgnoreCache.set(filePath, isIgnored)
|
|
85
|
+
|
|
86
|
+
// Always scan for directive lines (needed for recursive loop prevention)
|
|
87
|
+
const dirLines = findDirectiveLines(content)
|
|
88
|
+
directiveLineCache?.set(filePath, dirLines)
|
|
89
|
+
|
|
90
|
+
let ignoredLines: Set<number> | null = null
|
|
91
|
+
if (!isIgnored) {
|
|
92
|
+
ignoredLines = parseIgnoreDirectives(content, checkId)
|
|
93
|
+
lineIgnoreCache.set(filePath, ignoredLines)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return { fileIgnored: isIgnored, ignoredLines, directiveLines: dirLines }
|
|
97
|
+
} catch (error) {
|
|
98
|
+
logger.warn('fitness.ignore.file_read.failed', { evt: 'fitness.ignore.file_read.failed', module: 'fitness:ignore-processing', filePath, err: error });
|
|
99
|
+
fileIgnoreCache.set(filePath, false)
|
|
100
|
+
return { fileIgnored: false, ignoredLines: null, directiveLines: new Set() }
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// =============================================================================
|
|
105
|
+
// SIGNAL FILTERING
|
|
106
|
+
// =============================================================================
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Filters signals based on ignore directives.
|
|
110
|
+
*
|
|
111
|
+
* Signals pointing at lines that contain `@fitness-ignore` directives are
|
|
112
|
+
* never suppressed. This is a structural guarantee that prevents recursive
|
|
113
|
+
* loops: a check that audits directives cannot have its findings suppressed
|
|
114
|
+
* by the very directives it reports on.
|
|
115
|
+
*/
|
|
116
|
+
interface FilterResult {
|
|
117
|
+
filteredSignals: Signal[]
|
|
118
|
+
ignoredCount: number
|
|
119
|
+
appliedFileIgnores: Set<string>
|
|
120
|
+
appliedLineIgnores: Map<string, Set<number>>
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function classifySignals(
|
|
124
|
+
signals: readonly Signal[],
|
|
125
|
+
initialIgnoredCount: number,
|
|
126
|
+
fileIgnoreCache: Map<string, boolean>,
|
|
127
|
+
lineIgnoreCache: Map<string, Set<number>>,
|
|
128
|
+
directiveLineCache: Map<string, Set<number>>,
|
|
129
|
+
): FilterResult {
|
|
130
|
+
const filteredSignals: Signal[] = []
|
|
131
|
+
let ignoredCount = initialIgnoredCount
|
|
132
|
+
const appliedFileIgnores = new Set<string>()
|
|
133
|
+
const appliedLineIgnores = new Map<string, Set<number>>()
|
|
134
|
+
|
|
135
|
+
for (const signal of signals) {
|
|
136
|
+
if (!isSignalIgnored(signal, fileIgnoreCache, lineIgnoreCache, directiveLineCache)) {
|
|
137
|
+
filteredSignals.push(signal)
|
|
138
|
+
continue
|
|
139
|
+
}
|
|
140
|
+
ignoredCount++
|
|
141
|
+
const filePath = signal.code?.file
|
|
142
|
+
if (!filePath) continue
|
|
143
|
+
|
|
144
|
+
if (fileIgnoreCache.get(filePath)) {
|
|
145
|
+
appliedFileIgnores.add(filePath)
|
|
146
|
+
} else {
|
|
147
|
+
const line = signal.code?.line
|
|
148
|
+
if (line) {
|
|
149
|
+
let lineSet = appliedLineIgnores.get(filePath)
|
|
150
|
+
if (!lineSet) {
|
|
151
|
+
lineSet = new Set()
|
|
152
|
+
appliedLineIgnores.set(filePath, lineSet)
|
|
153
|
+
}
|
|
154
|
+
lineSet.add(line)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return { filteredSignals, ignoredCount, appliedFileIgnores, appliedLineIgnores }
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** Filter signals based on file-level and line-level @fitness-ignore directives */
|
|
163
|
+
export async function filterSignalsByDirectives(
|
|
164
|
+
signals: readonly Signal[],
|
|
165
|
+
checkId: string,
|
|
166
|
+
initialIgnoredCount: number,
|
|
167
|
+
): Promise<{ filteredSignals: Signal[]; ignoredCount: number; appliedDirectives: DirectiveEntry[] }> {
|
|
168
|
+
const fileIgnoreCache = new Map<string, boolean>()
|
|
169
|
+
const lineIgnoreCache = new Map<string, Set<number>>()
|
|
170
|
+
const directiveLineCache = new Map<string, Set<number>>()
|
|
171
|
+
|
|
172
|
+
// Pre-populate file ignore status for all unique file paths in parallel
|
|
173
|
+
const uniqueFiles = new Set<string>()
|
|
174
|
+
for (const signal of signals) {
|
|
175
|
+
const filePath = signal.code?.file
|
|
176
|
+
if (filePath) uniqueFiles.add(filePath)
|
|
177
|
+
}
|
|
178
|
+
await Promise.all(
|
|
179
|
+
[...uniqueFiles].map((filePath) =>
|
|
180
|
+
processFileIgnoreStatus(filePath, checkId, fileIgnoreCache, lineIgnoreCache, directiveLineCache),
|
|
181
|
+
),
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
const { filteredSignals, ignoredCount, appliedFileIgnores, appliedLineIgnores } =
|
|
185
|
+
classifySignals(signals, initialIgnoredCount, fileIgnoreCache, lineIgnoreCache, directiveLineCache)
|
|
186
|
+
|
|
187
|
+
const appliedDirectives = await collectAppliedDirectives(checkId, appliedFileIgnores, appliedLineIgnores)
|
|
188
|
+
|
|
189
|
+
return { filteredSignals, ignoredCount, appliedDirectives }
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Determines whether a single signal should be ignored based on cached directive data.
|
|
194
|
+
*
|
|
195
|
+
* File-level ignores always apply (the entire file is suppressed).
|
|
196
|
+
* Line-level ignores apply unless the signal points at a directive line itself
|
|
197
|
+
* (prevents recursive loops where directive-auditing checks suppress their own findings).
|
|
198
|
+
*/
|
|
199
|
+
function isSignalIgnored(
|
|
200
|
+
signal: Signal,
|
|
201
|
+
fileIgnoreCache: Map<string, boolean>,
|
|
202
|
+
lineIgnoreCache: Map<string, Set<number>>,
|
|
203
|
+
directiveLineCache: Map<string, Set<number>>,
|
|
204
|
+
): boolean {
|
|
205
|
+
const filePath = signal.code?.file
|
|
206
|
+
if (!filePath) return false
|
|
207
|
+
|
|
208
|
+
// File-level ignores always apply — no anti-recursion needed
|
|
209
|
+
if (fileIgnoreCache.get(filePath)) return true
|
|
210
|
+
|
|
211
|
+
const signalLine = signal.code?.line
|
|
212
|
+
const dirLines = directiveLineCache.get(filePath)
|
|
213
|
+
// For line-level ignores: never suppress signals pointing at directive lines (anti-recursion)
|
|
214
|
+
if (signalLine && dirLines?.has(signalLine)) return false
|
|
215
|
+
|
|
216
|
+
const ignoredLines = lineIgnoreCache.get(filePath)
|
|
217
|
+
if (signalLine && ignoredLines?.has(signalLine)) return true
|
|
218
|
+
|
|
219
|
+
return false
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// =============================================================================
|
|
223
|
+
// APPLIED DIRECTIVE COLLECTION
|
|
224
|
+
// =============================================================================
|
|
225
|
+
|
|
226
|
+
function toDirectiveEntry(
|
|
227
|
+
filePath: string,
|
|
228
|
+
lineNumber: number,
|
|
229
|
+
parsed: { type: 'file' | 'next-line'; checkId: string; reason: string | null },
|
|
230
|
+
): DirectiveEntry {
|
|
231
|
+
return {
|
|
232
|
+
filePath,
|
|
233
|
+
lineNumber,
|
|
234
|
+
type: parsed.type,
|
|
235
|
+
checkId: parsed.checkId,
|
|
236
|
+
group: extractGroup(parsed.checkId),
|
|
237
|
+
reason: parsed.reason,
|
|
238
|
+
weakReason: isWeakReason(parsed.reason),
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async function collectFileIgnoreDirectives(
|
|
243
|
+
checkId: string,
|
|
244
|
+
appliedFileIgnores: Set<string>,
|
|
245
|
+
): Promise<DirectiveEntry[]> {
|
|
246
|
+
const results = await Promise.all(
|
|
247
|
+
[...appliedFileIgnores].map(async (filePath): Promise<DirectiveEntry | null> => {
|
|
248
|
+
try {
|
|
249
|
+
const content = await fileCache.get(filePath)
|
|
250
|
+
const lines = content.split('\n')
|
|
251
|
+
for (let i = 0; i < Math.min(lines.length, 50); i++) {
|
|
252
|
+
const parsed = parseDirectiveLine(lines[i] ?? '')
|
|
253
|
+
if (parsed?.type === 'file' && parsed.checkId === checkId) {
|
|
254
|
+
return toDirectiveEntry(filePath, i + 1, parsed)
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
} catch (error) {
|
|
258
|
+
logger.warn('fitness.ignore.directive_read.failed', { evt: 'fitness.ignore.directive_read.failed', module: 'fitness:ignore-processing', err: error });
|
|
259
|
+
}
|
|
260
|
+
return null
|
|
261
|
+
}),
|
|
262
|
+
)
|
|
263
|
+
return results.filter((d): d is DirectiveEntry => d !== null)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
async function collectLineIgnoreDirectives(
|
|
267
|
+
checkId: string,
|
|
268
|
+
appliedLineIgnores: Map<string, Set<number>>,
|
|
269
|
+
): Promise<DirectiveEntry[]> {
|
|
270
|
+
const results = await Promise.all(
|
|
271
|
+
[...appliedLineIgnores.entries()].map(async ([filePath, suppressedLines]): Promise<DirectiveEntry[]> => {
|
|
272
|
+
const found: DirectiveEntry[] = []
|
|
273
|
+
try {
|
|
274
|
+
const content = await fileCache.get(filePath)
|
|
275
|
+
const lines = content.split('\n')
|
|
276
|
+
for (let i = 0; i < lines.length; i++) {
|
|
277
|
+
const parsed = parseDirectiveLine(lines[i] ?? '')
|
|
278
|
+
if (parsed?.type !== 'next-line' || parsed.checkId !== checkId) continue
|
|
279
|
+
let targetLine = i + 1
|
|
280
|
+
while (targetLine < lines.length && (lines[targetLine] ?? '').trimStart().startsWith('//')) {
|
|
281
|
+
targetLine++
|
|
282
|
+
}
|
|
283
|
+
if (suppressedLines.has(targetLine + 1)) {
|
|
284
|
+
found.push(toDirectiveEntry(filePath, i + 1, parsed))
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
} catch (error) {
|
|
288
|
+
logger.warn('fitness.ignore.directive_read.failed', { evt: 'fitness.ignore.directive_read.failed', module: 'fitness:ignore-processing', err: error });
|
|
289
|
+
}
|
|
290
|
+
return found
|
|
291
|
+
}),
|
|
292
|
+
)
|
|
293
|
+
const directives: DirectiveEntry[] = []
|
|
294
|
+
for (const batch of results) {
|
|
295
|
+
for (const d of batch) {
|
|
296
|
+
directives.push(d)
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return directives
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
async function collectAppliedDirectives(
|
|
303
|
+
checkId: string,
|
|
304
|
+
appliedFileIgnores: Set<string>,
|
|
305
|
+
appliedLineIgnores: Map<string, Set<number>>,
|
|
306
|
+
): Promise<DirectiveEntry[]> {
|
|
307
|
+
const [fileDirectives, lineDirectives] = await Promise.all([
|
|
308
|
+
collectFileIgnoreDirectives(checkId, appliedFileIgnores),
|
|
309
|
+
collectLineIgnoreDirectives(checkId, appliedLineIgnores),
|
|
310
|
+
])
|
|
311
|
+
return [...fileDirectives, ...lineDirectives]
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// =============================================================================
|
|
315
|
+
// RESULT BUILDING
|
|
316
|
+
// =============================================================================
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Builds the filtered result from the original result and filtered signals.
|
|
320
|
+
*/
|
|
321
|
+
export function buildFilteredResult(
|
|
322
|
+
result: CheckResult,
|
|
323
|
+
filteredSignals: Signal[],
|
|
324
|
+
ignoredCount: number,
|
|
325
|
+
start: number,
|
|
326
|
+
): CheckResult {
|
|
327
|
+
if (!Array.isArray(filteredSignals)) {
|
|
328
|
+
return result
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const durationMs = result.metadata.durationMs ?? Date.now() - start
|
|
332
|
+
const filteredErrors = countErrors(filteredSignals)
|
|
333
|
+
const filteredWarnings = countWarnings(filteredSignals)
|
|
334
|
+
|
|
335
|
+
const filteredResult: CheckResult = {
|
|
336
|
+
...result,
|
|
337
|
+
passed: filteredErrors === 0,
|
|
338
|
+
errors: filteredErrors,
|
|
339
|
+
warnings: filteredWarnings,
|
|
340
|
+
signals: filteredSignals,
|
|
341
|
+
metadata: {
|
|
342
|
+
...result.metadata,
|
|
343
|
+
durationMs,
|
|
344
|
+
signals: filteredSignals,
|
|
345
|
+
},
|
|
346
|
+
...(ignoredCount > 0 ? { ignoredCount } : {}),
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
return filteredResult
|
|
350
|
+
}
|