mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-03-31 06:03:29 +08:00
103 lines
2.7 KiB
JavaScript
103 lines
2.7 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* 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,
|
|
* 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
|
|
let data = '';
|
|
process.stdin.setEncoding('utf8');
|
|
|
|
process.stdin.on('data', chunk => {
|
|
if (data.length < MAX_STDIN) {
|
|
const remaining = MAX_STDIN - data.length;
|
|
data += chunk.substring(0, remaining);
|
|
}
|
|
});
|
|
|
|
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);
|
|
const filePath = input.tool_input?.file_path;
|
|
|
|
if (filePath && /\.(ts|tsx|js|jsx)$/.test(filePath)) {
|
|
try {
|
|
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 {
|
|
// Formatter not installed, file missing, or failed — non-blocking
|
|
}
|
|
}
|
|
} catch {
|
|
// Invalid input — pass through
|
|
}
|
|
|
|
process.stdout.write(data);
|
|
process.exit(0);
|
|
});
|