Skip to content

feat(no-useless-fallback-in-spread): add no-useless-fallback-in-spread rule - #1527

Open
bartlomieju wants to merge 1 commit into
mainfrom
oxlint-port-no-useless-fallback-in-spread
Open

feat(no-useless-fallback-in-spread): add no-useless-fallback-in-spread rule#1527
bartlomieju wants to merge 1 commit into
mainfrom
oxlint-port-no-useless-fallback-in-spread

Conversation

@bartlomieju

Copy link
Copy Markdown
Member

This ports the unicorn no-useless-fallback-in-spread rule from oxlint as a
native deno_lint rule.

The rule flags a useless empty-object fallback inside an object spread, such as
{ ...(foo || {}) } or { ...(foo ?? {}) }. Spreading a nullish (or otherwise
falsy) value into an object literal is a no-op, so providing an empty object
{} as a fallback via || or ?? adds nothing and can be removed. The rule
only triggers when the spread is inside an object literal (not an array literal
or call arguments), the logical operator is || or ??, and the right operand
is an empty object literal, unwrapping any surrounding parentheses to match
oxc's behavior.

Reference implementation:
https://github.com/oxc-project/oxc/blob/main/crates/oxc_linter/src/rules/unicorn/no_useless_fallback_in_spread.rs

Tagged RECOMMENDED (on by default) — flagging for maintainer sign-off.

@bartlomieju

Copy link
Copy Markdown
Member Author

Verdict: LGTM — correct and well-tested. Recommend merge after the RECOMMENDED sign-off you flagged + rebase. Not auto-merging (new rule).

Clean port; flags { ...(foo || {}) } / { ...(foo ?? {}) }.

Correctness — verified

  • Scoping is elegant: hooking object_lit means only object-literal spreads are checked, so array spreads ([...(foo || {})]), call-arg spreads (call({}, ...(foo || {}))), and destructuring patterns (const {...foo} = obj) are naturally excluded — all covered by valid tests.
  • Operator gate is correct: only LogicalOr/NullishCoalescing, so {...(foo && {})} isn't flagged (matches oxc), and only the right operand is checked, so {...({} || foo)} isn't flagged.
  • Empty-object check via object.props.is_empty() correctly treats {...(foo || {...{}})} (right object has a spread prop) and {...(foo || {not: "empty"})} as non-empty.
  • unwrap_parens is applied to both the spread expr and the right operand, and non-Bin spread exprs ({...(foo || {}).toString()}, {...fn(foo || {})}, {...(foo ? foo : {})}) are correctly skipped.

Perf: trivial — per object_lit, linear over its props.

Housekeeping: RECOMMENDED sign-off (you flagged it); mergeable: UNKNOWN → rebase; docs .md not in diff.

No code changes requested — the object_lit-scoped approach cleanly handles every edge in the reference. Just tagging + rebase.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant