@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,180 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { defineCheck } from '../define-check.js';
|
|
4
|
+
|
|
5
|
+
describe('defineCheck', () => {
|
|
6
|
+
describe('analyze mode', () => {
|
|
7
|
+
const noFooCheck = defineCheck({
|
|
8
|
+
id: '11111111-1111-4111-8111-111111111111',
|
|
9
|
+
slug: 'no-foo',
|
|
10
|
+
description: 'flag any line containing FOO',
|
|
11
|
+
tags: ['quality'],
|
|
12
|
+
analyze: (content, filePath) => {
|
|
13
|
+
const out: { line: number; message: string; severity: 'error' | 'warning'; filePath: string }[] = [];
|
|
14
|
+
const lines = content.split('\n');
|
|
15
|
+
for (const [i, line] of lines.entries()) {
|
|
16
|
+
if (line?.includes('FOO')) {
|
|
17
|
+
out.push({ line: i + 1, message: 'FOO not allowed', severity: 'error', filePath });
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return out;
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('returns a Check with the configured slug and id', () => {
|
|
25
|
+
expect(noFooCheck.config.slug).toBe('no-foo');
|
|
26
|
+
expect(noFooCheck.config.id).toBe('11111111-1111-4111-8111-111111111111');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('defaults itemType to "files"', () => {
|
|
30
|
+
expect(noFooCheck.config.itemType).toBe('files');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('marks scansFiles=true for analyze mode', () => {
|
|
34
|
+
expect(noFooCheck.config.scansFiles).toBe(true);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('records analysisMode "analyze"', () => {
|
|
38
|
+
expect(noFooCheck.config.analysisMode).toBe('analyze');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('preserves user-supplied tags', () => {
|
|
42
|
+
expect(noFooCheck.config.tags).toEqual(['quality']);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('exposes a getScope() and getMatcher() pair', () => {
|
|
46
|
+
const scope = noFooCheck.getScope();
|
|
47
|
+
expect(scope.include).toEqual([]);
|
|
48
|
+
expect(noFooCheck.getMatcher('/tmp')).toBeDefined();
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe('analyzeAll mode', () => {
|
|
53
|
+
const allCheck = defineCheck({
|
|
54
|
+
id: '22222222-2222-4222-8222-222222222222',
|
|
55
|
+
slug: 'all-mode-check',
|
|
56
|
+
description: 'returns no violations',
|
|
57
|
+
tags: ['demo'],
|
|
58
|
+
// eslint-disable-next-line @typescript-eslint/require-await -- stub for shape verification
|
|
59
|
+
analyzeAll: async () => [],
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('records analysisMode "analyzeAll"', () => {
|
|
63
|
+
expect(allCheck.config.analysisMode).toBe('analyzeAll');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('marks scansFiles=true for analyzeAll mode', () => {
|
|
67
|
+
expect(allCheck.config.scansFiles).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe('command mode', () => {
|
|
72
|
+
const cmd = defineCheck({
|
|
73
|
+
id: '33333333-3333-4333-8333-333333333333',
|
|
74
|
+
slug: 'cmd-check',
|
|
75
|
+
description: 'shells out',
|
|
76
|
+
tags: ['demo'],
|
|
77
|
+
command: { bin: 'echo', args: ['hello'], parseOutput: () => [] },
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('records analysisMode "command"', () => {
|
|
81
|
+
expect(cmd.config.analysisMode).toBe('command');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('marks scansFiles=false for command mode', () => {
|
|
85
|
+
expect(cmd.config.scansFiles).toBe(false);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe('scope handling', () => {
|
|
90
|
+
it('passes through scope.languages and scope.concerns', () => {
|
|
91
|
+
const c = defineCheck({
|
|
92
|
+
id: '44444444-4444-4444-8444-444444444444',
|
|
93
|
+
slug: 'scoped',
|
|
94
|
+
description: 's',
|
|
95
|
+
tags: ['demo'],
|
|
96
|
+
scope: { languages: ['typescript', 'rust'], concerns: ['backend'] },
|
|
97
|
+
analyze: () => [],
|
|
98
|
+
});
|
|
99
|
+
expect(c.config.checkScope?.languages).toEqual(['typescript', 'rust']);
|
|
100
|
+
expect(c.config.checkScope?.concerns).toEqual(['backend']);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('leaves checkScope undefined when scope is omitted', () => {
|
|
104
|
+
const c = defineCheck({
|
|
105
|
+
id: '55555555-5555-4555-8555-555555555555',
|
|
106
|
+
slug: 'unscoped',
|
|
107
|
+
description: 's',
|
|
108
|
+
tags: ['demo'],
|
|
109
|
+
analyze: () => [],
|
|
110
|
+
});
|
|
111
|
+
expect(c.config.checkScope).toBeUndefined();
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
describe('runtime metadata passthrough', () => {
|
|
116
|
+
it('preserves docs, disabled, confidence, and timeout', () => {
|
|
117
|
+
const c = defineCheck({
|
|
118
|
+
id: '66666666-6666-4666-8666-666666666666',
|
|
119
|
+
slug: 'with-meta',
|
|
120
|
+
description: 'meta',
|
|
121
|
+
tags: ['demo'],
|
|
122
|
+
docs: 'https://example.com/x',
|
|
123
|
+
disabled: true,
|
|
124
|
+
confidence: 'high',
|
|
125
|
+
timeout: 1234,
|
|
126
|
+
analyze: () => [],
|
|
127
|
+
});
|
|
128
|
+
expect(c.config.docs).toBe('https://example.com/x');
|
|
129
|
+
expect(c.config.disabled).toBe(true);
|
|
130
|
+
expect(c.config.confidence).toBe('high');
|
|
131
|
+
expect(c.config.timeout).toBe(1234);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('copies fileTypes when provided', () => {
|
|
135
|
+
const c = defineCheck({
|
|
136
|
+
id: '77777777-7777-4777-8777-777777777777',
|
|
137
|
+
slug: 'typed',
|
|
138
|
+
description: 'd',
|
|
139
|
+
tags: ['demo'],
|
|
140
|
+
fileTypes: ['ts', 'tsx'],
|
|
141
|
+
analyze: () => [],
|
|
142
|
+
});
|
|
143
|
+
expect(c.config.fileTypes).toEqual(['ts', 'tsx']);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
describe('validation', () => {
|
|
148
|
+
it('throws when id is missing', () => {
|
|
149
|
+
expect(() =>
|
|
150
|
+
// @ts-expect-error — testing the runtime guard
|
|
151
|
+
defineCheck({ slug: 'no-id', description: 'd', tags: [], analyze: () => [] }),
|
|
152
|
+
).toThrow();
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('throws when id is not a UUID', () => {
|
|
156
|
+
expect(() =>
|
|
157
|
+
defineCheck({
|
|
158
|
+
id: 'not-a-uuid',
|
|
159
|
+
slug: 'bad-id',
|
|
160
|
+
description: 'd',
|
|
161
|
+
tags: ['demo'],
|
|
162
|
+
analyze: () => [],
|
|
163
|
+
}),
|
|
164
|
+
).toThrow();
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('throws when slug is missing', () => {
|
|
168
|
+
expect(() =>
|
|
169
|
+
defineCheck({
|
|
170
|
+
id: '88888888-8888-4888-8888-888888888888',
|
|
171
|
+
// @ts-expect-error — testing the runtime guard
|
|
172
|
+
slug: undefined,
|
|
173
|
+
description: 'd',
|
|
174
|
+
tags: ['demo'],
|
|
175
|
+
analyze: () => [],
|
|
176
|
+
}),
|
|
177
|
+
).toThrow();
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { parseDirectiveLine } from '../directive-inventory.js'
|
|
4
|
+
|
|
5
|
+
describe('parseDirectiveLine', () => {
|
|
6
|
+
describe('line comments (// form)', () => {
|
|
7
|
+
it('parses @fitness-ignore-file with reason', () => {
|
|
8
|
+
const result = parseDirectiveLine('// @fitness-ignore-file no-console-log -- debug scaffold for this module')
|
|
9
|
+
expect(result).toEqual({ type: 'file', checkId: 'no-console-log', reason: 'debug scaffold for this module' })
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
it('parses @fitness-ignore-next-line without reason', () => {
|
|
13
|
+
const result = parseDirectiveLine('// @fitness-ignore-next-line no-any-types')
|
|
14
|
+
expect(result).toEqual({ type: 'next-line', checkId: 'no-any-types', reason: null })
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it('rejects lines without the directive prefix', () => {
|
|
18
|
+
expect(parseDirectiveLine('// just a comment')).toBeNull()
|
|
19
|
+
expect(parseDirectiveLine('const x = 1;')).toBeNull()
|
|
20
|
+
})
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
describe('block comments (/* form) — parity with suppression parser', () => {
|
|
24
|
+
it('parses single-line block directive with reason', () => {
|
|
25
|
+
const result = parseDirectiveLine('/* @fitness-ignore-file no-console-log -- legacy file */')
|
|
26
|
+
expect(result).toEqual({ type: 'file', checkId: 'no-console-log', reason: 'legacy file' })
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('parses single-line block directive without reason', () => {
|
|
30
|
+
const result = parseDirectiveLine('/* @fitness-ignore-next-line no-any-types */')
|
|
31
|
+
expect(result).toEqual({ type: 'next-line', checkId: 'no-any-types', reason: null })
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('strips trailing whitespace before */', () => {
|
|
35
|
+
const result = parseDirectiveLine('/* @fitness-ignore-file some-check */')
|
|
36
|
+
expect(result).toEqual({ type: 'file', checkId: 'some-check', reason: null })
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
describe('rejection cases', () => {
|
|
41
|
+
it('rejects directive without comment marker', () => {
|
|
42
|
+
expect(parseDirectiveLine('@fitness-ignore-file foo')).toBeNull()
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('rejects checkId with spaces', () => {
|
|
46
|
+
expect(parseDirectiveLine('// @fitness-ignore-file foo bar baz')).toBeNull()
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('rejects empty checkId', () => {
|
|
50
|
+
expect(parseDirectiveLine('// @fitness-ignore-file ')).toBeNull()
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
})
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
|
|
2
|
+
import { tmpdir } from 'node:os'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
|
6
|
+
|
|
7
|
+
import { createExecutionContext } from '../execution-context.js'
|
|
8
|
+
import { fileCache } from '../file-cache.js'
|
|
9
|
+
import { PathMatcher } from '../path-matcher.js'
|
|
10
|
+
|
|
11
|
+
let testDir: string
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
testDir = mkdtempSync(join(tmpdir(), 'opensip-exec-ctx-'))
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
fileCache.clear()
|
|
19
|
+
rmSync(testDir, { recursive: true, force: true })
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
describe('createExecutionContext > matchFiles fileCache fallback', () => {
|
|
23
|
+
// Regression test for the scope-resolver bug surfaced during the
|
|
24
|
+
// checks-builtin split: scope-empty checks (e.g. file-length-limit)
|
|
25
|
+
// were scanning every prewarmed file, including paths the user had
|
|
26
|
+
// explicitly listed in `globalExcludes`. The fix threads the run's
|
|
27
|
+
// globalExcludes through RunOptions into the matchFiles fallback.
|
|
28
|
+
|
|
29
|
+
// eslint-disable-next-line unicorn/consistent-function-scoping -- closes over describe-scoped `testDir`
|
|
30
|
+
function setupCachedFiles(): void {
|
|
31
|
+
mkdirSync(join(testDir, 'src'), { recursive: true })
|
|
32
|
+
mkdirSync(join(testDir, 'docs'), { recursive: true })
|
|
33
|
+
mkdirSync(join(testDir, 'tests', 'fixtures'), { recursive: true })
|
|
34
|
+
|
|
35
|
+
writeFileSync(join(testDir, 'src', 'a.ts'), 'export const a = 1')
|
|
36
|
+
writeFileSync(join(testDir, 'docs', 'design.md'), '# Design')
|
|
37
|
+
writeFileSync(join(testDir, 'tests', 'fixtures', 'sample.json'), '{}')
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function runMatchFiles(globalExcludes?: readonly string[]): Promise<readonly string[]> {
|
|
41
|
+
setupCachedFiles()
|
|
42
|
+
await fileCache.prewarm(testDir, ['**/*.ts', '**/*.md', '**/*.json'])
|
|
43
|
+
|
|
44
|
+
const matcher = PathMatcher.create({ cwd: testDir, include: [], exclude: [] })
|
|
45
|
+
const ctx = createExecutionContext(
|
|
46
|
+
{ id: 'test-id', slug: 'test-slug', itemType: 'files' },
|
|
47
|
+
testDir,
|
|
48
|
+
matcher,
|
|
49
|
+
globalExcludes ? { globalExcludes } : undefined,
|
|
50
|
+
)
|
|
51
|
+
return ctx.matchFiles()
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
it('returns every cached path when no globalExcludes are provided', async () => {
|
|
55
|
+
const files = await runMatchFiles()
|
|
56
|
+
expect(files.length).toBe(3)
|
|
57
|
+
// Sanity: includes the docs and fixtures files that we'll exclude below
|
|
58
|
+
expect(files.some((f) => f.endsWith('docs/design.md'))).toBe(true)
|
|
59
|
+
expect(files.some((f) => f.endsWith('tests/fixtures/sample.json'))).toBe(true)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('filters paths matching globalExcludes patterns out of the fallback', async () => {
|
|
63
|
+
const files = await runMatchFiles(['docs/**', 'tests/fixtures/**'])
|
|
64
|
+
expect(files.length).toBe(1)
|
|
65
|
+
expect(files[0]).toMatch(/src\/a\.ts$/)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('honors extension-style globalExcludes (*.md, *.json)', async () => {
|
|
69
|
+
const files = await runMatchFiles(['**/*.md', '**/*.json'])
|
|
70
|
+
expect(files.length).toBe(1)
|
|
71
|
+
expect(files[0]).toMatch(/src\/a\.ts$/)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('returns the unfiltered list when globalExcludes is an empty array', async () => {
|
|
75
|
+
// Empty array must not engage the matcher at all — otherwise we
|
|
76
|
+
// pay relative-path computation per file for no reason.
|
|
77
|
+
const files = await runMatchFiles([])
|
|
78
|
+
expect(files.length).toBe(3)
|
|
79
|
+
})
|
|
80
|
+
})
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
|
|
5
|
+
import { ValidationError } from '@opensip-tools/core';
|
|
6
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
7
|
+
|
|
8
|
+
import { createFileAccessor } from '../file-accessor.js';
|
|
9
|
+
import { fileCache } from '../file-cache.js';
|
|
10
|
+
|
|
11
|
+
let testDir: string;
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
|
|
15
|
+
testDir = mkdtempSync(join(tmpdir(), 'opensip-fa-'));
|
|
16
|
+
fileCache.clear();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
21
|
+
fileCache.clear();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe('createFileAccessor', () => {
|
|
25
|
+
it('exposes the configured paths via the readonly paths property', () => {
|
|
26
|
+
const acc = createFileAccessor(['/a.ts', '/b.ts']);
|
|
27
|
+
expect(acc.paths).toEqual(['/a.ts', '/b.ts']);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('reads file content from disk via fileCache when not preloaded', async () => {
|
|
31
|
+
const path = join(testDir, 'x.ts');
|
|
32
|
+
writeFileSync(path, 'hi');
|
|
33
|
+
const acc = createFileAccessor([path]);
|
|
34
|
+
expect(await acc.read(path)).toBe('hi');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('rejects reads of paths not in the configured set', async () => {
|
|
38
|
+
const acc = createFileAccessor(['/allowed.ts']);
|
|
39
|
+
await expect(acc.read('/disallowed.ts')).rejects.toThrow(ValidationError);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('caches reads — second call returns the same content even if disk changed', async () => {
|
|
43
|
+
const path = join(testDir, 'cache.ts');
|
|
44
|
+
writeFileSync(path, 'first');
|
|
45
|
+
const acc = createFileAccessor([path]);
|
|
46
|
+
expect(await acc.read(path)).toBe('first');
|
|
47
|
+
writeFileSync(path, 'second');
|
|
48
|
+
// Cached
|
|
49
|
+
expect(await acc.read(path)).toBe('first');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('throws ValidationError when a file exceeds 10 MB', async () => {
|
|
53
|
+
const path = join(testDir, 'big.txt');
|
|
54
|
+
// Use Buffer-write to avoid loading 11 MB of string into memory unnecessarily
|
|
55
|
+
writeFileSync(path, Buffer.alloc(11 * 1024 * 1024, 'a'));
|
|
56
|
+
const acc = createFileAccessor([path]);
|
|
57
|
+
await expect(acc.read(path)).rejects.toThrow(/File too large/);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('readMany reads multiple files and returns a Map', async () => {
|
|
61
|
+
const a = join(testDir, 'a.ts');
|
|
62
|
+
const b = join(testDir, 'b.ts');
|
|
63
|
+
writeFileSync(a, 'A');
|
|
64
|
+
writeFileSync(b, 'B');
|
|
65
|
+
const acc = createFileAccessor([a, b]);
|
|
66
|
+
const map = await acc.readMany([a, b]);
|
|
67
|
+
expect(map.get(a)).toBe('A');
|
|
68
|
+
expect(map.get(b)).toBe('B');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('readAll returns every configured path', async () => {
|
|
72
|
+
const a = join(testDir, 'a.ts');
|
|
73
|
+
writeFileSync(a, 'AA');
|
|
74
|
+
const acc = createFileAccessor([a]);
|
|
75
|
+
const map = await acc.readAll();
|
|
76
|
+
expect(map.size).toBe(1);
|
|
77
|
+
expect(map.get(a)).toBe('AA');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('throws when an aborted signal is passed', async () => {
|
|
81
|
+
const ac = new AbortController();
|
|
82
|
+
ac.abort();
|
|
83
|
+
const path = join(testDir, 'z.ts');
|
|
84
|
+
writeFileSync(path, 'z');
|
|
85
|
+
const acc = createFileAccessor([path], { signal: ac.signal });
|
|
86
|
+
await expect(acc.read(path)).rejects.toThrow();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('cachedCount reflects internal LRU size', async () => {
|
|
90
|
+
const path = join(testDir, 'cnt.ts');
|
|
91
|
+
writeFileSync(path, 'cnt');
|
|
92
|
+
const acc = createFileAccessor([path]) as unknown as { cachedCount: number; clearCache: () => void; read: (p: string) => Promise<string> };
|
|
93
|
+
expect(acc.cachedCount).toBe(0);
|
|
94
|
+
await acc.read(path);
|
|
95
|
+
expect(acc.cachedCount).toBe(1);
|
|
96
|
+
acc.clearCache();
|
|
97
|
+
expect(acc.cachedCount).toBe(0);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('preferentially returns content from the global fileCache when prewarmed', async () => {
|
|
101
|
+
const path = join(testDir, 'p.ts');
|
|
102
|
+
writeFileSync(path, 'on-disk');
|
|
103
|
+
await fileCache.prewarm(testDir, ['p.ts']);
|
|
104
|
+
// Mutate disk; accessor should still return prewarmed content
|
|
105
|
+
writeFileSync(path, 'changed');
|
|
106
|
+
const acc = createFileAccessor([path]);
|
|
107
|
+
expect(await acc.read(path)).toBe('on-disk');
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('LRU eviction kicks in beyond the configured capacity', async () => {
|
|
111
|
+
const paths: string[] = [];
|
|
112
|
+
for (let i = 0; i < 5; i++) {
|
|
113
|
+
const p = join(testDir, `${i}.ts`);
|
|
114
|
+
writeFileSync(p, String(i));
|
|
115
|
+
paths.push(p);
|
|
116
|
+
}
|
|
117
|
+
const acc = createFileAccessor(paths, { cacheCapacity: 2 }) as unknown as { cachedCount: number; read: (p: string) => Promise<string> };
|
|
118
|
+
for (const p of paths) await acc.read(p);
|
|
119
|
+
expect(acc.cachedCount).toBe(2);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
|
|
5
|
+
import { ValidationError } from '@opensip-tools/core';
|
|
6
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
7
|
+
|
|
8
|
+
import { DEFAULT_PREWARM_PATTERNS, fileCache } from '../file-cache.js';
|
|
9
|
+
|
|
10
|
+
let testDir: string;
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
|
|
14
|
+
testDir = mkdtempSync(join(tmpdir(), 'opensip-fc-'));
|
|
15
|
+
fileCache.clear();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
fileCache.clear();
|
|
20
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe('fileCache.prewarm', () => {
|
|
24
|
+
it('loads matching files into the cache', async () => {
|
|
25
|
+
writeFileSync(join(testDir, 'a.ts'), 'export const a = 1;');
|
|
26
|
+
writeFileSync(join(testDir, 'b.ts'), 'export const b = 2;');
|
|
27
|
+
const stats = await fileCache.prewarm(testDir, ['*.ts']);
|
|
28
|
+
expect(stats.filesLoaded).toBe(2);
|
|
29
|
+
expect(stats.totalBytes).toBeGreaterThan(0);
|
|
30
|
+
expect(stats.durationMs).toBeGreaterThanOrEqual(0);
|
|
31
|
+
expect(fileCache.stats.prewarmed).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('respects default ignore patterns (skips node_modules)', async () => {
|
|
35
|
+
mkdirSync(join(testDir, 'node_modules', 'foo'), { recursive: true });
|
|
36
|
+
writeFileSync(join(testDir, 'node_modules', 'foo', 'x.ts'), 'export {};');
|
|
37
|
+
writeFileSync(join(testDir, 'app.ts'), 'export const app = 1;');
|
|
38
|
+
await fileCache.prewarm(testDir, ['**/*.ts']);
|
|
39
|
+
expect(fileCache.paths().some((p) => p.includes('node_modules'))).toBe(false);
|
|
40
|
+
expect(fileCache.paths().some((p) => p.endsWith('app.ts'))).toBe(true);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('handles multiple patterns and deduplicates', async () => {
|
|
44
|
+
writeFileSync(join(testDir, 'x.ts'), '1');
|
|
45
|
+
const stats = await fileCache.prewarm(testDir, ['*.ts', '**/*.ts']);
|
|
46
|
+
expect(stats.filesLoaded).toBe(1);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe('fileCache.get', () => {
|
|
51
|
+
it('returns content from disk on cache miss and caches it', async () => {
|
|
52
|
+
const path = join(testDir, 'fresh.ts');
|
|
53
|
+
writeFileSync(path, 'fresh content');
|
|
54
|
+
const content = await fileCache.get(path);
|
|
55
|
+
expect(content).toBe('fresh content');
|
|
56
|
+
expect(fileCache.getCached(path)).toBe('fresh content');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('returns cached content on hit', async () => {
|
|
60
|
+
const path = join(testDir, 'a.ts');
|
|
61
|
+
writeFileSync(path, 'first');
|
|
62
|
+
await fileCache.prewarm(testDir, ['*.ts']);
|
|
63
|
+
// Mutate the file on disk; cached read still returns first
|
|
64
|
+
writeFileSync(path, 'second');
|
|
65
|
+
expect(await fileCache.get(path)).toBe('first');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('throws ValidationError when path is a directory', async () => {
|
|
69
|
+
const dirPath = join(testDir, 'dir');
|
|
70
|
+
mkdirSync(dirPath);
|
|
71
|
+
await expect(fileCache.get(dirPath)).rejects.toThrow(ValidationError);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('resolves relative paths against cwd', async () => {
|
|
75
|
+
const abs = join(testDir, 'foo.ts');
|
|
76
|
+
writeFileSync(abs, 'rel');
|
|
77
|
+
process.chdir(testDir);
|
|
78
|
+
const content = await fileCache.get('foo.ts');
|
|
79
|
+
expect(content).toBe('rel');
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe('fileCache.getCached', () => {
|
|
84
|
+
it('returns undefined when file is not in cache', () => {
|
|
85
|
+
expect(fileCache.getCached('/nope/nope.ts')).toBeUndefined();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('returns cached content after prewarm', async () => {
|
|
89
|
+
writeFileSync(join(testDir, 'q.ts'), 'q');
|
|
90
|
+
await fileCache.prewarm(testDir, ['*.ts']);
|
|
91
|
+
expect(fileCache.getCached(join(testDir, 'q.ts'))).toBe('q');
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe('fileCache.exists', () => {
|
|
96
|
+
it('returns true for cached files', async () => {
|
|
97
|
+
writeFileSync(join(testDir, 'e.ts'), 'e');
|
|
98
|
+
await fileCache.prewarm(testDir, ['*.ts']);
|
|
99
|
+
expect(await fileCache.exists(join(testDir, 'e.ts'))).toBe(true);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('returns true for files on disk but not yet cached', async () => {
|
|
103
|
+
writeFileSync(join(testDir, 'd.ts'), 'd');
|
|
104
|
+
expect(await fileCache.exists(join(testDir, 'd.ts'))).toBe(true);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('returns false when file does not exist', async () => {
|
|
108
|
+
expect(await fileCache.exists(join(testDir, 'missing.ts'))).toBe(false);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe('fileCache.clear', () => {
|
|
113
|
+
it('empties the cache and resets prewarmed flag', async () => {
|
|
114
|
+
writeFileSync(join(testDir, 'x.ts'), 'x');
|
|
115
|
+
await fileCache.prewarm(testDir, ['*.ts']);
|
|
116
|
+
expect(fileCache.stats.size).toBeGreaterThan(0);
|
|
117
|
+
fileCache.clear();
|
|
118
|
+
expect(fileCache.stats.size).toBe(0);
|
|
119
|
+
expect(fileCache.stats.prewarmed).toBe(false);
|
|
120
|
+
expect(fileCache.stats.cleared).toBe(true);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
describe('fileCache.paths', () => {
|
|
125
|
+
it('returns sorted absolute paths', async () => {
|
|
126
|
+
writeFileSync(join(testDir, 'b.ts'), '');
|
|
127
|
+
writeFileSync(join(testDir, 'a.ts'), '');
|
|
128
|
+
await fileCache.prewarm(testDir, ['*.ts']);
|
|
129
|
+
const paths = fileCache.paths();
|
|
130
|
+
expect(paths.length).toBe(2);
|
|
131
|
+
expect([...paths].sort()).toEqual(paths);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
describe('DEFAULT_PREWARM_PATTERNS', () => {
|
|
136
|
+
it('includes the major source extensions', () => {
|
|
137
|
+
expect(DEFAULT_PREWARM_PATTERNS).toContain('**/*.ts');
|
|
138
|
+
expect(DEFAULT_PREWARM_PATTERNS).toContain('**/*.tsx');
|
|
139
|
+
expect(DEFAULT_PREWARM_PATTERNS).toContain('**/*.js');
|
|
140
|
+
expect(DEFAULT_PREWARM_PATTERNS).toContain('**/*.json');
|
|
141
|
+
});
|
|
142
|
+
});
|