chore: add lint check to pre-commit hook
- Add scripts/lint-staged.js to run oxlint on staged files - Extend format-staged.js to include ui/src/ directory - Update pre-commit hook to run both format and lint checks The pre-commit hook now blocks commits if there are linting errors, catching issues like unused imports before they land.
This commit is contained in:
parent
2d451b30f9
commit
13661abbd8
@ -1,4 +1,9 @@
|
||||
#!/bin/sh
|
||||
ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
|
||||
[ -z "$ROOT" ] && exit 0
|
||||
node "$ROOT/scripts/format-staged.js"
|
||||
|
||||
# Format staged files
|
||||
node "$ROOT/scripts/format-staged.js" || exit 1
|
||||
|
||||
# Lint staged files
|
||||
node "$ROOT/scripts/lint-staged.js" || exit 1
|
||||
|
||||
@ -61,6 +61,7 @@
|
||||
"LICENSE",
|
||||
"scripts/postinstall.js",
|
||||
"scripts/format-staged.js",
|
||||
"scripts/lint-staged.js",
|
||||
"scripts/setup-git-hooks.js",
|
||||
"git-hooks/**",
|
||||
"dist/terminal/**",
|
||||
|
||||
@ -41,7 +41,7 @@ function filterOxfmtTargets(paths) {
|
||||
return paths
|
||||
.map(normalizeGitPath)
|
||||
.filter((filePath) =>
|
||||
(filePath.startsWith("src/") || filePath.startsWith("test/")) &&
|
||||
(filePath.startsWith("src/") || filePath.startsWith("test/") || filePath.startsWith("ui/src/")) &&
|
||||
OXFMT_EXTENSIONS.has(path.posix.extname(filePath)),
|
||||
);
|
||||
}
|
||||
|
||||
104
scripts/lint-staged.js
Normal file
104
scripts/lint-staged.js
Normal file
@ -0,0 +1,104 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const LINT_EXTENSIONS = new Set([".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs"]);
|
||||
|
||||
function getRepoRoot() {
|
||||
const here = path.dirname(fileURLToPath(import.meta.url));
|
||||
return path.resolve(here, "..");
|
||||
}
|
||||
|
||||
function runGitCommand(args, options = {}) {
|
||||
return spawnSync("git", args, {
|
||||
cwd: options.cwd,
|
||||
encoding: "utf-8",
|
||||
stdio: options.stdio ?? "pipe",
|
||||
});
|
||||
}
|
||||
|
||||
function splitNullDelimited(value) {
|
||||
if (!value) return [];
|
||||
const text = String(value);
|
||||
return text.split("\0").filter(Boolean);
|
||||
}
|
||||
|
||||
function normalizeGitPath(filePath) {
|
||||
return filePath.replace(/\\/g, "/");
|
||||
}
|
||||
|
||||
function filterLintTargets(paths) {
|
||||
return paths
|
||||
.map(normalizeGitPath)
|
||||
.filter((filePath) =>
|
||||
(filePath.startsWith("src/") ||
|
||||
filePath.startsWith("test/") ||
|
||||
filePath.startsWith("ui/src/")) &&
|
||||
LINT_EXTENSIONS.has(path.posix.extname(filePath)),
|
||||
);
|
||||
}
|
||||
|
||||
function resolveOxlintCommand(repoRoot) {
|
||||
const binName = process.platform === "win32" ? "oxlint.cmd" : "oxlint";
|
||||
const local = path.join(repoRoot, "node_modules", ".bin", binName);
|
||||
if (fs.existsSync(local)) {
|
||||
return { command: local, args: [] };
|
||||
}
|
||||
|
||||
const result = spawnSync("oxlint", ["--version"], { stdio: "ignore" });
|
||||
if (result.status === 0) {
|
||||
return { command: "oxlint", args: [] };
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function getGitPaths(args, repoRoot) {
|
||||
const result = runGitCommand(args, { cwd: repoRoot });
|
||||
if (result.status !== 0) return [];
|
||||
return splitNullDelimited(result.stdout ?? "");
|
||||
}
|
||||
|
||||
function lintFiles(repoRoot, oxlint, files) {
|
||||
const result = spawnSync(oxlint.command, [...oxlint.args, ...files], {
|
||||
cwd: repoRoot,
|
||||
stdio: "inherit",
|
||||
});
|
||||
return result.status === 0;
|
||||
}
|
||||
|
||||
function main() {
|
||||
const repoRoot = getRepoRoot();
|
||||
const staged = getGitPaths(
|
||||
["diff", "--cached", "--name-only", "-z", "--diff-filter=ACMR"],
|
||||
repoRoot,
|
||||
);
|
||||
const targets = filterLintTargets(staged);
|
||||
if (targets.length === 0) return;
|
||||
|
||||
const oxlint = resolveOxlintCommand(repoRoot);
|
||||
if (!oxlint) {
|
||||
process.stderr.write("[pre-commit] oxlint not found; skipping lint.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!lintFiles(repoRoot, oxlint, targets)) {
|
||||
process.exitCode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
filterLintTargets,
|
||||
getRepoRoot,
|
||||
normalizeGitPath,
|
||||
resolveOxlintCommand,
|
||||
splitNullDelimited,
|
||||
};
|
||||
|
||||
if (
|
||||
process.argv[1] &&
|
||||
path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)
|
||||
) {
|
||||
main();
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user