pr-checkmate 3.0.3 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{cli.js → cjs/cli.js} +30 -30
- package/dist/{config → cjs/config}/index.d.ts +2 -2
- package/dist/{config → cjs/config}/index.js +8 -7
- package/dist/{config → cjs/config}/loader.d.ts +1 -1
- package/dist/{config → cjs/config}/loader.js +8 -8
- package/dist/{core → cjs/core}/checks/dependencies/banned-imports.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/dependencies/banned-imports.js +10 -10
- package/dist/{core → cjs/core}/checks/dependencies/circular-deps.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/dependencies/circular-deps.js +27 -27
- package/dist/{core → cjs/core}/checks/dependencies/dependency-check.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/dependencies/dependency-check.js +17 -17
- package/dist/{core → cjs/core}/checks/dependencies/grype-scan.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/dependencies/grype-scan.js +18 -18
- package/dist/{core → cjs/core}/checks/dependencies/license-check.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/dependencies/license-check.js +12 -12
- package/dist/{core → cjs/core}/checks/dependencies/npm-audit.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/dependencies/npm-audit.js +14 -14
- package/dist/{core → cjs/core}/checks/dependencies/outdated-deps.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/dependencies/outdated-deps.js +14 -14
- package/dist/{core → cjs/core}/checks/dependencies/vuln-scan.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/dependencies/vuln-scan.js +14 -14
- package/dist/{core → cjs/core}/checks/findings.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/findings.js +16 -16
- package/dist/{core → cjs/core}/checks/git/custom-rules.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/git/custom-rules.js +19 -19
- package/dist/{core → cjs/core}/checks/git/diff-smell.d.ts +2 -2
- package/dist/{core → cjs/core}/checks/git/diff-smell.js +13 -13
- package/dist/{core → cjs/core}/checks/git/large-files.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/git/large-files.js +15 -15
- package/dist/{core → cjs/core}/checks/git/leftover-debug.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/git/leftover-debug.js +13 -13
- package/dist/{core → cjs/core}/checks/git/lockfile-drift.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/git/lockfile-drift.js +12 -12
- package/dist/{core → cjs/core}/checks/git/merge-conflict.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/git/merge-conflict.js +15 -15
- package/dist/{core → cjs/core}/checks/git/missing-tests.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/git/missing-tests.js +15 -15
- package/dist/{core → cjs/core}/checks/git/todo-fixme.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/git/todo-fixme.js +11 -11
- package/dist/{core → cjs/core}/checks/languages/cpp-format.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/languages/cpp-format.js +18 -18
- package/dist/{core → cjs/core}/checks/languages/external-checks.d.ts +9 -9
- package/dist/{core → cjs/core}/checks/languages/external-checks.js +10 -10
- package/dist/{core → cjs/core}/checks/languages/external-runner.d.ts +2 -2
- package/dist/{core → cjs/core}/checks/languages/external-runner.js +21 -21
- package/dist/{core → cjs/core}/checks/languages/go-format.d.ts +1 -1
- package/dist/cjs/core/checks/languages/go-format.js +202 -0
- package/dist/cjs/core/checks/languages/lint.d.ts +2 -0
- package/dist/{core → cjs/core}/checks/languages/lint.js +21 -21
- package/dist/{core → cjs/core}/checks/languages/prettier.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/languages/prettier.js +18 -18
- package/dist/{core → cjs/core}/checks/languages/python-format.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/languages/python-format.js +14 -14
- package/dist/{core → cjs/core}/checks/languages/python-lint.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/languages/python-lint.js +13 -13
- package/dist/{core → cjs/core}/checks/languages/python-typecheck.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/languages/python-typecheck.js +29 -29
- package/dist/{core → cjs/core}/checks/languages/typecheck.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/languages/typecheck.js +13 -13
- package/dist/{core → cjs/core}/checks/pr/commitlint.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/pr/commitlint.js +12 -12
- package/dist/{core → cjs/core}/checks/pr/pr-body.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/pr/pr-body.js +8 -8
- package/dist/{core → cjs/core}/checks/pr/pr-size-check.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/pr/pr-size-check.js +10 -10
- package/dist/{core → cjs/core}/checks/pr/pr-title-lint.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/pr/pr-title-lint.js +8 -8
- package/dist/{core → cjs/core}/checks/quality/case-collision.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/quality/case-collision.js +7 -7
- package/dist/{core → cjs/core}/checks/quality/config-validation.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/quality/config-validation.js +9 -9
- package/dist/{core → cjs/core}/checks/quality/coverage.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/quality/coverage.js +4 -4
- package/dist/{core → cjs/core}/checks/quality/dead-code.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/quality/dead-code.js +23 -23
- package/dist/{core → cjs/core}/checks/quality/duplicate-check.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/quality/duplicate-check.js +22 -22
- package/dist/{core → cjs/core}/checks/quality/license-header.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/quality/license-header.js +16 -16
- package/dist/{core → cjs/core}/checks/quality/markdown-lint.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/quality/markdown-lint.js +17 -17
- package/dist/{core → cjs/core}/checks/quality/package-size.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/quality/package-size.js +12 -12
- package/dist/{core → cjs/core}/checks/quality/spellcheck.d.ts +2 -2
- package/dist/{core → cjs/core}/checks/quality/spellcheck.js +18 -18
- package/dist/{core → cjs/core}/checks/quality/symlinks.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/quality/symlinks.js +8 -8
- package/dist/{core → cjs/core}/checks/quality/yaml-lint.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/quality/yaml-lint.js +12 -12
- package/dist/{core → cjs/core}/checks/security/diff-security.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/security/diff-security.js +15 -15
- package/dist/{core → cjs/core}/checks/security/dockerfile-security.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/security/dockerfile-security.js +16 -16
- package/dist/{core → cjs/core}/checks/security/migration-safety.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/security/migration-safety.js +17 -17
- package/dist/{core → cjs/core}/checks/security/security.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/security/security.js +21 -21
- package/dist/{core → cjs/core}/checks/security/sensitive-file-guard.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/security/sensitive-file-guard.js +14 -14
- package/dist/{core → cjs/core}/checks/security/workflow-security.d.ts +2 -2
- package/dist/{core → cjs/core}/checks/security/workflow-security.js +14 -14
- package/dist/{core → cjs/core}/checks/tool-install.d.ts +1 -1
- package/dist/{core → cjs/core}/checks/tool-install.js +2 -2
- package/dist/{core → cjs/core}/context.d.ts +1 -1
- package/dist/{core → cjs/core}/context.js +16 -16
- package/dist/cjs/core/index.d.ts +4 -0
- package/dist/{core → cjs/core}/index.js +7 -7
- package/dist/{core → cjs/core}/install/cache.js +2 -2
- package/dist/{core → cjs/core}/install/doctor.d.ts +4 -4
- package/dist/{core → cjs/core}/install/doctor.js +34 -34
- package/dist/{core → cjs/core}/install/ensure.d.ts +2 -2
- package/dist/{core → cjs/core}/install/ensure.js +15 -14
- package/dist/{core → cjs/core}/install/lock.js +4 -4
- package/dist/{core → cjs/core}/install/prepare.d.ts +4 -4
- package/dist/{core → cjs/core}/install/prepare.js +13 -13
- package/dist/{core → cjs/core}/install/profiles.d.ts +2 -2
- package/dist/{core → cjs/core}/install/reuse.d.ts +1 -1
- package/dist/{core → cjs/core}/install/reuse.js +4 -4
- package/dist/{core → cjs/core}/registry.d.ts +1 -1
- package/dist/cjs/core/registry.js +112 -0
- package/dist/{core → cjs/core}/reporters.d.ts +1 -1
- package/dist/{core → cjs/core}/reporters.js +28 -28
- package/dist/{core → cjs/core}/run-checks.d.ts +2 -2
- package/dist/{core → cjs/core}/run-checks.js +31 -31
- package/dist/{core → cjs/core}/targets.d.ts +1 -1
- package/dist/{core → cjs/core}/targets.js +20 -20
- package/dist/{core → cjs/core}/types.d.ts +3 -3
- package/dist/cjs/index.d.ts +12 -0
- package/dist/{index.js → cjs/index.js} +18 -18
- package/dist/{init.js → cjs/init.js} +68 -56
- package/dist/{interfaces → cjs/interfaces}/index.d.ts +3 -3
- package/dist/cjs/package.json +1 -0
- package/dist/{scripts → cjs/scripts}/copy-configs.js +22 -7
- package/dist/{scripts → cjs/scripts}/generate-install-manifests.js +2 -2
- package/dist/{scripts → cjs/scripts}/publish-github.js +4 -4
- package/dist/{utils → cjs/utils}/detect-language.js +12 -12
- package/dist/cjs/utils/execa.js +46 -0
- package/dist/{utils → cjs/utils}/git.js +2 -2
- package/dist/{utils → cjs/utils}/http.js +2 -2
- package/dist/cjs/utils/index.d.ts +15 -0
- package/dist/{utils → cjs/utils}/index.js +13 -13
- package/dist/{utils → cjs/utils}/own-deps.d.ts +2 -0
- package/dist/{utils → cjs/utils}/own-deps.js +1 -0
- package/dist/{utils → cjs/utils}/package-version.js +2 -1
- package/dist/{utils → cjs/utils}/resolve-bin.js +2 -1
- package/dist/{utils → cjs/utils}/update-notifier.js +4 -4
- package/dist/esm/cli.d.ts +2 -0
- package/dist/esm/cli.js +137 -0
- package/dist/esm/config/constants.d.ts +153 -0
- package/dist/esm/config/constants.js +360 -0
- package/dist/esm/config/index.d.ts +40 -0
- package/dist/esm/config/index.js +60 -0
- package/dist/esm/config/loader.d.ts +6 -0
- package/dist/esm/config/loader.js +191 -0
- package/dist/esm/config/pr-checkmate-workflow-docker.yml +79 -0
- package/dist/esm/config/pr-checkmate-workflow.yml +92 -0
- package/dist/esm/core/checks/dependencies/banned-imports.d.ts +2 -0
- package/dist/esm/core/checks/dependencies/banned-imports.js +70 -0
- package/dist/esm/core/checks/dependencies/circular-deps.d.ts +2 -0
- package/dist/esm/core/checks/dependencies/circular-deps.js +155 -0
- package/dist/esm/core/checks/dependencies/dependency-check.d.ts +43 -0
- package/dist/esm/core/checks/dependencies/dependency-check.js +174 -0
- package/dist/esm/core/checks/dependencies/grype-scan.d.ts +22 -0
- package/dist/esm/core/checks/dependencies/grype-scan.js +112 -0
- package/dist/esm/core/checks/dependencies/license-check.d.ts +2 -0
- package/dist/esm/core/checks/dependencies/license-check.js +61 -0
- package/dist/esm/core/checks/dependencies/npm-audit.d.ts +6 -0
- package/dist/esm/core/checks/dependencies/npm-audit.js +80 -0
- package/dist/esm/core/checks/dependencies/outdated-deps.d.ts +2 -0
- package/dist/esm/core/checks/dependencies/outdated-deps.js +66 -0
- package/dist/esm/core/checks/dependencies/vuln-scan.d.ts +2 -0
- package/dist/esm/core/checks/dependencies/vuln-scan.js +54 -0
- package/dist/esm/core/checks/findings.d.ts +299 -0
- package/dist/esm/core/checks/findings.js +701 -0
- package/dist/esm/core/checks/git/custom-rules.d.ts +2 -0
- package/dist/esm/core/checks/git/custom-rules.js +106 -0
- package/dist/esm/core/checks/git/diff-smell.d.ts +19 -0
- package/dist/esm/core/checks/git/diff-smell.js +69 -0
- package/dist/esm/core/checks/git/large-files.d.ts +2 -0
- package/dist/esm/core/checks/git/large-files.js +112 -0
- package/dist/esm/core/checks/git/leftover-debug.d.ts +2 -0
- package/dist/esm/core/checks/git/leftover-debug.js +89 -0
- package/dist/esm/core/checks/git/lockfile-drift.d.ts +2 -0
- package/dist/esm/core/checks/git/lockfile-drift.js +114 -0
- package/dist/esm/core/checks/git/merge-conflict.d.ts +2 -0
- package/dist/esm/core/checks/git/merge-conflict.js +117 -0
- package/dist/esm/core/checks/git/missing-tests.d.ts +2 -0
- package/dist/esm/core/checks/git/missing-tests.js +105 -0
- package/dist/esm/core/checks/git/todo-fixme.d.ts +7 -0
- package/dist/esm/core/checks/git/todo-fixme.js +80 -0
- package/dist/esm/core/checks/languages/cpp-format.d.ts +7 -0
- package/dist/esm/core/checks/languages/cpp-format.js +91 -0
- package/dist/esm/core/checks/languages/external-checks.d.ts +77 -0
- package/dist/esm/core/checks/languages/external-checks.js +197 -0
- package/dist/esm/core/checks/languages/external-runner.d.ts +119 -0
- package/dist/esm/core/checks/languages/external-runner.js +138 -0
- package/dist/esm/core/checks/languages/go-format.d.ts +8 -0
- package/dist/{core → esm/core}/checks/languages/go-format.js +29 -35
- package/dist/esm/core/checks/languages/lint.d.ts +2 -0
- package/dist/esm/core/checks/languages/lint.js +92 -0
- package/dist/esm/core/checks/languages/prettier.d.ts +2 -0
- package/dist/esm/core/checks/languages/prettier.js +85 -0
- package/dist/esm/core/checks/languages/python-format.d.ts +7 -0
- package/dist/esm/core/checks/languages/python-format.js +61 -0
- package/dist/esm/core/checks/languages/python-lint.d.ts +9 -0
- package/dist/esm/core/checks/languages/python-lint.js +55 -0
- package/dist/esm/core/checks/languages/python-typecheck.d.ts +14 -0
- package/dist/esm/core/checks/languages/python-typecheck.js +184 -0
- package/dist/esm/core/checks/languages/ruff-shared.d.ts +10 -0
- package/dist/esm/core/checks/languages/ruff-shared.js +35 -0
- package/dist/esm/core/checks/languages/typecheck.d.ts +2 -0
- package/dist/esm/core/checks/languages/typecheck.js +61 -0
- package/dist/esm/core/checks/pr/commitlint.d.ts +2 -0
- package/dist/esm/core/checks/pr/commitlint.js +102 -0
- package/dist/esm/core/checks/pr/pr-body.d.ts +2 -0
- package/dist/esm/core/checks/pr/pr-body.js +43 -0
- package/dist/esm/core/checks/pr/pr-size-check.d.ts +2 -0
- package/dist/esm/core/checks/pr/pr-size-check.js +42 -0
- package/dist/esm/core/checks/pr/pr-title-lint.d.ts +2 -0
- package/dist/esm/core/checks/pr/pr-title-lint.js +31 -0
- package/dist/esm/core/checks/quality/case-collision.d.ts +8 -0
- package/dist/esm/core/checks/quality/case-collision.js +39 -0
- package/dist/esm/core/checks/quality/config-validation.d.ts +11 -0
- package/dist/esm/core/checks/quality/config-validation.js +188 -0
- package/dist/esm/core/checks/quality/coverage.d.ts +2 -0
- package/dist/esm/core/checks/quality/coverage.js +62 -0
- package/dist/esm/core/checks/quality/dead-code.d.ts +2 -0
- package/dist/esm/core/checks/quality/dead-code.js +124 -0
- package/dist/esm/core/checks/quality/duplicate-check.d.ts +2 -0
- package/dist/esm/core/checks/quality/duplicate-check.js +141 -0
- package/dist/esm/core/checks/quality/license-header.d.ts +7 -0
- package/dist/esm/core/checks/quality/license-header.js +81 -0
- package/dist/esm/core/checks/quality/markdown-lint.d.ts +2 -0
- package/dist/esm/core/checks/quality/markdown-lint.js +104 -0
- package/dist/esm/core/checks/quality/package-size.d.ts +36 -0
- package/dist/esm/core/checks/quality/package-size.js +196 -0
- package/dist/esm/core/checks/quality/spellcheck.d.ts +77 -0
- package/dist/esm/core/checks/quality/spellcheck.js +296 -0
- package/dist/esm/core/checks/quality/symlinks.d.ts +16 -0
- package/dist/esm/core/checks/quality/symlinks.js +57 -0
- package/dist/esm/core/checks/quality/yaml-lint.d.ts +20 -0
- package/dist/esm/core/checks/quality/yaml-lint.js +116 -0
- package/dist/esm/core/checks/security/diff-security.d.ts +2 -0
- package/dist/esm/core/checks/security/diff-security.js +354 -0
- package/dist/esm/core/checks/security/dockerfile-security.d.ts +2 -0
- package/dist/esm/core/checks/security/dockerfile-security.js +98 -0
- package/dist/esm/core/checks/security/migration-safety.d.ts +2 -0
- package/dist/esm/core/checks/security/migration-safety.js +137 -0
- package/dist/esm/core/checks/security/security.d.ts +63 -0
- package/dist/esm/core/checks/security/security.js +201 -0
- package/dist/esm/core/checks/security/sensitive-file-guard.d.ts +2 -0
- package/dist/esm/core/checks/security/sensitive-file-guard.js +160 -0
- package/dist/esm/core/checks/security/workflow-security.d.ts +12 -0
- package/dist/esm/core/checks/security/workflow-security.js +100 -0
- package/dist/esm/core/checks/tool-install.d.ts +102 -0
- package/dist/esm/core/checks/tool-install.js +66 -0
- package/dist/esm/core/commands.d.ts +27 -0
- package/dist/esm/core/commands.js +89 -0
- package/dist/esm/core/context.d.ts +62 -0
- package/dist/esm/core/context.js +241 -0
- package/dist/esm/core/index.d.ts +4 -0
- package/dist/esm/core/index.js +4 -0
- package/dist/esm/core/install/cache.d.ts +58 -0
- package/dist/esm/core/install/cache.js +142 -0
- package/dist/esm/core/install/doctor.d.ts +35 -0
- package/dist/esm/core/install/doctor.js +164 -0
- package/dist/esm/core/install/ensure.d.ts +77 -0
- package/dist/esm/core/install/ensure.js +269 -0
- package/dist/esm/core/install/lock.d.ts +34 -0
- package/dist/esm/core/install/lock.js +92 -0
- package/dist/esm/core/install/merge.d.ts +47 -0
- package/dist/esm/core/install/merge.js +85 -0
- package/dist/esm/core/install/prepare.d.ts +76 -0
- package/dist/esm/core/install/prepare.js +142 -0
- package/dist/esm/core/install/profiles.d.ts +78 -0
- package/dist/esm/core/install/profiles.js +192 -0
- package/dist/esm/core/install/reuse.d.ts +41 -0
- package/dist/esm/core/install/reuse.js +100 -0
- package/dist/esm/core/registry.d.ts +6 -0
- package/dist/esm/core/registry.js +109 -0
- package/dist/esm/core/reporters.d.ts +18 -0
- package/dist/esm/core/reporters.js +266 -0
- package/dist/esm/core/run-checks.d.ts +33 -0
- package/dist/esm/core/run-checks.js +293 -0
- package/dist/esm/core/targets.d.ts +140 -0
- package/dist/esm/core/targets.js +213 -0
- package/dist/esm/core/types.d.ts +195 -0
- package/dist/esm/core/types.js +38 -0
- package/dist/esm/index.d.ts +12 -0
- package/dist/esm/index.js +15 -0
- package/dist/esm/init.d.ts +38 -0
- package/dist/esm/init.js +421 -0
- package/dist/esm/interfaces/index.d.ts +432 -0
- package/dist/esm/interfaces/index.js +2 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/scripts/copy-configs.d.ts +1 -0
- package/dist/esm/scripts/copy-configs.js +64 -0
- package/dist/esm/scripts/generate-install-manifests.d.ts +39 -0
- package/dist/esm/scripts/generate-install-manifests.js +115 -0
- package/dist/esm/scripts/publish-github.d.ts +1 -0
- package/dist/esm/scripts/publish-github.js +45 -0
- package/dist/esm/utils/ci.d.ts +11 -0
- package/dist/esm/utils/ci.js +40 -0
- package/dist/esm/utils/detect-language.d.ts +48 -0
- package/dist/esm/utils/detect-language.js +234 -0
- package/dist/esm/utils/direct-deps.d.ts +21 -0
- package/dist/esm/utils/direct-deps.js +220 -0
- package/dist/esm/utils/execa.d.ts +22 -0
- package/dist/{utils → esm/utils}/execa.js +1 -4
- package/dist/esm/utils/git.d.ts +14 -0
- package/dist/esm/utils/git.js +21 -0
- package/dist/esm/utils/glob.d.ts +24 -0
- package/dist/esm/utils/glob.js +40 -0
- package/dist/esm/utils/http.d.ts +59 -0
- package/dist/esm/utils/http.js +115 -0
- package/dist/esm/utils/index.d.ts +15 -0
- package/dist/esm/utils/index.js +26 -0
- package/dist/esm/utils/logger.d.ts +65 -0
- package/dist/esm/utils/logger.js +157 -0
- package/dist/esm/utils/own-deps.d.ts +16 -0
- package/dist/esm/utils/own-deps.js +107 -0
- package/dist/esm/utils/package-version.d.ts +4 -0
- package/dist/esm/utils/package-version.js +38 -0
- package/dist/esm/utils/pool.d.ts +49 -0
- package/dist/esm/utils/pool.js +113 -0
- package/dist/esm/utils/resolve-bin.d.ts +67 -0
- package/dist/esm/utils/resolve-bin.js +156 -0
- package/dist/esm/utils/result-collector.d.ts +33 -0
- package/dist/esm/utils/result-collector.js +44 -0
- package/dist/esm/utils/update-notifier.d.ts +19 -0
- package/dist/esm/utils/update-notifier.js +108 -0
- package/install-manifests/core/package-lock.json +4 -4
- package/install-manifests/core/package.json +1 -1
- package/install-manifests/cpp/package-lock.json +4 -4
- package/install-manifests/cpp/package.json +1 -1
- package/package.json +16 -14
- package/dist/core/checks/languages/lint.d.ts +0 -2
- package/dist/core/index.d.ts +0 -4
- package/dist/core/registry.js +0 -112
- package/dist/index.d.ts +0 -12
- package/dist/utils/index.d.ts +0 -15
- /package/dist/{cli.d.ts → cjs/cli.d.ts} +0 -0
- /package/dist/{config → cjs/config}/constants.d.ts +0 -0
- /package/dist/{config → cjs/config}/constants.js +0 -0
- /package/dist/{config → cjs/config}/pr-checkmate-workflow-docker.yml +0 -0
- /package/dist/{config → cjs/config}/pr-checkmate-workflow.yml +0 -0
- /package/dist/{core → cjs/core}/checks/languages/ruff-shared.d.ts +0 -0
- /package/dist/{core → cjs/core}/checks/languages/ruff-shared.js +0 -0
- /package/dist/{core → cjs/core}/commands.d.ts +0 -0
- /package/dist/{core → cjs/core}/commands.js +0 -0
- /package/dist/{core → cjs/core}/install/cache.d.ts +0 -0
- /package/dist/{core → cjs/core}/install/lock.d.ts +0 -0
- /package/dist/{core → cjs/core}/install/merge.d.ts +0 -0
- /package/dist/{core → cjs/core}/install/merge.js +0 -0
- /package/dist/{core → cjs/core}/install/profiles.js +0 -0
- /package/dist/{core → cjs/core}/types.js +0 -0
- /package/dist/{init.d.ts → cjs/init.d.ts} +0 -0
- /package/dist/{interfaces → cjs/interfaces}/index.js +0 -0
- /package/dist/{scripts → cjs/scripts}/copy-configs.d.ts +0 -0
- /package/dist/{scripts → cjs/scripts}/generate-install-manifests.d.ts +0 -0
- /package/dist/{scripts → cjs/scripts}/publish-github.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/ci.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/ci.js +0 -0
- /package/dist/{utils → cjs/utils}/detect-language.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/direct-deps.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/direct-deps.js +0 -0
- /package/dist/{utils → cjs/utils}/execa.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/git.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/glob.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/glob.js +0 -0
- /package/dist/{utils → cjs/utils}/http.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/logger.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/logger.js +0 -0
- /package/dist/{utils → cjs/utils}/package-version.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/pool.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/pool.js +0 -0
- /package/dist/{utils → cjs/utils}/resolve-bin.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/result-collector.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/result-collector.js +0 -0
- /package/dist/{utils → cjs/utils}/update-notifier.d.ts +0 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { getPackageConfigPath, hasLocalConfig, IGNORE_PATTERNS, getSourcePaths, } from '../../../config/index.js';
|
|
4
|
+
import { execa } from '../../../utils/execa.js';
|
|
5
|
+
import { logger, cleanupTempFile, matchesAnyGlob, resolvePackageBin, } from '../../../utils/index.js';
|
|
6
|
+
import { resolveScopedTargetFiles } from '../../targets.js';
|
|
7
|
+
import { pass, warn, skip } from '../../types.js';
|
|
8
|
+
function loadUserCspellConfig(cwd) {
|
|
9
|
+
const configPath = path.join(cwd, 'pr-checkmate.json');
|
|
10
|
+
if (!fs.existsSync(configPath))
|
|
11
|
+
return {};
|
|
12
|
+
try {
|
|
13
|
+
return JSON.parse(fs.readFileSync(configPath, 'utf-8')).cspell || {};
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
logger.warn(`[Spellcheck]: ⚠️ Failed to read cspell config: ${err}`);
|
|
17
|
+
return {};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Anchors an ignore glob to the repository root.
|
|
22
|
+
*
|
|
23
|
+
* cspell matches `ignorePaths` against each file's ABSOLUTE path, so an unanchored
|
|
24
|
+
* `**\/build/**` also matches every ancestor directory of the workspace. On Bitbucket
|
|
25
|
+
* Pipelines the clone lives in `/opt/atlassian/pipelines/agent/build`, so that one
|
|
26
|
+
* pattern excluded the entire repository and the check silently spellchecked nothing.
|
|
27
|
+
* A leading `/` anchors the pattern to the config's directory (the repo root) while
|
|
28
|
+
* `/**\/dir/**` still matches at any depth INSIDE the repo — verified against cspell 10.
|
|
29
|
+
*
|
|
30
|
+
* Patterns that are already anchored (`/…`) or plainly relative (`dir/**`,
|
|
31
|
+
* `CHANGELOG.md`) are left untouched: they cannot match an ancestor.
|
|
32
|
+
*/
|
|
33
|
+
export function anchorIgnoreGlob(pattern) {
|
|
34
|
+
return pattern.startsWith('**/') ? `/${pattern}` : pattern;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Folds the client's `cspell` block from pr-checkmate.json into the bundled
|
|
38
|
+
* defaults. `enabled` is deliberately not carried over — it gates the check
|
|
39
|
+
* itself (see `applies`) and is not a cspell setting.
|
|
40
|
+
*
|
|
41
|
+
* Lists are appended so a client extends the curated vocabulary instead of
|
|
42
|
+
* replacing it; `language` is the one exception and replaces the default, because
|
|
43
|
+
* a client writing `"en"` means exactly that and appending would be meaningless.
|
|
44
|
+
*/
|
|
45
|
+
export function mergeCspellConfig(defaultConfig, userConfig) {
|
|
46
|
+
const dictionaries = [...(defaultConfig.dictionaries ?? []), ...(userConfig.dictionaries ?? [])];
|
|
47
|
+
return {
|
|
48
|
+
...defaultConfig,
|
|
49
|
+
language: userConfig.language || defaultConfig.language,
|
|
50
|
+
// Appended, so a client can point at a dictionary they installed themselves
|
|
51
|
+
// without losing the bundled ones. Anything that does not resolve is dropped
|
|
52
|
+
// later rather than passed to cspell, which would abort the whole run.
|
|
53
|
+
import: [...(defaultConfig.import ?? []), ...(userConfig.import ?? [])],
|
|
54
|
+
words: [...defaultConfig.words, ...(userConfig.words || [])],
|
|
55
|
+
// Client globs are anchored too — a repo's own pattern is meant to be relative
|
|
56
|
+
// to that repo, never to whatever directories sit above the checkout.
|
|
57
|
+
ignorePaths: [...defaultConfig.ignorePaths, ...(userConfig.ignorePaths || [])].map(anchorIgnoreGlob),
|
|
58
|
+
ignoreRegExpList: [...defaultConfig.ignoreRegExpList, ...(userConfig.ignoreRegExpList || [])],
|
|
59
|
+
// The bundled dictionaries arrive through `import`, so there is nothing to
|
|
60
|
+
// override here. cspell ignores names it cannot resolve, so a client typo
|
|
61
|
+
// costs coverage but never fails the run.
|
|
62
|
+
...(dictionaries.length > 0 ? { dictionaries } : {}),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Non-English dictionaries the package no longer installs, and the language code
|
|
67
|
+
* each one serves.
|
|
68
|
+
*
|
|
69
|
+
* They used to be hard dependencies and cost every client ~9 MB on every install,
|
|
70
|
+
* to spellcheck languages almost none of them write. They are still *supported*:
|
|
71
|
+
* {@link availableDictionaries} enables one the moment it resolves, so a client
|
|
72
|
+
* who wants Russian back runs `npm i -D @cspell/dict-ru_ru` and edits no config.
|
|
73
|
+
*
|
|
74
|
+
* They are added at runtime rather than left in the bundled `cspell.json`,
|
|
75
|
+
* because a config that references an uninstalled dictionary is not a degraded
|
|
76
|
+
* config — see {@link resolveImports} — it is a broken one.
|
|
77
|
+
*/
|
|
78
|
+
const OPTIONAL_DICTIONARIES = [
|
|
79
|
+
{ pkg: '@cspell/dict-ru_ru/cspell-ext.json', lang: 'ru', script: 'Cyrillic' },
|
|
80
|
+
{ pkg: '@cspell/dict-uk-ua/cspell-ext.json', lang: 'uk', script: 'Cyrillic' },
|
|
81
|
+
{ pkg: '@cspell/dict-he/cspell-ext.json', lang: 'he', script: 'Hebrew' },
|
|
82
|
+
{ pkg: '@cspell/dict-fr-fr/cspell-ext.json', lang: 'fr' },
|
|
83
|
+
{ pkg: '@cspell/dict-es-es/cspell-ext.json', lang: 'es' },
|
|
84
|
+
];
|
|
85
|
+
/**
|
|
86
|
+
* The optional dictionaries this installation actually has — and what to do
|
|
87
|
+
* about the ones it does not.
|
|
88
|
+
*
|
|
89
|
+
* Dropping a dictionary must not turn into a flood of warnings: a repository
|
|
90
|
+
* with Russian comments would report every Russian word as a misspelling, which
|
|
91
|
+
* is worse than the ~9 MB the dictionaries cost. So for the languages written in
|
|
92
|
+
* a script of their own, absence suppresses that script instead: cspell cannot
|
|
93
|
+
* judge those words, and reporting words it cannot judge is noise, not coverage.
|
|
94
|
+
*
|
|
95
|
+
* Latin-script languages (French, Spanish) have no such escape — their words are
|
|
96
|
+
* indistinguishable from misspelled English — so their absence is only logged,
|
|
97
|
+
* with the command that restores them.
|
|
98
|
+
*
|
|
99
|
+
* @returns imports and language codes to enable, ignore patterns for scripts left
|
|
100
|
+
* without a dictionary, and the packages a client may want to install.
|
|
101
|
+
*/
|
|
102
|
+
export function availableDictionaries(resolve = require.resolve) {
|
|
103
|
+
const imports = [];
|
|
104
|
+
const languages = [];
|
|
105
|
+
const scripts = new Set();
|
|
106
|
+
const absent = [];
|
|
107
|
+
for (const { pkg, lang, script } of OPTIONAL_DICTIONARIES) {
|
|
108
|
+
try {
|
|
109
|
+
imports.push(resolve(pkg));
|
|
110
|
+
languages.push(lang);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
absent.push(pkg.split('/cspell-ext.json')[0]);
|
|
114
|
+
if (script)
|
|
115
|
+
scripts.add(script);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// A script is only suppressed when NO dictionary covering it survived: with
|
|
119
|
+
// Russian installed and Ukrainian missing, Cyrillic is still checked.
|
|
120
|
+
const covered = new Set(OPTIONAL_DICTIONARIES.filter(d => d.script && languages.includes(d.lang)).map(d => d.script));
|
|
121
|
+
return {
|
|
122
|
+
imports,
|
|
123
|
+
languages,
|
|
124
|
+
ignoreRegExpList: [...scripts]
|
|
125
|
+
.filter(script => !covered.has(script))
|
|
126
|
+
.map(script => `/\\p{Script=${script}}+/gu`),
|
|
127
|
+
absent,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Turn config imports into absolute paths, dropping the ones that are not installed.
|
|
132
|
+
*
|
|
133
|
+
* An unresolvable `import` is not a soft failure in cspell: it aborts config
|
|
134
|
+
* loading, checks **zero files**, and exits 1 — which this check would then have
|
|
135
|
+
* reported as "spelling issues found", a warning about problems that do not exist
|
|
136
|
+
* on a run that examined nothing. Passing the raw string through and hoping cspell
|
|
137
|
+
* copes is therefore the one thing that must not happen.
|
|
138
|
+
*
|
|
139
|
+
* @returns the imports that resolved, plus the language codes left without a
|
|
140
|
+
* dictionary so the caller can drop them from `language`.
|
|
141
|
+
*/
|
|
142
|
+
export function resolveImports(imports, baseDir, resolve = require.resolve) {
|
|
143
|
+
const resolvedPaths = [];
|
|
144
|
+
const missing = [];
|
|
145
|
+
for (const entry of imports) {
|
|
146
|
+
// A relative path comes from our own bundled config; it ships with the
|
|
147
|
+
// package and is resolved against it, not against the client's cwd.
|
|
148
|
+
if (entry.startsWith('.')) {
|
|
149
|
+
resolvedPaths.push(path.resolve(baseDir, entry));
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
resolvedPaths.push(resolve(entry));
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
missing.push({
|
|
157
|
+
pkg: entry,
|
|
158
|
+
lang: OPTIONAL_DICTIONARIES.find(d => entry.startsWith(d.pkg))?.lang,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return { resolved: resolvedPaths, missing };
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Drop language codes whose dictionary is absent.
|
|
166
|
+
*
|
|
167
|
+
* Leaving `ru` in `language` with no Russian dictionary does not spellcheck
|
|
168
|
+
* Russian — it reports every Russian word as a misspelling. Having no opinion is
|
|
169
|
+
* the honest outcome when the dictionary that would form one is not installed.
|
|
170
|
+
*/
|
|
171
|
+
export function dropMissingLanguages(language, missing) {
|
|
172
|
+
const kept = language
|
|
173
|
+
.split(',')
|
|
174
|
+
.map(code => code.trim())
|
|
175
|
+
.filter(code => code && !missing.includes(code));
|
|
176
|
+
// `en` is the floor: a config with an empty `language` makes cspell fall back
|
|
177
|
+
// to its own default, which is not necessarily what was configured here.
|
|
178
|
+
return kept.length > 0 ? kept.join(',') : 'en';
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Resolve a package id from the repository under review first, then from our own
|
|
182
|
+
* tree.
|
|
183
|
+
*
|
|
184
|
+
* The default `require.resolve` searches from THIS module, which is only the
|
|
185
|
+
* client's tree by accident. Installed as a dependency we sit in their
|
|
186
|
+
* `node_modules` and npm hoists `@cspell/dict-*` above us, so walking up finds
|
|
187
|
+
* it. Run through `npx` we sit in the npx cache and their `node_modules` is not
|
|
188
|
+
* on the path at all — so `npm i -D @cspell/dict-ru_ru`, which this file's own
|
|
189
|
+
* docstring promises is all it takes, did nothing and said nothing (ticket 081).
|
|
190
|
+
*
|
|
191
|
+
* Same policy as tool resolution for binaries: the client's copy first, ours as
|
|
192
|
+
* the fallback.
|
|
193
|
+
*/
|
|
194
|
+
function resolveFrom(cwd) {
|
|
195
|
+
return id => {
|
|
196
|
+
try {
|
|
197
|
+
return require.resolve(id, { paths: [cwd] });
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
return require.resolve(id);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function createTempCspellConfig(cwd) {
|
|
205
|
+
const packageConfigPath = getPackageConfigPath('cspell.json');
|
|
206
|
+
const packageConfigDir = path.dirname(packageConfigPath);
|
|
207
|
+
const defaultConfig = JSON.parse(fs.readFileSync(packageConfigPath, 'utf-8'));
|
|
208
|
+
const userConfig = loadUserCspellConfig(cwd);
|
|
209
|
+
const merged = mergeCspellConfig(defaultConfig, userConfig);
|
|
210
|
+
const resolve = resolveFrom(cwd);
|
|
211
|
+
const { resolved, missing } = resolveImports(merged.import ?? [], packageConfigDir, resolve);
|
|
212
|
+
const available = availableDictionaries(resolve);
|
|
213
|
+
for (const { pkg } of missing) {
|
|
214
|
+
logger.info(`[Spellcheck]: dictionary ${pkg} is not installed and was skipped. Add it with \`npm i -D ${pkg}\`.`);
|
|
215
|
+
}
|
|
216
|
+
if (available.absent.length > 0) {
|
|
217
|
+
// `info`, not `debug`. A client who installed a dictionary and saw no change
|
|
218
|
+
// had nothing to read: the one line that would have explained it was behind a
|
|
219
|
+
// flag. Which dictionaries are in play decides which findings appear, so it
|
|
220
|
+
// belongs in the ordinary log (ticket 081).
|
|
221
|
+
logger.info(`[Spellcheck]: optional dictionaries not installed: ${available.absent.join(', ')}. ` +
|
|
222
|
+
`Install any of them to spellcheck that language (\`npm i -D ${available.absent[0]}\`).`);
|
|
223
|
+
}
|
|
224
|
+
// A language the client asked for whose dictionary is absent is dropped rather
|
|
225
|
+
// than left in place: without the dictionary, "ru" does not spellcheck Russian,
|
|
226
|
+
// it reports every Russian word as a misspelling.
|
|
227
|
+
const requested = dropMissingLanguages(merged.language, OPTIONAL_DICTIONARIES.map(d => d.lang).filter(lang => !available.languages.includes(lang)));
|
|
228
|
+
const mergedConfig = {
|
|
229
|
+
...merged,
|
|
230
|
+
language: [...new Set([...requested.split(','), ...available.languages])].join(','),
|
|
231
|
+
import: [...resolved, ...available.imports],
|
|
232
|
+
ignoreRegExpList: [...merged.ignoreRegExpList, ...available.ignoreRegExpList],
|
|
233
|
+
};
|
|
234
|
+
const tempConfigPath = path.join(cwd, '.cspell.temp.json');
|
|
235
|
+
fs.writeFileSync(tempConfigPath, JSON.stringify(mergedConfig, null, 2));
|
|
236
|
+
return tempConfigPath;
|
|
237
|
+
}
|
|
238
|
+
export const spellcheckCheck = {
|
|
239
|
+
name: 'Spellcheck',
|
|
240
|
+
phase: 'informational',
|
|
241
|
+
weight: 'heavy',
|
|
242
|
+
/**
|
|
243
|
+
* Clients turn the check off with `cspell.enabled: false` (or the `spellcheck`
|
|
244
|
+
* alias the config interface uses). The universal `severity: { Spellcheck: "off" }`
|
|
245
|
+
* switch keeps working too — this is the per-check flag every other check exposes.
|
|
246
|
+
*/
|
|
247
|
+
applies(ctx) {
|
|
248
|
+
return ctx.config.cspell?.enabled !== false && ctx.config.spellcheck?.enabled !== false;
|
|
249
|
+
},
|
|
250
|
+
async run(ctx) {
|
|
251
|
+
const targets = await resolveScopedTargetFiles(ctx, ['*.ts', '*.tsx', '*.js', '*.jsx', '*.md', '*.mdx', '*.json'], getSourcePaths(ctx.cwd));
|
|
252
|
+
if (targets === null)
|
|
253
|
+
return skip('git unavailable');
|
|
254
|
+
// Committed build output and test reports are dropped here, in JS, against
|
|
255
|
+
// repo-RELATIVE paths — a client cannot fix a typo in a generated file, so
|
|
256
|
+
// reporting one is noise that buries the real findings. Neither cspell
|
|
257
|
+
// mechanism can do this safely: `--exclude` ignores glob anchoring outright
|
|
258
|
+
// (`--exclude=/**/build/**` still matches an ancestor `build` dir, which on
|
|
259
|
+
// Bitbucket Pipelines is the checkout itself), and `ignorePaths` only reaches
|
|
260
|
+
// repos that have no cspell config of their own. Filtering the list keeps one
|
|
261
|
+
// rule for every repo. `ignoreDirs` already covers plain directory names via
|
|
262
|
+
// `resolveTargetFiles`; this adds the composite globs it cannot express
|
|
263
|
+
// (`**/cypress/videos/**`, `**/jest-html-reporters-*/**`).
|
|
264
|
+
const files = targets.filter(f => !matchesAnyGlob(f, IGNORE_PATTERNS));
|
|
265
|
+
if (files.length === 0)
|
|
266
|
+
return pass('no files to spellcheck');
|
|
267
|
+
const hasLocal = hasLocalConfig(['cspell.json', '.cspell.json', 'cspell.config.json'], ctx.cwd);
|
|
268
|
+
let tempConfigPath = null;
|
|
269
|
+
const cspellBin = resolvePackageBin('cspell', 'bin.mjs');
|
|
270
|
+
// `--no-must-find-files`: cspell exits 1 when it checked nothing, which the
|
|
271
|
+
// exit-code mapping below would report as "spelling issues found" — a warning
|
|
272
|
+
// about problems that do not exist. Every file being excluded is a pass, not a
|
|
273
|
+
// finding.
|
|
274
|
+
const baseArgs = [...files, '--no-progress', '--no-must-find-files'];
|
|
275
|
+
let args;
|
|
276
|
+
if (hasLocal) {
|
|
277
|
+
args = baseArgs;
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
tempConfigPath = createTempCspellConfig(ctx.cwd);
|
|
281
|
+
args = [...baseArgs, '--config', tempConfigPath];
|
|
282
|
+
}
|
|
283
|
+
try {
|
|
284
|
+
const result = await execa(process.execPath, [cspellBin, ...args], {
|
|
285
|
+
cwd: ctx.cwd,
|
|
286
|
+
reject: false,
|
|
287
|
+
stdio: 'inherit',
|
|
288
|
+
});
|
|
289
|
+
return result.exitCode === 0 ? pass() : warn('spelling issues found');
|
|
290
|
+
}
|
|
291
|
+
finally {
|
|
292
|
+
if (tempConfigPath)
|
|
293
|
+
cleanupTempFile(tempConfigPath);
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Check } from '../../types.js';
|
|
2
|
+
/** True when `fullPath` is a symlink whose target does not exist. */
|
|
3
|
+
export declare function isBrokenSymlink(fullPath: string): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* Flags tracked symlinks whose target does not exist. `fs.existsSync` follows a
|
|
6
|
+
* symlink to its target, so it returns `false` for exactly the broken case while
|
|
7
|
+
* the link itself is still a real, tracked file — that's what makes a plain
|
|
8
|
+
* existence check (as used by `resolveTargetFiles`) unusable here and requires
|
|
9
|
+
* the dedicated `isBrokenSymlink` pass over `fs.lstatSync` above.
|
|
10
|
+
*
|
|
11
|
+
* Whole-repo scan (not delta), like Case Collision: a broken link fails a
|
|
12
|
+
* checkout or build regardless of which PR introduced it, so it's worth
|
|
13
|
+
* catching even when this run's diff never touched it. Informational and warns
|
|
14
|
+
* by default — promote to a gate per repo with `symlinks.severity`.
|
|
15
|
+
*/
|
|
16
|
+
export declare const symlinksCheck: Check;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { matchesAnyGlob } from '../../../utils/index.js';
|
|
4
|
+
import { resolveTargets } from '../../targets.js';
|
|
5
|
+
import { pass } from '../../types.js';
|
|
6
|
+
import { severityEmitter } from '../findings.js';
|
|
7
|
+
/** True when `fullPath` is a symlink whose target does not exist. */
|
|
8
|
+
export function isBrokenSymlink(fullPath) {
|
|
9
|
+
let stat;
|
|
10
|
+
try {
|
|
11
|
+
stat = fs.lstatSync(fullPath);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return false; // gone between listing and stat
|
|
15
|
+
}
|
|
16
|
+
return stat.isSymbolicLink() && !fs.existsSync(fullPath);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Flags tracked symlinks whose target does not exist. `fs.existsSync` follows a
|
|
20
|
+
* symlink to its target, so it returns `false` for exactly the broken case while
|
|
21
|
+
* the link itself is still a real, tracked file — that's what makes a plain
|
|
22
|
+
* existence check (as used by `resolveTargetFiles`) unusable here and requires
|
|
23
|
+
* the dedicated `isBrokenSymlink` pass over `fs.lstatSync` above.
|
|
24
|
+
*
|
|
25
|
+
* Whole-repo scan (not delta), like Case Collision: a broken link fails a
|
|
26
|
+
* checkout or build regardless of which PR introduced it, so it's worth
|
|
27
|
+
* catching even when this run's diff never touched it. Informational and warns
|
|
28
|
+
* by default — promote to a gate per repo with `symlinks.severity`.
|
|
29
|
+
*/
|
|
30
|
+
export const symlinksCheck = {
|
|
31
|
+
name: 'Broken Symlinks',
|
|
32
|
+
phase: 'informational',
|
|
33
|
+
applies(ctx) {
|
|
34
|
+
return ctx.config.symlinks?.enabled !== false;
|
|
35
|
+
},
|
|
36
|
+
async run(ctx) {
|
|
37
|
+
const files = await resolveTargets(ctx, ['*'], {
|
|
38
|
+
wholeTree: true,
|
|
39
|
+
onEmpty: { skip: 'no tracked files' },
|
|
40
|
+
});
|
|
41
|
+
if (!Array.isArray(files))
|
|
42
|
+
return files;
|
|
43
|
+
const ignore = ctx.config.symlinks?.ignore ?? [];
|
|
44
|
+
const broken = [];
|
|
45
|
+
for (const file of files) {
|
|
46
|
+
if (ignore.length > 0 && matchesAnyGlob(file, ignore))
|
|
47
|
+
continue;
|
|
48
|
+
if (isBrokenSymlink(path.join(ctx.cwd, file)))
|
|
49
|
+
broken.push(file);
|
|
50
|
+
}
|
|
51
|
+
if (broken.length === 0)
|
|
52
|
+
return pass();
|
|
53
|
+
const sev = severityEmitter(ctx.config.symlinks?.severity, 'warn');
|
|
54
|
+
broken.forEach(f => sev.log(`[Broken Symlinks]: ${sev.icon} ${f} — target does not exist`));
|
|
55
|
+
return sev.emit(`${broken.length} broken symlink(s)`);
|
|
56
|
+
},
|
|
57
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Check } from '../../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* True when a parser problem describes something actually wrong with the file —
|
|
4
|
+
* a syntax error, a duplicate key, a tab used for indentation.
|
|
5
|
+
*/
|
|
6
|
+
export declare function isFileDefect(problem: {
|
|
7
|
+
code?: string;
|
|
8
|
+
}): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Bundled YAML linter (the `yaml` package — no runner dependency, always
|
|
11
|
+
* available like Markdown/Spellcheck). Parses every changed `.yml`/`.yaml` file
|
|
12
|
+
* and reports the parser's own errors and warnings: syntax errors, duplicate map
|
|
13
|
+
* keys, tabs used as indentation, and other structural problems. Multi-document
|
|
14
|
+
* files (`---`-separated) are each parsed. ON by default — runs unless
|
|
15
|
+
* `yamlLint.enabled` is explicitly `false`. Findings are a hard error by default
|
|
16
|
+
* (a YAML problem fails the run); downgrade to advisory with
|
|
17
|
+
* `yamlLint.severity: "warn"`. Clients can exclude paths with `yamlLint.ignore`
|
|
18
|
+
* (glob patterns) in pr-checkmate.json.
|
|
19
|
+
*/
|
|
20
|
+
export declare const yamlLintCheck: Check;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { parseAllDocuments } from 'yaml';
|
|
4
|
+
import { logger, matchesAnyGlob } from '../../../utils/index.js';
|
|
5
|
+
import { resolveTargetFiles } from '../../targets.js';
|
|
6
|
+
import { pass, skip } from '../../types.js';
|
|
7
|
+
import { severityEmitter } from '../findings.js';
|
|
8
|
+
/** First line of a `yaml` error/warning message, stripped of its source excerpt. */
|
|
9
|
+
function shortMessage(message) {
|
|
10
|
+
return message.split('\n')[0].trim();
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Parser problems that are not defects in the file.
|
|
14
|
+
*
|
|
15
|
+
* `TAG_RESOLVE_FAILED` means the parser met an application-specific tag it has no
|
|
16
|
+
* schema for. YAML is explicitly extensible there, so the document is valid and the
|
|
17
|
+
* parser simply is not the application that defines the tag: `!Ref`, `!Sub`,
|
|
18
|
+
* `!GetAtt`, `!Equals` in CloudFormation and SAM templates, `!include` in Home
|
|
19
|
+
* Assistant, `!vault` in Ansible. Reporting those calls a whole ecosystem's valid
|
|
20
|
+
* files broken — one CloudFormation template produced **557 blocking findings** for
|
|
21
|
+
* a client, none of which was a real problem.
|
|
22
|
+
*
|
|
23
|
+
* Matched on the parser's `code`, not on message text, so a wording change upstream
|
|
24
|
+
* cannot silently re-enable it.
|
|
25
|
+
*/
|
|
26
|
+
const NON_DEFECT_CODES = new Set(['TAG_RESOLVE_FAILED']);
|
|
27
|
+
/**
|
|
28
|
+
* True when a parser problem describes something actually wrong with the file —
|
|
29
|
+
* a syntax error, a duplicate key, a tab used for indentation.
|
|
30
|
+
*/
|
|
31
|
+
export function isFileDefect(problem) {
|
|
32
|
+
return problem.code === undefined || !NON_DEFECT_CODES.has(problem.code);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Bundled YAML linter (the `yaml` package — no runner dependency, always
|
|
36
|
+
* available like Markdown/Spellcheck). Parses every changed `.yml`/`.yaml` file
|
|
37
|
+
* and reports the parser's own errors and warnings: syntax errors, duplicate map
|
|
38
|
+
* keys, tabs used as indentation, and other structural problems. Multi-document
|
|
39
|
+
* files (`---`-separated) are each parsed. ON by default — runs unless
|
|
40
|
+
* `yamlLint.enabled` is explicitly `false`. Findings are a hard error by default
|
|
41
|
+
* (a YAML problem fails the run); downgrade to advisory with
|
|
42
|
+
* `yamlLint.severity: "warn"`. Clients can exclude paths with `yamlLint.ignore`
|
|
43
|
+
* (glob patterns) in pr-checkmate.json.
|
|
44
|
+
*/
|
|
45
|
+
export const yamlLintCheck = {
|
|
46
|
+
name: 'YAML Lint',
|
|
47
|
+
phase: 'blocking',
|
|
48
|
+
applies(ctx) {
|
|
49
|
+
return ctx.config.yamlLint?.enabled !== false;
|
|
50
|
+
},
|
|
51
|
+
async run(ctx) {
|
|
52
|
+
// Keep the CI/workflow dirs that are globally ignored: they hold the very
|
|
53
|
+
// YAML (GitHub Actions, GitLab CI, CircleCI) a YAML linter most needs to see.
|
|
54
|
+
const allTargets = await resolveTargetFiles(ctx, ['*.yml', '*.yaml'], {
|
|
55
|
+
keepDirs: ['.github', '.gitlab', '.circleci'],
|
|
56
|
+
});
|
|
57
|
+
if (allTargets === null)
|
|
58
|
+
return skip('git unavailable');
|
|
59
|
+
if (allTargets.length === 0)
|
|
60
|
+
return skip('no YAML files');
|
|
61
|
+
const ignore = ctx.config.yamlLint?.ignore ?? [];
|
|
62
|
+
const targets = ignore.length > 0 ? allTargets.filter(f => !matchesAnyGlob(f, ignore)) : allTargets;
|
|
63
|
+
if (targets.length === 0)
|
|
64
|
+
return skip('all YAML files ignored');
|
|
65
|
+
const issues = [];
|
|
66
|
+
for (const file of targets) {
|
|
67
|
+
let source;
|
|
68
|
+
try {
|
|
69
|
+
source = fs.readFileSync(path.join(ctx.cwd, file), 'utf-8');
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
logger.warn(`[YAML Lint]: ⚠️ Could not read ${file}: ${err}`);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
// parseAllDocuments never throws — it collects problems on each document,
|
|
76
|
+
// so a single malformed file cannot abort the whole check.
|
|
77
|
+
const docs = parseAllDocuments(source, { prettyErrors: true });
|
|
78
|
+
for (const doc of docs) {
|
|
79
|
+
const problems = [
|
|
80
|
+
...doc.errors.map(p => ({ problem: p, blocking: true })),
|
|
81
|
+
...doc.warnings.map(p => ({ problem: p, blocking: false })),
|
|
82
|
+
].filter(({ problem }) => isFileDefect(problem));
|
|
83
|
+
for (const { problem, blocking } of problems) {
|
|
84
|
+
const pos = problem.linePos?.[0];
|
|
85
|
+
issues.push({
|
|
86
|
+
file,
|
|
87
|
+
blocking,
|
|
88
|
+
line: pos?.line,
|
|
89
|
+
col: pos?.col,
|
|
90
|
+
message: shortMessage(problem.message),
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (issues.length === 0)
|
|
96
|
+
return pass();
|
|
97
|
+
// A file that does not parse blocks; a file that parses and merely worries
|
|
98
|
+
// the parser does not. Treating both as blocking is what made this check
|
|
99
|
+
// feel like an obstacle rather than a gate — and a check people switch off
|
|
100
|
+
// protects nobody. `yamlLint.severity` still overrides both at once.
|
|
101
|
+
const configured = ctx.config.yamlLint?.severity;
|
|
102
|
+
const broken = issues.filter(i => i.blocking);
|
|
103
|
+
const questionable = issues.filter(i => !i.blocking);
|
|
104
|
+
const describe = (i) => `${i.file}${i.line ? `:${i.line}${i.col ? `:${i.col}` : ''}` : ''} — ${i.message}`;
|
|
105
|
+
const sev = severityEmitter(configured, broken.length > 0 ? 'error' : 'warn');
|
|
106
|
+
[...broken, ...questionable]
|
|
107
|
+
.slice(0, 10)
|
|
108
|
+
.forEach(i => sev.log(`[YAML Lint]: ${sev.icon} ${describe(i)}`));
|
|
109
|
+
if (issues.length > 10)
|
|
110
|
+
sev.log(`[YAML Lint]: ... and ${issues.length - 10} more`);
|
|
111
|
+
const summary = broken.length > 0 && questionable.length > 0
|
|
112
|
+
? `${broken.length} unparseable, ${questionable.length} questionable YAML issue(s)`
|
|
113
|
+
: `${issues.length} YAML issue(s) found`;
|
|
114
|
+
return sev.emit(summary);
|
|
115
|
+
},
|
|
116
|
+
};
|