@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,157 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
getIdentifierName,
|
|
6
|
+
getLineNumber,
|
|
7
|
+
getPropertyChain,
|
|
8
|
+
isInStringLiteral,
|
|
9
|
+
isLiteral,
|
|
10
|
+
isPropertyAccess,
|
|
11
|
+
parseSource,
|
|
12
|
+
walkNodes,
|
|
13
|
+
} from '../ast-utilities.js';
|
|
14
|
+
|
|
15
|
+
const parse = (content: string) => parseSource(content, 'x.ts');
|
|
16
|
+
|
|
17
|
+
describe('parseSource', () => {
|
|
18
|
+
it('parses valid TypeScript', () => {
|
|
19
|
+
expect(parse('const x = 1;')).not.toBeNull();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('returns null on parse failure', () => {
|
|
23
|
+
expect(parseSource(undefined as unknown as string, 'x.ts')).toBeNull();
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe('walkNodes', () => {
|
|
28
|
+
it('visits every descendant node', () => {
|
|
29
|
+
const sf = parse('const x = 1; const y = 2;');
|
|
30
|
+
if (!sf) throw new Error('parse failed');
|
|
31
|
+
let count = 0;
|
|
32
|
+
walkNodes(sf, () => count++);
|
|
33
|
+
expect(count).toBeGreaterThan(2);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe('getIdentifierName / getPropertyChain', () => {
|
|
38
|
+
it('returns identifier text', () => {
|
|
39
|
+
const sf = parse('foo;');
|
|
40
|
+
if (!sf) throw new Error('parse failed');
|
|
41
|
+
let leaf = '';
|
|
42
|
+
walkNodes(sf, (n) => {
|
|
43
|
+
if (ts.isIdentifier(n) && leaf === '') leaf = getIdentifierName(n);
|
|
44
|
+
});
|
|
45
|
+
expect(leaf).toBe('foo');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('returns property chain', () => {
|
|
49
|
+
const sf = parse('a.b.c;');
|
|
50
|
+
if (!sf) throw new Error('parse failed');
|
|
51
|
+
let result = '';
|
|
52
|
+
walkNodes(sf, (n) => {
|
|
53
|
+
if (ts.isPropertyAccessExpression(n) && result === '') result = getPropertyChain(n);
|
|
54
|
+
});
|
|
55
|
+
expect(result).toBe('a.b.c');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('returns empty for non-identifier non-property nodes', () => {
|
|
59
|
+
const sf = parse('1 + 2;');
|
|
60
|
+
if (!sf) throw new Error('parse failed');
|
|
61
|
+
let result = '';
|
|
62
|
+
walkNodes(sf, (n) => {
|
|
63
|
+
if (ts.isBinaryExpression(n)) {
|
|
64
|
+
result = getIdentifierName(n);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
expect(result).toBe('');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('getPropertyChain returns empty for non-identifier non-property', () => {
|
|
71
|
+
const sf = parse('1 + 2;');
|
|
72
|
+
if (!sf) throw new Error('parse failed');
|
|
73
|
+
let result = '';
|
|
74
|
+
walkNodes(sf, (n) => {
|
|
75
|
+
if (ts.isBinaryExpression(n) && result === '') result = getPropertyChain(n);
|
|
76
|
+
});
|
|
77
|
+
expect(result).toBe('');
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe('getLineNumber', () => {
|
|
82
|
+
it('returns 1-based line numbers', () => {
|
|
83
|
+
const sf = parse('\n\nconst x = 1;');
|
|
84
|
+
if (!sf) throw new Error('parse failed');
|
|
85
|
+
let line = 0;
|
|
86
|
+
walkNodes(sf, (n) => {
|
|
87
|
+
if (ts.isVariableDeclaration(n)) {
|
|
88
|
+
line = getLineNumber(n, sf);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
expect(line).toBe(3);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe('isPropertyAccess', () => {
|
|
96
|
+
it('matches the right property name', () => {
|
|
97
|
+
const sf = parse('foo.bar();');
|
|
98
|
+
if (!sf) throw new Error('parse failed');
|
|
99
|
+
let matched = false;
|
|
100
|
+
walkNodes(sf, (n) => {
|
|
101
|
+
if (ts.isPropertyAccessExpression(n) && isPropertyAccess(n, 'bar')) matched = true;
|
|
102
|
+
});
|
|
103
|
+
expect(matched).toBe(true);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('returns false for the wrong property name', () => {
|
|
107
|
+
const sf = parse('foo.bar();');
|
|
108
|
+
if (!sf) throw new Error('parse failed');
|
|
109
|
+
let matched = false;
|
|
110
|
+
walkNodes(sf, (n) => {
|
|
111
|
+
if (ts.isPropertyAccessExpression(n) && isPropertyAccess(n, 'baz')) matched = true;
|
|
112
|
+
});
|
|
113
|
+
expect(matched).toBe(false);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
describe('isLiteral', () => {
|
|
118
|
+
it.each([
|
|
119
|
+
['"hi"', true],
|
|
120
|
+
['42', true],
|
|
121
|
+
['true', true],
|
|
122
|
+
['false', true],
|
|
123
|
+
['null', true],
|
|
124
|
+
['undefined', true],
|
|
125
|
+
['x', false],
|
|
126
|
+
])('isLiteral(%s) === %s', (src, expected) => {
|
|
127
|
+
const sf = parse(`(${src});`);
|
|
128
|
+
if (!sf) throw new Error('parse failed');
|
|
129
|
+
let result: boolean | null = null;
|
|
130
|
+
walkNodes(sf, (n) => {
|
|
131
|
+
if (ts.isParenthesizedExpression(n) && result === null) result = isLiteral(n.expression);
|
|
132
|
+
});
|
|
133
|
+
expect(result).toBe(expected);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
describe('isInStringLiteral', () => {
|
|
138
|
+
it('returns true for nodes inside a template', () => {
|
|
139
|
+
const sf = parse('const x = `${foo}`;');
|
|
140
|
+
if (!sf) throw new Error('parse failed');
|
|
141
|
+
let found = false;
|
|
142
|
+
walkNodes(sf, (n) => {
|
|
143
|
+
if (ts.isIdentifier(n) && n.text === 'foo' && isInStringLiteral(n)) found = true;
|
|
144
|
+
});
|
|
145
|
+
expect(found).toBe(true);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('returns false for nodes outside any string', () => {
|
|
149
|
+
const sf = parse('const x = 1; const y = x;');
|
|
150
|
+
if (!sf) throw new Error('parse failed');
|
|
151
|
+
let found = false;
|
|
152
|
+
walkNodes(sf, (n) => {
|
|
153
|
+
if (ts.isIdentifier(n) && n.text === 'y' && !isInStringLiteral(n)) found = true;
|
|
154
|
+
});
|
|
155
|
+
expect(found).toBe(true);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { validateCheckConfig } from '../check-config.js'
|
|
4
|
+
|
|
5
|
+
const BASE_CONFIG = {
|
|
6
|
+
id: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
|
|
7
|
+
slug: 'test-check',
|
|
8
|
+
description: 'A test check',
|
|
9
|
+
tags: ['quality'],
|
|
10
|
+
analyze: () => [],
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
describe('validateCheckConfig', () => {
|
|
14
|
+
it('accepts a check with tags array', () => {
|
|
15
|
+
expect(() => validateCheckConfig(BASE_CONFIG)).not.toThrow()
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it('rejects a check without tags', () => {
|
|
19
|
+
const config = { ...BASE_CONFIG, tags: undefined }
|
|
20
|
+
expect(() => validateCheckConfig(config)).toThrow()
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('rejects a check with empty tags array', () => {
|
|
24
|
+
const config = { ...BASE_CONFIG, tags: [] }
|
|
25
|
+
expect(() => validateCheckConfig(config)).toThrow()
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('accepts arbitrary tag strings', () => {
|
|
29
|
+
const config = { ...BASE_CONFIG, tags: ['custom-tag', 'another-one', 'cwe-89'] }
|
|
30
|
+
expect(() => validateCheckConfig(config)).not.toThrow()
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('validates all three analysis modes with tags', () => {
|
|
34
|
+
// analyze mode
|
|
35
|
+
expect(() => validateCheckConfig({
|
|
36
|
+
...BASE_CONFIG,
|
|
37
|
+
analyze: (_content: string) => [],
|
|
38
|
+
})).not.toThrow()
|
|
39
|
+
|
|
40
|
+
// analyzeAll mode
|
|
41
|
+
// eslint-disable-next-line sonarjs/no-unused-vars -- destructure-omit pattern: drop `analyze` from spread copy
|
|
42
|
+
const { analyze: _, ...noAnalyze } = BASE_CONFIG
|
|
43
|
+
expect(() => validateCheckConfig({
|
|
44
|
+
...noAnalyze,
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/require-await -- arrow must match `(files: FileAccessor) => Promise<CheckViolation[]>`
|
|
46
|
+
analyzeAll: async () => [],
|
|
47
|
+
})).not.toThrow()
|
|
48
|
+
|
|
49
|
+
// command mode
|
|
50
|
+
expect(() => validateCheckConfig({
|
|
51
|
+
...noAnalyze,
|
|
52
|
+
command: {
|
|
53
|
+
bin: 'echo',
|
|
54
|
+
args: [],
|
|
55
|
+
parseOutput: () => [],
|
|
56
|
+
},
|
|
57
|
+
})).not.toThrow()
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('rejects config without any analysis mode', () => {
|
|
61
|
+
// eslint-disable-next-line sonarjs/no-unused-vars -- destructure-omit pattern: drop `analyze` from spread copy
|
|
62
|
+
const { analyze: _, ...noMode } = BASE_CONFIG
|
|
63
|
+
expect(() => validateCheckConfig(noMode)).toThrow()
|
|
64
|
+
})
|
|
65
|
+
})
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { executeCommand } from '../command-executor.js';
|
|
4
|
+
|
|
5
|
+
import type { CommandConfig } from '../check-config.js';
|
|
6
|
+
|
|
7
|
+
const cwd = process.cwd();
|
|
8
|
+
|
|
9
|
+
describe('executeCommand', () => {
|
|
10
|
+
it('runs a command with array args and parses stdout', async () => {
|
|
11
|
+
const config: CommandConfig = {
|
|
12
|
+
bin: 'echo',
|
|
13
|
+
args: ['hello'],
|
|
14
|
+
parseOutput: (stdout) => [{
|
|
15
|
+
line: 1,
|
|
16
|
+
message: stdout.trim(),
|
|
17
|
+
severity: 'warning',
|
|
18
|
+
}],
|
|
19
|
+
};
|
|
20
|
+
const result = await executeCommand(config, [], { cwd });
|
|
21
|
+
expect(result.aborted).toBe(false);
|
|
22
|
+
expect(result.exitCode).toBe(0);
|
|
23
|
+
expect(result.violations).toHaveLength(1);
|
|
24
|
+
expect(result.violations[0]?.message).toBe('hello');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('runs a command with function args derived from files', async () => {
|
|
28
|
+
const config: CommandConfig = {
|
|
29
|
+
bin: 'echo',
|
|
30
|
+
args: (files) => [`got-${files.length}`],
|
|
31
|
+
parseOutput: (stdout) => [{
|
|
32
|
+
line: 1,
|
|
33
|
+
message: stdout.trim(),
|
|
34
|
+
severity: 'warning',
|
|
35
|
+
}],
|
|
36
|
+
};
|
|
37
|
+
const result = await executeCommand(config, ['a', 'b', 'c'], { cwd });
|
|
38
|
+
expect(result.violations[0]?.message).toBe('got-3');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('returns an error when the bin is not installed (ENOENT)', async () => {
|
|
42
|
+
const config: CommandConfig = {
|
|
43
|
+
bin: 'definitely-not-a-real-binary-xyz123',
|
|
44
|
+
args: [],
|
|
45
|
+
parseOutput: () => [],
|
|
46
|
+
};
|
|
47
|
+
const result = await executeCommand(config, [], { cwd });
|
|
48
|
+
expect(result.error).toContain('not installed');
|
|
49
|
+
expect(result.violations).toEqual([]);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('returns an error when exit code is unexpected', async () => {
|
|
53
|
+
const config: CommandConfig = {
|
|
54
|
+
bin: 'sh',
|
|
55
|
+
args: ['-c', 'exit 5'],
|
|
56
|
+
parseOutput: () => [],
|
|
57
|
+
expectedExitCodes: [0],
|
|
58
|
+
};
|
|
59
|
+
const result = await executeCommand(config, [], { cwd });
|
|
60
|
+
expect(result.error).toContain('unexpected code 5');
|
|
61
|
+
expect(result.violations).toEqual([]);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('honors expectedExitCodes when set', async () => {
|
|
65
|
+
const config: CommandConfig = {
|
|
66
|
+
bin: 'sh',
|
|
67
|
+
args: ['-c', 'echo done; exit 1'],
|
|
68
|
+
parseOutput: (stdout) => [{
|
|
69
|
+
line: 1,
|
|
70
|
+
message: stdout.trim(),
|
|
71
|
+
severity: 'warning',
|
|
72
|
+
}],
|
|
73
|
+
expectedExitCodes: [0, 1],
|
|
74
|
+
};
|
|
75
|
+
const result = await executeCommand(config, [], { cwd });
|
|
76
|
+
expect(result.violations).toHaveLength(1);
|
|
77
|
+
expect(result.exitCode).toBe(1);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Pin the contentFilter dispatch in define-check.ts and
|
|
3
|
+
* file-accessor.ts. Two modes are intentional and distinct:
|
|
4
|
+
*
|
|
5
|
+
* - `strip-strings` → strings blanked, COMMENTS PRESERVED.
|
|
6
|
+
* Use when a rule reads comment markers
|
|
7
|
+
* (e.g. `// @swallow-ok`).
|
|
8
|
+
* - `strip-strings-and-comments` → both blanked. Use when the same
|
|
9
|
+
* forbidden phrase could appear in a
|
|
10
|
+
* comment and would false-fire.
|
|
11
|
+
*
|
|
12
|
+
* Mixing them was the bug behind a 2026-05-05 mis-fix that mapped both
|
|
13
|
+
* modes to codeNoComments, breaking every rule that scans comments for
|
|
14
|
+
* directives. This test pins the contract.
|
|
15
|
+
*
|
|
16
|
+
* The legacy `'code-only'` / `'no-strings-no-comments'` aliases were
|
|
17
|
+
* removed in 0.5.0; this file used to assert the alias mapping and now
|
|
18
|
+
* just asserts the canonical names.
|
|
19
|
+
*/
|
|
20
|
+
import { mkdtemp, writeFile } from 'node:fs/promises'
|
|
21
|
+
import { tmpdir } from 'node:os'
|
|
22
|
+
import { join } from 'node:path'
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
import { defaultLanguageRegistry } from '@opensip-tools/core'
|
|
26
|
+
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
|
|
27
|
+
|
|
28
|
+
import { filterContent } from '../content-filter.js'
|
|
29
|
+
import { createFileAccessor } from '../file-accessor.js'
|
|
30
|
+
|
|
31
|
+
import type { LanguageAdapter } from '@opensip-tools/core'
|
|
32
|
+
|
|
33
|
+
// FileAccessor.read dispatches strip via the registered LanguageAdapter
|
|
34
|
+
// for the file's extension. Register a minimal TS adapter for the test
|
|
35
|
+
// scope so the dispatch resolves and the existing core filterContent
|
|
36
|
+
// implementation produces the expected output. Lang packages live in
|
|
37
|
+
// their own workspaces and core can't depend on @opensip-tools/lang-typescript
|
|
38
|
+
// directly without creating a cycle.
|
|
39
|
+
const inProcessTypescriptAdapter: LanguageAdapter = {
|
|
40
|
+
id: 'typescript-test-shim',
|
|
41
|
+
fileExtensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'],
|
|
42
|
+
parse: () => null,
|
|
43
|
+
stripStrings: (s) => filterContent(s).code,
|
|
44
|
+
stripComments: (s) => filterContent(s).codeNoComments,
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
beforeAll(() => {
|
|
48
|
+
defaultLanguageRegistry.register(inProcessTypescriptAdapter)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
afterAll(() => {
|
|
52
|
+
defaultLanguageRegistry.clear()
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
async function writeTempFile(content: string): Promise<string> {
|
|
56
|
+
const dir = await mkdtemp(join(tmpdir(), 'cf-dispatch-'))
|
|
57
|
+
const filePath = join(dir, 'sample.ts')
|
|
58
|
+
await writeFile(filePath, content, 'utf8')
|
|
59
|
+
return filePath
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
describe('FileAccessor contentFilter dispatch', () => {
|
|
63
|
+
describe('strip-strings — strings blanked, comments preserved', () => {
|
|
64
|
+
it('preserves line-comment text so rules can scan markers', async () => {
|
|
65
|
+
const filePath = await writeTempFile(
|
|
66
|
+
`const a = 1\n// @swallow-ok intentional fallthrough\nconst b = 2`,
|
|
67
|
+
)
|
|
68
|
+
const accessor = createFileAccessor([filePath], { contentFilter: 'strip-strings' })
|
|
69
|
+
const content = await accessor.read(filePath)
|
|
70
|
+
|
|
71
|
+
expect(content).toContain('@swallow-ok')
|
|
72
|
+
expect(content).toContain('const a = 1')
|
|
73
|
+
expect(content).toContain('const b = 2')
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('preserves block-comment text including JSDoc directives', async () => {
|
|
77
|
+
const filePath = await writeTempFile(
|
|
78
|
+
`/** @deprecated use Y instead */\nexport function legacy() {}`,
|
|
79
|
+
)
|
|
80
|
+
const accessor = createFileAccessor([filePath], { contentFilter: 'strip-strings' })
|
|
81
|
+
const content = await accessor.read(filePath)
|
|
82
|
+
|
|
83
|
+
expect(content).toContain('@deprecated')
|
|
84
|
+
expect(content).toContain('export function legacy')
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
it('blanks string-literal contents', async () => {
|
|
88
|
+
const filePath = await writeTempFile(`const url = 'phrase_in_string'`)
|
|
89
|
+
const accessor = createFileAccessor([filePath], { contentFilter: 'strip-strings' })
|
|
90
|
+
const content = await accessor.read(filePath)
|
|
91
|
+
|
|
92
|
+
expect(content).not.toContain('phrase_in_string')
|
|
93
|
+
expect(content).toContain('const url = ')
|
|
94
|
+
})
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
describe('strip-strings-and-comments — both blanked', () => {
|
|
98
|
+
it('blanks comment text so rules don\'t false-fire on prose', async () => {
|
|
99
|
+
const filePath = await writeTempFile(
|
|
100
|
+
`const a = 1\n// forbidden_phrase_in_comment\nconst b = 2`,
|
|
101
|
+
)
|
|
102
|
+
const accessor = createFileAccessor([filePath], { contentFilter: 'strip-strings-and-comments' })
|
|
103
|
+
const content = await accessor.read(filePath)
|
|
104
|
+
|
|
105
|
+
expect(content).not.toContain('forbidden_phrase_in_comment')
|
|
106
|
+
expect(content).toContain('const a = 1')
|
|
107
|
+
expect(content).toContain('const b = 2')
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
it('blanks both strings and comments in the same content', async () => {
|
|
111
|
+
const filePath = await writeTempFile(
|
|
112
|
+
`const url = 'phrase_in_string' // phrase_in_comment`,
|
|
113
|
+
)
|
|
114
|
+
const accessor = createFileAccessor([filePath], { contentFilter: 'strip-strings-and-comments' })
|
|
115
|
+
const content = await accessor.read(filePath)
|
|
116
|
+
|
|
117
|
+
expect(content).not.toContain('phrase_in_string')
|
|
118
|
+
expect(content).not.toContain('phrase_in_comment')
|
|
119
|
+
})
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
describe('default (raw) — no filter applied', () => {
|
|
123
|
+
it('preserves both strings and comments verbatim', async () => {
|
|
124
|
+
const src = `const url = 'phrase'\n// also phrase`
|
|
125
|
+
const filePath = await writeTempFile(src)
|
|
126
|
+
const accessor = createFileAccessor([filePath]) // no contentFilter → raw passthrough
|
|
127
|
+
const content = await accessor.read(filePath)
|
|
128
|
+
|
|
129
|
+
expect(content).toBe(src)
|
|
130
|
+
})
|
|
131
|
+
})
|
|
132
|
+
})
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { clearFilterCache, filterContent } from '../content-filter.js'
|
|
4
|
+
|
|
5
|
+
describe('filterContent', () => {
|
|
6
|
+
describe('string and comment masking', () => {
|
|
7
|
+
it('replaces string-literal content with spaces but preserves length', () => {
|
|
8
|
+
clearFilterCache()
|
|
9
|
+
const src = `const x = 'hello'`
|
|
10
|
+
const { code } = filterContent(src)
|
|
11
|
+
expect(code.length).toBe(src.length)
|
|
12
|
+
expect(code).toBe(`const x = ' '`)
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('preserves comment content verbatim (comments tracked, not masked)', () => {
|
|
16
|
+
clearFilterCache()
|
|
17
|
+
const src = `const x = 1 // loadConfig() mentioned here\nconst y = 2`
|
|
18
|
+
const { code } = filterContent(src)
|
|
19
|
+
// Line comments are left intact — directives live in comments
|
|
20
|
+
expect(code).toContain('loadConfig() mentioned here')
|
|
21
|
+
})
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
describe('template literals', () => {
|
|
25
|
+
it('masks simple template body text', () => {
|
|
26
|
+
clearFilterCache()
|
|
27
|
+
const src = `const x = \`hello world\``
|
|
28
|
+
const { code } = filterContent(src)
|
|
29
|
+
expect(code).toBe(`const x = \` \``)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('masks template-head and template-tail text, preserves expressions', () => {
|
|
33
|
+
clearFilterCache()
|
|
34
|
+
const src = `const x = \`pre \${value} post\``
|
|
35
|
+
const { code } = filterContent(src)
|
|
36
|
+
// Expression `value` is code — preserved. Text around `${ ... }` is masked.
|
|
37
|
+
expect(code).toContain('value')
|
|
38
|
+
expect(code).not.toContain('pre ')
|
|
39
|
+
expect(code).not.toContain(' post')
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
// Regression: nested templates inside `${...}` expressions used to desync the
|
|
43
|
+
// scanner state (a plain `inTemplate` boolean flipped off by the inner
|
|
44
|
+
// TemplateTail left the outer's CloseBrace unrescanned, which caused every
|
|
45
|
+
// token after the inner template to be misinterpreted as part of a string).
|
|
46
|
+
// The symptom was that real code — `loadConfig(process.cwd())`, type
|
|
47
|
+
// annotations, anything — below the nested template got wiped to whitespace
|
|
48
|
+
// silently, producing false negatives in every `contentFilter: 'strip-strings'`
|
|
49
|
+
// check that scanned the affected file. Fix replaced the boolean with a
|
|
50
|
+
// depth counter; this test keeps it fixed.
|
|
51
|
+
it('handles nested templates inside ${} expressions — code below is preserved', () => {
|
|
52
|
+
clearFilterCache()
|
|
53
|
+
const src = [
|
|
54
|
+
'const lines = items.map(f => `- ${sanitize(f)}`).join("\\n")',
|
|
55
|
+
'const after = loadConfig(process.cwd())',
|
|
56
|
+
'export function helper(cfg: ReturnType<typeof loadConfig>): string { return "" }',
|
|
57
|
+
].join('\n')
|
|
58
|
+
const { code } = filterContent(src)
|
|
59
|
+
// The nested template's inner text `- ` should be masked, but sanitize(f),
|
|
60
|
+
// the .map/.join chain, and everything below must survive intact.
|
|
61
|
+
expect(code).toContain('sanitize(f)')
|
|
62
|
+
expect(code).toContain('loadConfig(process.cwd())')
|
|
63
|
+
expect(code).toContain('ReturnType<typeof loadConfig>')
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('handles doubly-nested templates', () => {
|
|
67
|
+
clearFilterCache()
|
|
68
|
+
const src = [
|
|
69
|
+
'const s = `a ${`b ${c}`} d`',
|
|
70
|
+
'const survives = loadConfig(process.cwd())',
|
|
71
|
+
].join('\n')
|
|
72
|
+
const { code } = filterContent(src)
|
|
73
|
+
expect(code).toContain('survives')
|
|
74
|
+
expect(code).toContain('loadConfig(process.cwd())')
|
|
75
|
+
// The identifier `c` inside the innermost expression is code and must survive
|
|
76
|
+
expect(code).toContain('${c}')
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
describe('codeNoComments — strings AND comments masked', () => {
|
|
81
|
+
it('masks line comments while preserving line/column offsets', () => {
|
|
82
|
+
clearFilterCache()
|
|
83
|
+
const src = `const x = 1 // calls getDatabase() somewhere\nconst y = 2`
|
|
84
|
+
const { code, codeNoComments } = filterContent(src)
|
|
85
|
+
// `code` (strings-only) leaves the line comment intact
|
|
86
|
+
expect(code).toContain('getDatabase()')
|
|
87
|
+
// `codeNoComments` masks the comment text but keeps length
|
|
88
|
+
expect(codeNoComments.length).toBe(src.length)
|
|
89
|
+
expect(codeNoComments).not.toContain('getDatabase')
|
|
90
|
+
// Code BEFORE the comment survives
|
|
91
|
+
expect(codeNoComments).toContain('const x = 1')
|
|
92
|
+
// Newlines are preserved so line numbers stay accurate
|
|
93
|
+
expect(codeNoComments.split('\n')).toHaveLength(2)
|
|
94
|
+
expect(codeNoComments.split('\n')[1]).toBe('const y = 2')
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it('masks block / JSDoc comments across multiple lines', () => {
|
|
98
|
+
clearFilterCache()
|
|
99
|
+
const src = [
|
|
100
|
+
'/**',
|
|
101
|
+
' * Replace getDatabase() with the constructor StoreDeps.',
|
|
102
|
+
' * The check guards against process-wide tenant accessors.',
|
|
103
|
+
' */',
|
|
104
|
+
'export class TicketStore {}',
|
|
105
|
+
].join('\n')
|
|
106
|
+
const { codeNoComments } = filterContent(src)
|
|
107
|
+
expect(codeNoComments).not.toContain('getDatabase')
|
|
108
|
+
expect(codeNoComments).not.toContain('StoreDeps')
|
|
109
|
+
expect(codeNoComments).not.toContain('process-wide')
|
|
110
|
+
// Code AFTER the JSDoc survives
|
|
111
|
+
expect(codeNoComments).toContain('export class TicketStore')
|
|
112
|
+
// Line count preserved
|
|
113
|
+
expect(codeNoComments.split('\n')).toHaveLength(5)
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
it('masks both strings and comments in the same content', () => {
|
|
117
|
+
clearFilterCache()
|
|
118
|
+
const src = `const url = 'https://api.example.com' // call openai.messages.create() here`
|
|
119
|
+
const { codeNoComments } = filterContent(src)
|
|
120
|
+
expect(codeNoComments).not.toContain('https')
|
|
121
|
+
expect(codeNoComments).not.toContain('messages.create')
|
|
122
|
+
expect(codeNoComments).toContain('const url = ')
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
it('does not strip comments when only `code` is requested', () => {
|
|
126
|
+
// Regression guard: codeNoComments is a sibling field, not a replacement.
|
|
127
|
+
// `code` must continue to leave comments intact (some checks scan
|
|
128
|
+
// comments for `@deprecated` / `@fitness-ignore` directives).
|
|
129
|
+
clearFilterCache()
|
|
130
|
+
const src = `const x = 1 // @deprecated — use Y instead`
|
|
131
|
+
const { code, codeNoComments } = filterContent(src)
|
|
132
|
+
expect(code).toContain('@deprecated')
|
|
133
|
+
expect(codeNoComments).not.toContain('@deprecated')
|
|
134
|
+
})
|
|
135
|
+
})
|
|
136
|
+
})
|