From f65310b44fcb16141e1a956a18d7dfa0789d415b Mon Sep 17 00:00:00 2001 From: connorshea <2977353+connorshea@users.noreply.github.com> Date: Tue, 17 Feb 2026 09:22:00 +0000 Subject: [PATCH] fix(linter): Handle optional chaining in `prefer-object-from-entries` rule. (#19475) Had some guidance from Claude on this one, still getting familiar with the AST and methods that are available in oxc for this kind of thing. --- .../src/rules/unicorn/prefer_object_from_entries.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/oxc_linter/src/rules/unicorn/prefer_object_from_entries.rs b/crates/oxc_linter/src/rules/unicorn/prefer_object_from_entries.rs index 164036c320e6d..3415fdbc3d804 100644 --- a/crates/oxc_linter/src/rules/unicorn/prefer_object_from_entries.rs +++ b/crates/oxc_linter/src/rules/unicorn/prefer_object_from_entries.rs @@ -1,6 +1,6 @@ use oxc_ast::{ AstKind, - ast::{Expression, ObjectPropertyKind, PropertyKind, Statement}, + ast::{Expression, MemberExpression, ObjectPropertyKind, PropertyKind, Statement}, }; use oxc_diagnostics::OxcDiagnostic; use oxc_macros::declare_oxc_lint; @@ -89,6 +89,8 @@ impl Rule for PreferObjectFromEntries { let AstKind::CallExpression(call_expr) = node.kind() else { return }; if call_expr.arguments.len() == 1 + && !call_expr.optional + && !call_expr.callee.as_member_expression().is_some_and(MemberExpression::optional) && call_expr.arguments[0].is_expression() && does_expr_match_any_path( &call_expr.callee, @@ -345,8 +347,7 @@ fn test() { ("_.fromPairs()", None), ("new _.fromPairs(pairs)", None), ("_.fromPairs(...[pairs])", None), - // TODO: Fix this rule so this test passes. - // ("_?.fromPairs(pairs)", None), + ("_?.fromPairs(pairs)", None), ("_.foo(pairs)", Some(serde_json::json!([{"functions": ["foo"]}]))), ("foo(pairs)", Some(serde_json::json!([{"functions": ["utils.object.foo"]}]))), ("object.foo(pairs)", Some(serde_json::json!([{"functions": ["utils.object.foo"]}]))),