中文名为钩子,实际常用于代码某些执行阶段触发某些逻辑,如结尾触发检测或测试,使得代码编译正常。
安全防线、质量守卫、审计日志,全部由 Hooks 在“幕后”自动完成
cursor中hooks配置:https://cursor.com/cn/docs/hooks
针对vue3代码:高频用于eslint 运行没问题后再给到执行,可以有效降低AI带来的语法等问题。
文件位置:.cursor/hooks/local-lint-check.mjs
js#!/usr/bin/env node
/**
* Cursor stop hook: lint changed src files with the same ESLint rules as `npm run local`
* (vite-plugin-eslint in config/vite.config.dev.ts).
*/
import { spawnSync } from 'node:child_process'
import { readFileSync } from 'node:fs'
const MAX_OUTPUT_CHARS = 8000
const LINTABLE_FILE = /\.(vue|ts|tsx|js|jsx)$/i
function readHookInput() {
try {
const raw = readFileSync(0, 'utf8')
return raw ? JSON.parse(raw) : {}
} catch {
return {}
}
}
function runGit(args) {
const result = spawnSync('git', args, {
cwd: process.cwd(),
encoding: 'utf8',
shell: process.platform === 'win32',
})
return (result.stdout || '').split(/\r?\n/).filter(Boolean)
}
function getChangedLintableFiles() {
const files = new Set()
for (const file of runGit(['diff', '--name-only', 'HEAD', '--', 'src/'])) {
if (LINTABLE_FILE.test(file)) files.add(file)
}
for (const file of runGit(['diff', '--cached', '--name-only', 'HEAD', '--', 'src/'])) {
if (LINTABLE_FILE.test(file)) files.add(file)
}
for (const file of runGit(['ls-files', '--others', '--exclude-standard', 'src/'])) {
if (LINTABLE_FILE.test(file)) files.add(file)
}
return [...files]
}
function runEslint(files) {
const npx = process.platform === 'win32' ? 'npx.cmd' : 'npx'
const result = spawnSync(
npx,
['eslint', ...files, '--max-warnings', '0', '--format', 'stylish'],
{
cwd: process.cwd(),
encoding: 'utf8',
shell: process.platform === 'win32',
env: process.env,
}
)
const output = [result.stdout, result.stderr].filter(Boolean).join('\n').trim()
return {
ok: result.status === 0,
output,
exitCode: result.status ?? 1,
}
}
function emit(result) {
process.stdout.write(`${JSON.stringify(result)}\n`)
}
const input = readHookInput()
if (input.status === 'aborted') {
emit({})
process.exit(0)
}
const changedFiles = getChangedLintableFiles()
if (changedFiles.length === 0) {
emit({})
process.exit(0)
}
const { ok, output, exitCode } = runEslint(changedFiles)
if (ok) {
emit({})
process.exit(0)
}
const truncated =
output.length > MAX_OUTPUT_CHARS ? `${output.slice(0, MAX_OUTPUT_CHARS)}\n...(输出已截断)` : output
const fileList = changedFiles.map((f) => `- ${f}`).join('\n')
emit({
followup_message: `本地 Lint 检查未通过(规则与 npm run local 开发服一致)。请修复以下问题:
检查文件:
${fileList}
\`\`\`
${truncated || `eslint 退出码 ${exitCode}`}
\`\`\`
可本地复现:npx eslint ${changedFiles.join(' ')}`,
})
process.exit(0)
代码每次跑完,都会自动触发eslint check 使得:
js已修复 Prettier 格式问题:将「复用HEX」表单项和 a-option 的多行属性合并为单行。npx eslint 现已通过(exit code 0)。
js已修复 detail.vue 中的 2 处 Prettier 格式问题:
第 117 行:将 a-button 的多行属性合并为单行
第 726 行:将三元表达式合并为单行
对上述两个文件的 ESLint 检查已通过。
js已修复:将 fetchReuseHexCandidates 及其依赖的 isPersonalUploadedHex、sortReuseHexOptions 提前到 resetImportState 之前定义,消除 no-use-before-define 报错。
上述 3 个文件的 ESLint 检查均已通过。
本文作者:lixf6
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!