fix(linter/no-array-sort): skip non compare fn sort arguments#22752
Merged
camc314 merged 2 commits intoMay 28, 2026
Merged
Conversation
Closes oxc-project#22487. Narrow `unicorn/no-array-sort` to skip `.sort(...)` calls whose single argument cannot be a valid `Array#sort` `compareFn`. `Array.prototype.sort` accepts either zero arguments or a function-shaped value; an object, string, numeric, template-literal, array-literal, or unary-numeric argument is therefore inconsistent with `Array#sort` and almost always indicates a query-builder API like Mongoose's `Model.find().sort({ field: 1 })`. The in-source TODO list at `no_array_sort.rs:156` already enumerated exactly these false-positive shapes; this change promotes those cases from commented TODOs to active `pass` tests and adds the issue body's Mongoose reproduction as a named regression case.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR narrows unicorn/no-array-sort to avoid false positives for non-array .sort(...) APIs such as Mongoose query sorting.
Changes:
- Adds an argument-shape helper to skip
.sort(...)calls with single non-compare-function literal-style arguments. - Promotes prior TODO false-positive cases into passing tests.
- Adds Mongoose regression pass cases from the linked issue.
Merging this PR will not alter performance
Comparing Footnotes
|
graphite-app Bot
pushed a commit
that referenced
this pull request
May 28, 2026
Follow-on from the review comment on #22752: unwrap parenthesized `.sort(...)` arguments before deciding whether they are non-compareFn query-builder arguments.
camc314
pushed a commit
that referenced
this pull request
Jun 1, 2026
# Oxlint ### 🚀 Features - e4b1f46 linter/typescript: Implement `method-signature-style` rule (#22679) (Mikhail Baev) - bc462ca linter/vue: Implement no-reserved-component-names rule (#22741) (bab) - ef9e751 linter/vue: Implement component-definition-name-casing rule (#22818) (bab) - d67f51a linter/vue: Implement require-prop-type-constructor rule (#22708) (bab) - 1444f82 linter/promise/spec-only: Add `Promise.try` to `Promise` static methods (#22812) (Ben Saufley) - 8422e8b linter/jsdoc: Implement `require-yields-description` rule (#22805) (Mikhail Baev) - fe93f97 linter/eslint: Implement `prefer-named-capture-group` rule (#22759) (Sebastian Poxhofer) - 1a7798b linter: Add suggestion for `unicorn/no-new-array` (#22682) (Sysix) ### 🐛 Bug Fixes - 760a9f9 linter: Report errors when writing to the filesystem (#22881) (camc314) - e5a2748 linter: Avoid no-unreachable false positive after conditional loop (#22869) (camc314) - 39d92d6 linter/arrow-body-style: Preserve comments within function (#22854) (Sysix) - 3d13e29 parser: Reject `declare` in an already-ambient context (TS1038) (#22850) (Boshen) - 5152854 parser: Reject statements in ambient contexts (TS1036) (#22849) (Boshen) - 2eafea6 parser: Reject function implementations in ambient contexts (TS1183) (#22845) (Boshen) - c645615 parser: Reject incompatible class member modifiers (#22843) (Boshen) - 4a1ca4a linter/export: Detect duplicate explicit exports (#22798) (camc314) - 0a9a735 linter/no-loop-func: Allow safe let closures (#22811) (camc314) - 1599f11 linter: Align lsp extends default plugins (#22788) (camc314) - db32ec9 linter/no-accumulating-spread: Use loop as primary span (#22800) (camc314) - 33ec6b4 linter/consistent-test-it: Avoid adjacent describe leakage (#22796) (camc314) - 2606069 linter/no-array-sort: Unwrap parenthesized sort args (#22794) (camc314) - 9f2f709 linter/no-array-sort: Skip non compare fn sort arguments (#22752) (Gaurav Dubey) - 27268a0 linter/no-else-return: Preserve statement boundary in fixer (#22687) (camc314) - d9cb6d8 linter/no-empty-function: Allow functions callbacks with `allow: functions` (#22764) (camc314) - a40a314 linter/no-shadow-restricted-names: Ignore enum members (#22762) (camc314) - 82366d9 linter/no-cond-assign: Align ternary handling (#22761) (camc314) ### 📚 Documentation - 5e113ba linter: Add license notices for ported ESLint plugins (#22768) (Boshen) # Oxfmt ### 🚀 Features - d75cbbf oxfmt: Format `parser:json` files by `oxc_formatter_json` (#22709) (leaysgur) - 49db054 formatter_json: Implement `oxc_formatter_json` (json variant only) (#22641) (leaysgur) - 9c71f2e ast, codegen, formatter: Add `WithClauseKeyword::as_str` helper and use it (#22791) (camc314) ### 🐛 Bug Fixes - d3cdd62 oxfmt: Skip formatting for whitespace-only file (#22780) (leaysgur) - 23f0cc8 formatter: Don't move comments inside variable declaration in for in loop (#22776) (leaysgur) - f200c40 formatter: Don't move comments inside variable declaration in for of loop (#22773) (Leonabcd123) ### 📚 Documentation - 845f393 oxfmt,formatter,formatter_json,formatter_core: Add/update AGENTS.md (#22873) (leaysgur)
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
Closes #22487.
unicorn/no-array-sortcurrently flags every member-call named.sort(...),including query-builder APIs like Mongoose's
Model.find().sort({ field: 1 }).The receiver is not an
Array, so the diagnostic is a false positive.This change narrows the rule by inspecting the single argument's shape.
Array.prototype.sort(compareFn?)accepts either zero arguments or a function-shaped value. A single object, string, numeric, template-literal, array-literal,
or unary-numeric argument is therefore incompatible with
Array#sort. Skippingdiagnostics in those cases removes the false positives without weakening
detection of the real misuse patterns this rule targets (
array.sort(),[...array].sort(),array.sort(compareFn)).Changes
crates/oxc_linter/src/rules/unicorn/no_array_sort.rs:is_non_compare_fn_argumentearly-returns fromRule::runwhenthe call has exactly one argument matching the non-
compareFnshapes listedabove.
// TODO: Get these passing?block at the previousno_array_sort.rs:156enumerated exactly these false-positive cases. ThoseTODO entries are now active
passtests.passregression tests drawn directly from the issue body(
User.find().sort({ createdAt: -1 }),User.find().sort("-createdAt"),Post.find({ published: true }).sort({ updatedAt: "desc" })).failandexpect_fixcases are unchanged. The snapshot filesnapshots/unicorn_no_array_sort.snapis unchanged because the newpasscases produce no diagnostics.
Test plan
cargo test --all-features -p oxc_linter no_array_sort—1 passed; 0 failedcargo test --all-features -p oxc_linter unicorn::—148 passed; 0 failedcargo fmt -- --check crates/oxc_linter/src/rules/unicorn/no_array_sort.rs— cleanarray.sort(compareFn)—Argument::Identifier(or arrow/function expr); not skipped, still reportedarray.sort((a, b) => a - b)—Argument::ArrowFunctionExpression; not skipped, still reportedarray.sort(({a}) => a)— destructuring lives inside the arrow body; argument is stillArrowFunctionExpression; not skippedquery.sort(-1)/query.sort(+1)—Argument::UnaryExpressionover aNumericLiteral; explicitly skippedarray.sort(...spread)—Argument::SpreadElement; the existing earlier early-return handles thisNotes
AI usage policy. The diagnostic narrowing follows the in-source TODO list
the maintainer already curated, and all logic, tests, and reasoning were
reviewed before submission.
rest of the unicorn rules. If a future direction prefers gating this kind
of receiver inference behind
--type-aware, this PR's logic can bereused or moved without disturbing public API.