fix(oxlint): skip js-combine-iterations on lazy Iterator helper chains (#205)#272
Merged
Conversation
Walks the chain inward from the inner call's receiver, classifying each CallExpression as iterator-producing (.values/.keys/.entries on a non-Object receiver, Iterator.from(), or a syntactically-declared generator), pass- through (chainable iteration method), or unknown/materializing. Lazy chains rooted in iterators (e.g. arr.values().filter().map().toArray()) no longer trip the rule, while eager array chains (and Object.values/keys/entries, Array.from, .toArray() materializers) still do. Closes #205. Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
…hains Adds 18 test cases covering eager arrays (still flagged), .values/.keys/.entries on Map/Set/array (not flagged), Object.values/entries (still flagged because they return arrays), .toArray() / Array.from() materialization (still flagged), Iterator.from(...) chains, hoisted and const-bound generator declarations, optional chaining, .flatMap() walks, the existing Boolean / identity filter exclusions, and a documented imported-generator false positive. Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
|
🔴 React Review — 0/100 (unchanged) · No new issues Reviewed by react-review for commit 20238e5. Configure here. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
…r fix" This reverts commit b1c0d8e. Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the false positive in
js-combine-iterationsfor chains rooted in lazy Iterator helpers. Previously, this benign single-pass pipeline:…was reported as
.filter().map() iterates the array twice — combine into a single loop with .reduce() or for...of. Iterator helpers are lazy and single-pass, so this is incorrect.Closes #205. Supersedes #212 (which only inspected the immediate inner-call receiver and missed deeper nesting, generators,
Iterator.from,Object.values/.toArray()distinctions, etc.).Approach
Walk the chain inward from the inner call's receiver, classifying each
CallExpression:<x>.values(),<x>.keys(),<x>.entries()where<x>is not the globalObject(Maps, Sets, arrays,URLSearchParams, etc.)Iterator.from(<x>)function* gen() {}orconst gen = function*() {}, including hoisted use)map/filter/flatMap/forEach)..toArray(),Array.from(...), plain identifiers, and any other call shape — so eager array chains and Iterator helper chains that have been re-materialized into arrays still get flagged.Object.values/keys/entries(...)is intentionally treated as eager (returns an array), soObject.values(map).map().filter()still fires.Cross-file imports of generators, class-method generators, and TS-type-only
IterableIterator<T>parameters remain accepted false positives — documented in the test file.Files
packages/oxlint-plugin-react-doctor/src/plugin/constants/js.ts— addsITERATOR_PRODUCING_METHOD_NAMES.packages/oxlint-plugin-react-doctor/src/plugin/rules/js-performance/js-combine-iterations.ts— collects per-file generator names onProgramenter, then walks the receiver chain to detect iterator-rooted lazy chains before reporting.packages/react-doctor/tests/regressions/js-performance-rules.test.ts— 18 new regression cases.Test matrix (regression tests)
arr.filter().map()numbers.values().filter().map().toArray()(issue #205 repro)numbers.values().map().filter()(deeper nesting)mapInstance.entries().map().filter()setInstance.keys().filter().map()Object.values(obj).map().filter()Object.*is eager)Object.entries(obj).filter().map()arr.values().toArray().filter().map().toArray()materializes)Array.from(it).filter().map()Iterator.from(arr).map().filter()function* countUp(){}thencountUp().filter().map()const gen = function*(){}; gen().filter().map()arr?.values()?.filter()?.map()(optional chaining)groups.flatMap(...).filter().map()(eager.flatMap)groups.values().flatMap(...).filter().map().toArray()arr.map(x => x ? x : null).filter(Boolean)arr.map(x => x ? x : null).filter(name => name)gen()from another file then.filter().map()Verification
pnpm typecheck— green (10/10 tasks).pnpm lint— 0 warnings, 0 errors across 542 files.pnpm format— clean.pnpm test— 998 / 998 tests pass, including all 18 new regression cases underjs-combine-iterations.pnpm --filter oxlint-plugin-react-doctor gen:check— registry in sync.Eval Results
Ran against 100-repo corpus (baseline: main @ 529015d, 13,279 diagnostics).
Parity: OK — Zero regressions, zero changes. The fix correctly targets lazy iterator chains without affecting any other diagnostics across the entire corpus.