mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-04-10 11:23:32 +08:00
Merge pull request #252 from pythonstrup/feat/auto-detect-formatter
LGTM — Auto-detect formatter hook. Safe, well-structured.
This commit is contained in:
@@ -108,7 +108,7 @@
|
|||||||
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/post-edit-format.js\""
|
"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",
|
"matcher": "Edit",
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
#!/usr/bin/env node
|
#!/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)
|
* Cross-platform (Windows, macOS, Linux)
|
||||||
*
|
*
|
||||||
* Runs after Edit tool use. If the edited file is a JS/TS file,
|
* 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 { execFileSync } = require('child_process');
|
||||||
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const MAX_STDIN = 1024 * 1024; // 1MB limit
|
const MAX_STDIN = 1024 * 1024; // 1MB limit
|
||||||
@@ -22,6 +25,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', () => {
|
process.stdin.on('end', () => {
|
||||||
try {
|
try {
|
||||||
const input = JSON.parse(data);
|
const input = JSON.parse(data);
|
||||||
@@ -29,15 +78,19 @@ process.stdin.on('end', () => {
|
|||||||
|
|
||||||
if (filePath && /\.(ts|tsx|js|jsx)$/.test(filePath)) {
|
if (filePath && /\.(ts|tsx|js|jsx)$/.test(filePath)) {
|
||||||
try {
|
try {
|
||||||
// Use npx.cmd on Windows to avoid shell: true which enables command injection
|
const projectRoot = findProjectRoot(path.dirname(path.resolve(filePath)));
|
||||||
const npxBin = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
const formatter = detectFormatter(projectRoot);
|
||||||
execFileSync(npxBin, ['prettier', '--write', filePath], {
|
const cmd = getFormatterCommand(formatter, filePath);
|
||||||
cwd: path.dirname(path.resolve(filePath)),
|
|
||||||
stdio: ['pipe', 'pipe', 'pipe'],
|
if (cmd) {
|
||||||
timeout: 15000
|
execFileSync(cmd.bin, cmd.args, {
|
||||||
});
|
cwd: projectRoot,
|
||||||
|
stdio: ['pipe', 'pipe', 'pipe'],
|
||||||
|
timeout: 15000
|
||||||
|
});
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// Prettier not installed, file missing, or failed — non-blocking
|
// Formatter not installed, file missing, or failed — non-blocking
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
Reference in New Issue
Block a user