diff --git a/.husky/pre-commit b/.husky/pre-commit index 4331a63..66407cd 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -2,4 +2,4 @@ if grep -q '"lint-staged"' package.json; then pnpm exec lint-staged --concurrent false fi -pnpm run verify:commit +node scripts/husky-fast-check.mjs diff --git a/package.json b/package.json index ba709f5..895fc72 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "lint": "eslint .", "prepare": "husky", "typecheck": "vue-tsc --noEmit", + "verify:staged": "node scripts/husky-fast-check.mjs", "verify:commit": "pnpm run lint && pnpm run typecheck", "release": "bumpp --all", "version": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0", diff --git a/scripts/husky-fast-check.mjs b/scripts/husky-fast-check.mjs new file mode 100644 index 0000000..97679a0 --- /dev/null +++ b/scripts/husky-fast-check.mjs @@ -0,0 +1,86 @@ +import { spawnSync } from 'node:child_process' +import { existsSync } from 'node:fs' +import { extname } from 'node:path' + +const CHECK_EXTENSIONS = new Set([ + '.ts', + '.tsx', + '.js', + '.jsx', + '.mjs', + '.cjs', + '.vue', +]) +const CHECK_EXCLUDED_ROOTS = ['dist/', 'node_modules/'] + +function run(command, args) { + const result = spawnSync(command, args, { + shell: process.platform === 'win32' && command === 'pnpm', + stdio: 'inherit', + }) + + if (result.error) { + console.error(result.error.message) + process.exit(1) + } + + if (result.status !== 0) { + process.exit(result.status ?? 1) + } +} + +function output(command, args) { + const result = spawnSync(command, args, { + encoding: 'utf8', + shell: false, + }) + + if (result.error) { + console.error(result.error.message) + process.exit(1) + } + + if (result.status !== 0) { + process.exit(result.status ?? 1) + } + + return result.stdout +} + +function getPnpmCommand() { + return 'pnpm' +} + +function getStagedFiles() { + return output('git', [ + 'diff', + '--cached', + '--name-only', + '--diff-filter=ACMR', + '-z', + ]) + .split('\0') + .map((file) => file.replaceAll('\\', '/')) + .filter(Boolean) +} + +const files = getStagedFiles().filter((file) => { + if (!existsSync(file)) return false + if (CHECK_EXCLUDED_ROOTS.some((root) => file.startsWith(root))) return false + + return CHECK_EXTENSIONS.has(extname(file)) +}) + +if (files.length === 0) { + console.info('[husky] no staged files need eslint.') + process.exit(0) +} + +run(getPnpmCommand(), [ + 'exec', + 'eslint', + '--cache', + '--cache-location', + 'node_modules/.cache/husky-eslint/', + ...files, +])