chore: 优化Husky提交钩子

This commit is contained in:
sunlei 2026-06-05 08:53:31 +08:00
parent 6b651fc612
commit 08847dcf76
3 changed files with 113 additions and 1 deletions

View File

@ -1 +1 @@
pnpm run verify:commit node scripts/husky-fast-check.mjs

View File

@ -10,6 +10,7 @@
"lint": "pnpm run typecheck", "lint": "pnpm run typecheck",
"prepare": "husky", "prepare": "husky",
"typecheck": "pnpm -r --sort run typecheck", "typecheck": "pnpm -r --sort run typecheck",
"verify:staged": "node scripts/husky-fast-check.mjs",
"verify:commit": "pnpm run lint && pnpm run build" "verify:commit": "pnpm run lint && pnpm run build"
}, },
"devDependencies": { "devDependencies": {

View File

@ -0,0 +1,111 @@
import { spawnSync } from 'node:child_process';
import { existsSync } from 'node:fs';
const FULL_CHECK_FILES = new Set([
'package.json',
'pnpm-lock.yaml',
'pnpm-workspace.yaml',
'tsconfig.base.json',
'tsconfig.json',
]);
const WORKSPACES = [
{
filter: '@kt/openapi-parser',
prefix: 'packages/openapi-parser/',
},
{
filter: '@kt/knife4j-vue3-ui',
prefix: 'packages/knife4j-vue3-ui/',
},
{
filter: '@kwitsukasa/knife4j-swagger-vue3',
prefix: 'packages/nestjs-knife4j/',
},
{
filter: '@kt/knife4j-swagger-vue3-playground',
prefix: 'apps/playground/',
},
];
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)
.filter((file) => existsSync(file));
}
const stagedFiles = getStagedFiles();
if (stagedFiles.length === 0) {
console.info('[husky] no staged files.');
process.exit(0);
}
if (stagedFiles.some((file) => FULL_CHECK_FILES.has(file))) {
run(getPnpmCommand(), ['-r', '--sort', 'run', 'typecheck']);
process.exit(0);
}
const affectedFilters = new Set();
for (const file of stagedFiles) {
for (const workspace of WORKSPACES) {
if (file.startsWith(workspace.prefix)) {
affectedFilters.add(workspace.filter);
}
}
}
if (affectedFilters.size === 0) {
console.info('[husky] no staged workspace files need typecheck.');
process.exit(0);
}
for (const filter of affectedFilters) {
run(getPnpmCommand(), ['--filter', filter, 'run', 'typecheck']);
}