{"record":{"id":"59708f083d8bd3da","repo":"oxc-project/oxc","slug":"prefer-a-single-flatmap-over-filter-flatmap","errorCode":null,"errorMessage":"Prefer a single `.flatMap(…)` over `.filter(…).flatMap(…)`.","messagePattern":"Prefer a single `\\.flatMap\\(…\\)` over `\\.filter\\(…\\)\\.flatMap\\(…\\)`\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/oxc_linter/src/rules/unicorn/prefer_array_flat_map.rs","lineNumber":163,"sourceCode":"        && member.property.name == \"flatMap\"\n        && let Expression::CallExpression(filter) = member.object.get_inner_expression()\n        && !filter.optional\n        && filter.type_arguments.is_none()\n        && filter.arguments.len() == 1\n        && let Expression::StaticMemberExpression(filter_member) =\n            filter.callee.get_inner_expression()\n        && !filter_member.optional\n        && filter_member.property.name == \"filter\"\n        && !has_optional_chain(&filter_member.object)\n        && !ctx.has_comments_between(call.span)\n        && let Some((filter_name, predicate)) = simple_callback(&filter.arguments[0])\n        && let Some((map_name, mapped)) = simple_callback(&call.arguments[0])\n        && filter_name == map_name\n        && matches!(mapped.without_parentheses(), Expression::ArrayExpression(array) if array.elements.len() > 1)\n        && !is_known_non_indexed_receiver(&filter_member.object, ctx)\n    {\n        ctx.diagnostic_with_suggestion(\n            OxcDiagnostic::warn(\"Prefer a single `.flatMap(…)` over `.filter(…).flatMap(…)`.\")\n                .with_label(member.property.span),\n            |fixer| {\n                let receiver = fixer.source_range(filter_member.object.span());\n                let predicate_text = fixer.source_range(predicate.span());\n                // These expressions need grouping when used as the test of a conditional.\n                let predicate_text = if matches!(\n                    predicate,\n                    Expression::ArrowFunctionExpression(_)\n                        | Expression::AssignmentExpression(_)\n                        | Expression::ClassExpression(_)\n                        | Expression::ConditionalExpression(_)\n                        | Expression::FunctionExpression(_)\n                        | Expression::ObjectExpression(_)\n                        | Expression::SequenceExpression(_)\n                        | Expression::TSAsExpression(_)\n                        | Expression::TSNonNullExpression(_)\n                        | Expression::TSSatisfiesExpression(_)\n                        | Expression::TSTypeAssertion(_)","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/oxc-project/oxc/blob/12cb5473519327bd37780f2e42bf1eade98542b6/crates/oxc_linter/src/rules/unicorn/prefer_array_flat_map.rs#L145-L181","documentation":"This is a lint diagnostic from the oxlint rule `unicorn/prefer-array-flat-map`. It fires when code chains `.filter(...).flatMap(...)` on the same receiver, because the filter step can be inlined as an array literal returned by the flatMap callback, yielding a single `.flatMap(…)` call. The library throws it to steer developers toward simpler, more idiomatic array chaining.","triggerScenarios":"oxlint detects `x.filter(fn).flatMap(cb)` where the filter callback name matches the flatMap callback's predicate name (simple_callback on the flatMap argument), the flatMap callback returns an array literal with more than one element (so inlining is beneficial), and the receiver is not a known non-indexed object (checked via is_known_non_indexed_receiver).","commonSituations":"Seen in everyday data-transformation code where developers filter then flatMap over arrays; also appears in migration runs when enabling unicorn presets, and in CI when new oxlint versions add this rule.","solutions":["Replace `.filter(predicate).flatMap(cb)` with a single `.flatMap(el => predicate(el) ? [...] : [])`, inlining the predicate condition into the callback.","Apply the rule's provided auto-fix (it rewrites the chain, adding grouping parentheses around the predicate when used as a conditional test).","Disable or downgrade `unicorn/prefer-array-flat-map` in .oxlintrc.json if the two-call form is preferred."],"exampleFix":"// before\nconst ids = users.filter(u => u.active).flatMap(u => [u.id, u.parentId]);\n// after\nconst ids = users.flatMap(u => u.active ? [u.id, u.parentId] : []);","handlingStrategy":"validation","validationCode":"// oxlint config check before CI\n// .oxlintrc.json\n// { \"rules\": { \"unicorn/prefer-array-flat-map\": \"warn\" } }\n// pre-commit: npx oxlint --fix --rule 'unicorn/prefer-array-flat-map':error","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Write flatMap-first: inline filter predicates into the flatMap callback from the start.","Run `oxlint --fix` locally before committing to let the rule rewrite chains automatically.","Enable the unicorn preset in code review so the style is enforced continuously."],"tags":["lint","javascript","arrays","code-style"],"backgroundTag":"deprecated-api-usage","analyzedSha":"12cb5473519327bd37780f2e42bf1eade98542b6","analyzedAt":"2026-09-20T16:15:10.494Z","contentChangedAt":"2026-09-20T16:15:10.494Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}