Skip to content

fix(format): preserve built-in fields when partially overriding a formatter#14883

Open
zerone0x wants to merge 1 commit intoanomalyco:devfrom
zerone0x:fix/formatter-partial-override-drops-command
Open

fix(format): preserve built-in fields when partially overriding a formatter#14883
zerone0x wants to merge 1 commit intoanomalyco:devfrom
zerone0x:fix/formatter-partial-override-drops-command

Conversation

@zerone0x
Copy link
Contributor

Issue for this PR

Closes #14857

Type of change

  • Bug fix

What does this PR do?

When a user overrides a built-in formatter's extensions without also specifying command, the entire override was silently discarded and the original built-in (including all default extensions) remained unchanged.

Root cause: The merge order was wrong. The code spread command: [] as an empty stub before ...item, then passed the combined object as the override to mergeDeep. Since the user didn't provide command, the stub [] was used — which then replaced the built-in command array. The command.length === 0 guard fired, skipping the formatter entirely.

Fix: Change the merge order to: defaults < built-in < user config

// Before (broken): stub defaults override built-in fields the user didn't specify
mergeDeep(formatters[name] ?? {}, { command: [], extensions: [], ...item })

// After (fixed): built-in values fill in what the user didn't override
{
  command: [],
  extensions: [],
  enabled: async () => true,
  ...(formatters[name] ?? {}),  // built-in overrides defaults
  ...userOverride,               // user config overrides built-in (only provided fields)
  name,
}

This means a user can now write:

"formatter": {
  "prettier": {
    "extensions": [".js", ".ts"]
  }
}

…and prettier's built-in command is preserved while only the extensions are narrowed.

How did you verify your code works?

  • Traced the logic manually for: (a) built-in override with only extensions, (b) override with only command, (c) override with both, (d) new custom formatter, (e) disabled: true — all cases behave correctly.
  • Removed the now-unused mergeDeep import from remeda.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

🤖 Generated with Claude Code (issue-hunter-pro)

…matter

When a user overrides only `extensions` (without specifying `command`),
the built-in command was silently replaced with an empty array due to
incorrect merge ordering. The `command: []` stub spread before `...item`
was then passed to mergeDeep as the override value, causing the
`command.length === 0` guard to skip the entire formatter config.

Fix the merge order so that:
  defaults < built-in < user config

This way, any field the user omits falls back to the built-in value
instead of an empty default.

Fixes anomalyco#14857

Co-Authored-By: Claude <noreply@anthropic.com>
@zerone0x zerone0x force-pushed the fix/formatter-partial-override-drops-command branch from b832eca to 5a6347f Compare February 24, 2026 10:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]: Partial formatter override silently dropped when command is not specified

1 participant