mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-03-30 21:53:28 +08:00
feat: auto-detect formatter in post-edit hook (Biome/Prettier)
The post-edit-format hook was hardcoded to use Prettier. Projects using Biome had their code reformatted with Prettier defaults (e.g. double quotes overwriting single quotes). Now the hook walks up from the edited file to find the project root, then checks for config files: - biome.json / biome.jsonc → runs Biome - .prettierrc / prettier.config.* → runs Prettier - Neither found → skips formatting silently
This commit is contained in:
@@ -108,7 +108,7 @@
|
||||
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/post-edit-format.js\""
|
||||
}
|
||||
],
|
||||
"description": "Auto-format JS/TS files with Prettier after edits"
|
||||
"description": "Auto-format JS/TS files after edits (auto-detects Biome or Prettier)"
|
||||
},
|
||||
{
|
||||
"matcher": "Edit",
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* PostToolUse Hook: Auto-format JS/TS files with Prettier after edits
|
||||
* PostToolUse Hook: Auto-format JS/TS files after edits
|
||||
*
|
||||
* Cross-platform (Windows, macOS, Linux)
|
||||
*
|
||||
* Runs after Edit tool use. If the edited file is a JS/TS file,
|
||||
* formats it with Prettier. Fails silently if Prettier isn't installed.
|
||||
* auto-detects the project formatter (Biome or Prettier) by looking
|
||||
* for config files, then formats accordingly.
|
||||
* Fails silently if no formatter is found or installed.
|
||||
*/
|
||||
|
||||
const { execFileSync } = require('child_process');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const MAX_STDIN = 1024 * 1024; // 1MB limit
|
||||
@@ -21,6 +24,52 @@ process.stdin.on('data', chunk => {
|
||||
}
|
||||
});
|
||||
|
||||
function findProjectRoot(startDir) {
|
||||
let dir = startDir;
|
||||
while (dir !== path.dirname(dir)) {
|
||||
if (fs.existsSync(path.join(dir, 'package.json'))) return dir;
|
||||
dir = path.dirname(dir);
|
||||
}
|
||||
return startDir;
|
||||
}
|
||||
|
||||
function detectFormatter(projectRoot) {
|
||||
const biomeConfigs = ['biome.json', 'biome.jsonc'];
|
||||
for (const cfg of biomeConfigs) {
|
||||
if (fs.existsSync(path.join(projectRoot, cfg))) return 'biome';
|
||||
}
|
||||
|
||||
const prettierConfigs = [
|
||||
'.prettierrc',
|
||||
'.prettierrc.json',
|
||||
'.prettierrc.js',
|
||||
'.prettierrc.cjs',
|
||||
'.prettierrc.mjs',
|
||||
'.prettierrc.yml',
|
||||
'.prettierrc.yaml',
|
||||
'.prettierrc.toml',
|
||||
'prettier.config.js',
|
||||
'prettier.config.cjs',
|
||||
'prettier.config.mjs',
|
||||
];
|
||||
for (const cfg of prettierConfigs) {
|
||||
if (fs.existsSync(path.join(projectRoot, cfg))) return 'prettier';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function getFormatterCommand(formatter, filePath) {
|
||||
const npxBin = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
||||
if (formatter === 'biome') {
|
||||
return { bin: npxBin, args: ['@biomejs/biome', 'format', '--write', filePath] };
|
||||
}
|
||||
if (formatter === 'prettier') {
|
||||
return { bin: npxBin, args: ['prettier', '--write', filePath] };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
process.stdin.on('end', () => {
|
||||
try {
|
||||
const input = JSON.parse(data);
|
||||
@@ -28,15 +77,19 @@ process.stdin.on('end', () => {
|
||||
|
||||
if (filePath && /\.(ts|tsx|js|jsx)$/.test(filePath)) {
|
||||
try {
|
||||
// Use npx.cmd on Windows to avoid shell: true which enables command injection
|
||||
const npxBin = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
||||
execFileSync(npxBin, ['prettier', '--write', filePath], {
|
||||
cwd: path.dirname(path.resolve(filePath)),
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
timeout: 15000
|
||||
});
|
||||
const projectRoot = findProjectRoot(path.dirname(path.resolve(filePath)));
|
||||
const formatter = detectFormatter(projectRoot);
|
||||
const cmd = getFormatterCommand(formatter, filePath);
|
||||
|
||||
if (cmd) {
|
||||
execFileSync(cmd.bin, cmd.args, {
|
||||
cwd: projectRoot,
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
timeout: 15000
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
// Prettier not installed, file missing, or failed — non-blocking
|
||||
// Formatter not installed, file missing, or failed — non-blocking
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
|
||||
Reference in New Issue
Block a user