feat(hooks): auto-detect formatter in post-edit hook (Biome/Prettier)#252
Conversation
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
📝 WalkthroughWalkthroughThe post-edit hook now automatically detects and uses either Biome or Prettier for code formatting, replacing a hardcoded Prettier dependency. The description in hooks.json was updated to reflect this auto-detection capability. Detection logic checks for formatter configuration files in the project root. Changes
Sequence Diagram(s)sequenceDiagram
participant Hook as Post-Edit Hook
participant FS as File System
participant Detect as Formatter Detector
participant Cmd as Command Builder
participant Exec as Executor
Hook->>FS: findProjectRoot(startDir)
FS-->>Hook: projectRoot path
Hook->>Detect: detectFormatter(projectRoot)
Detect->>FS: Check for biome.json/biome.jsonc
Detect->>FS: Check for Prettier config files
FS-->>Detect: formatter name or null
Detect-->>Hook: formatter type
alt Formatter Found
Hook->>Cmd: getFormatterCommand(formatter, filePath)
Cmd-->>Hook: npx command string
Hook->>Exec: Execute command
Exec-->>Hook: success/failure
else No Formatter
Hook-->>Hook: Non-blocking skip
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Tip Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
scripts/hooks/post-edit-format.js (2)
36-60:detectFormattermisses two valid Prettier config locations
package.json"prettier"key — a commonly used inline Prettier config that the detection loop skips entirely.- Workspace-level configs in monorepos — detection only runs against the directory containing the nearest
package.json. Ifbiome.jsonor.prettierrclives at the workspace root (one level above the package), it won't be found. Extending the check to walk up fromprojectRootuntil a formatter config is found (mirroring howfindProjectRootwalks up forpackage.json) would cover this gap.♻️ Proposed fix: add `package.json` prettier-key check
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'; } + + // Check package.json for an inline "prettier" key + const pkgPath = path.join(projectRoot, 'package.json'); + if (fs.existsSync(pkgPath)) { + try { + const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')); + if (pkg.prettier) return 'prettier'; + } catch {} + } return null; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/hooks/post-edit-format.js` around lines 36 - 60, detectFormatter currently only checks local biomeConfigs and prettierConfigs files and doesn't detect a "prettier" key inside package.json nor search parent directories; update detectFormatter to (1) when scanning for Prettier, also read package.json at the current directory and return 'prettier' if it contains a "prettier" key, and (2) instead of only checking projectRoot, walk up parent directories (like findProjectRoot does) until filesystem root to look for biomeConfigs, prettierConfigs and package.json "prettier" key so workspace-level configs are detected; keep the existing return values ('biome' or 'prettier') and null fallback.
78-90: RelativefilePathpassed to formatter causes silent failures whenprojectRootdiffers from process CWDLine 80 resolves the path to locate
projectRoot, but the original (potentially relative)filePathis passed togetFormatterCommandon line 82. WhenexecFileSyncruns withcwd: projectRoot, a relative path is resolved againstprojectRoot—not the process CWD—targeting the wrong path.Example (monorepo, process CWD =
/workspace):
filePath:packages/app/src/index.ts(relative)projectRoot:/workspace/packages/app- Formatter receives:
prettier --write packages/app/src/index.tswithcwd=/workspace/packages/app- Effective path:
/workspace/packages/app/packages/app/src/index.ts❌Similar defensive path resolution is already used in
post-edit-typecheck.js(line 32), confirming that relative paths need handling.♻️ Proposed fix: resolve filePath once and use it throughout
if (filePath && /\.(ts|tsx|js|jsx)$/.test(filePath)) { try { - const projectRoot = findProjectRoot(path.dirname(path.resolve(filePath))); + const absFilePath = path.resolve(filePath); + const projectRoot = findProjectRoot(path.dirname(absFilePath)); const formatter = detectFormatter(projectRoot); - const cmd = getFormatterCommand(formatter, filePath); + const cmd = getFormatterCommand(formatter, absFilePath); if (cmd) { execFileSync(cmd.bin, cmd.args, {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/hooks/post-edit-format.js` around lines 78 - 90, The formatter is being passed the original (possibly relative) filePath which, when execFileSync runs with cwd set to projectRoot, causes wrong paths; resolve filePath to an absolute path once (e.g., using path.resolve with the original filePath) after computing projectRoot (or immediately) and then use that resolvedFilePath for getFormatterCommand, for any args passed to execFileSync, and anywhere else filePath is used (references: filePath, projectRoot, findProjectRoot, detectFormatter, getFormatterCommand, execFileSync) so the formatter always receives an absolute correct path.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@scripts/hooks/post-edit-format.js`:
- Around line 36-60: detectFormatter currently only checks local biomeConfigs
and prettierConfigs files and doesn't detect a "prettier" key inside
package.json nor search parent directories; update detectFormatter to (1) when
scanning for Prettier, also read package.json at the current directory and
return 'prettier' if it contains a "prettier" key, and (2) instead of only
checking projectRoot, walk up parent directories (like findProjectRoot does)
until filesystem root to look for biomeConfigs, prettierConfigs and package.json
"prettier" key so workspace-level configs are detected; keep the existing return
values ('biome' or 'prettier') and null fallback.
- Around line 78-90: The formatter is being passed the original (possibly
relative) filePath which, when execFileSync runs with cwd set to projectRoot,
causes wrong paths; resolve filePath to an absolute path once (e.g., using
path.resolve with the original filePath) after computing projectRoot (or
immediately) and then use that resolvedFilePath for getFormatterCommand, for any
args passed to execFileSync, and anywhere else filePath is used (references:
filePath, projectRoot, findProjectRoot, detectFormatter, getFormatterCommand,
execFileSync) so the formatter always receives an absolute correct path.
affaan-m
left a comment
There was a problem hiding this comment.
Automated review: this PR has merge conflicts. Please rebase or resolve.
|
Hey @pythonstrup! 👋 This PR has a merge conflict that needs to be resolved before it can be merged. Could you please rebase on main? Thanks! |
affaan-m
left a comment
There was a problem hiding this comment.
Automated review: this PR has merge conflicts. Please rebase or resolve.
|
CI check requested - please rebase on latest main to trigger CI. |
…matter LGTM — Auto-detect formatter hook. Safe, well-structured.
Description
The
post-edit-formathook was hardcoded to use Prettier. Projects usingBiome had their code silently reformatted with Prettier defaults (e.g.
single quotes → double quotes), causing unexpected diffs.
This change makes the hook auto-detect the project's formatter by walking
up the directory tree from the edited file and checking for config files:
biome.json/biome.jsonc→ Biome.prettierrc/prettier.config.*→ PrettierType of Change
feat:New featureChecklist
node tests/run-all.js)Summary by CodeRabbit
Release Notes