AI Disclosure: Generated with Claude Code, Opus 5. Tested and reviewed
by me.
Why do many code when few do trick?
Follow-up to #25901. Hand-rolled import checks can simply be replaced
with the shared `is_import_symbol` helper, this also helps improve the
accuracy of the code to catch aliased imports for one of them.
### Bug fixed
`is_vue_define_component_reference` (used by
`vue/no-deprecated-delete-set` to decide whether a `this.$set` /
`this.$delete` call sits inside a Vue component) gated on the **local**
name being `defineComponent` before walking up to the
`ImportDeclaration`, so an aliased import was never recognised:
```vue
<script>
import { defineComponent as dc } from 'vue'
dc({
mounted () {
this.$set(obj, key, value)
this.$delete(obj, key)
}
})
</script>
```
Neither call was reported before; both are now. Covered by a new test
case.
### Pure simplifications
- `is_imported_set_or_del_from_vue` (`no-deprecated-delete-set`) — 20
lines → two `is_import_symbol` calls.
- `is_vue_next_tick_import` (`utils/vue.rs`, used by
`vue/next-tick-style` and `vue/valid-next-tick`) — 18 lines → one call.
Both already matched by symbol id, so behavior is unchanged.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
AI Disclosure: Generated with Claude Code, Opus 5. Tested and reviewed
by me.
`no-react-children` decided whether an identifier came from `react` with
a hand-rolled helper that matched by **name**:
```rust
fn is_imported_from_react(local_name: &str, ctx: &LintContext) -> bool {
ctx.module_record().import_entries.iter().any(|entry| {
entry.module_request.name() == "react" && entry.local_name.name() == local_name
})
}
```
This replaces it with the existing shared helpers, `is_import_symbol`
and `is_import_from_module`.
### Bugs fixed
Four false positives, where a local binding shadowed the import:
```js
import { Children } from 'react';
function f(x) { const Children = { count: () => 0 }; return Children.count(x); }
import React from 'react';
function f(x) { const React = { Children: { map: () => {} } }; return React.Children.map(x); }
import { Children } from 'react';
export function f(Children) { return Children.count(1); }
import { count as Children } from 'react'; Children.toArray(x)
```
One false negative, an aliased import the local-name check couldn't see:
```js
import { Children as C } from 'react'; C.toArray(x)
```
All five are covered by new test cases.
### Performance
This has a minor downside in perf, but it's significantly less than a
millisecond difference and is probably worth the downside. We had
originally decided not to care about aliases when implementing this
rule, but this change allows us to reuse the existing util code for
checking where the import comes from, and fixes the aforementioned edge
cases, so I think this is a worthwhile change.
Measured with two `--features allocator` builds, paired and interleaved,
using `--debug=timings --threads=1` to isolate the rule's own time from
parse/semantic noise.
| corpus | base | new | change |
| --- | --- | --- | --- |
| sentry | 4.416ms | 4.589ms | +3.9% slower |
| material-ui | 3.111ms | 3.217ms | +3.4% slower |
| bluesky | 0.503ms | 0.540ms | +7.2% slower |
| actualbudget | 2.012ms | 2.105ms | +4.6% slower |
| synthetic, `Children` used heavily | 19.112ms | 15.443ms | 19.2%
faster |
There is a small, consistent regression on real code, and it's
deliberate. Dropping the `ident.name == "Children"` gate means every
`obj.method()` call in a file importing `react` now does two array
lookups instead of one string compare; removing the `O(imports)` scan
only pays off where `Children` is actually used, which is 27 files out
of 8.8K in sentry. The absolute cost is ≤0.17ms, and `no-react-children`
isn't a default rule anyway.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Cameron <cameron.clark@hey.com>
AI Disclosure: Generated with Claude Code, Opus 5. Tested and reviewed
by me.
Ten call sites across nine rules checked whether an identifier is a
specific global with:
```rust
ctx.scoping().root_unresolved_references().contains_key(&ident.name)
```
That asks whether the **name** is unresolved **somewhere in the file**,
not whether **this reference** is global. Any file that shadows the
global in one scope and uses the real global in another gets a false
positive on the shadowed use:
```js
function f(myLogger) {
const console = myLogger;
console.log(1); // reported by `no-console` — this is the bug
}
console.log(2); // the real global, elsewhere in the file
```
`ctx.is_reference_to_global_variable(ident)` already exists for this and
is used at ~50 other call sites. It is `reference.symbol_id().is_none()`
— one field read instead of hashing the name into the
unresolved-references map — and it honours the user's `globals: { X:
"off" }` config.
### Rules fixed
| rule | shadowed code that was wrongly reported |
| --- | --- |
| `eslint/no-console` | `const console = myLogger; console.log(foo)` |
| `eslint/no-constant-binary-expression` | `const String = MyString;
String(x) ?? y` |
| `eslint/no-new-native-nonconstructor` | `const Symbol = FakeSymbol;
new Symbol()` |
| `eslint/prefer-object-spread` | `const Object = MyObject;
Object.assign({}, a)` |
| `eslint/symbol-description` | `const Symbol = FakeSymbol; Symbol()` |
| `eslint/valid-typeof` | `const undefined = u; typeof x === undefined`
|
| `promise/avoid-new` | `const Promise = FakePromise; new Promise(fn)` |
| `unicorn/new-for-builtins` | `const String = MyString; new
String('x')` |
| `unicorn/prefer-global-this` | `const window = fake; window.foo` |
Each rule gets a pass test in that shape. Both halves matter — without a
second, genuine use of the global the name lookup already returns false,
so a single-scope test would pass before the fix too.
Three of these ship a fix or suggestion (`prefer-global-this`,
`valid-typeof`, `no-console`), so the false positive was rewriting or
deleting code the user owns.
### Real-world impact
Base vs. branch over four corpora (vscode, sentry, material-ui, actual),
each rule isolated with `-A all -A nursery -D <rule> --format=json
--no-ignore --disable-nested-config`, diagnostics normalised to `(file,
span, code, message)`:
**0 added, 23 removed.** Every removal is `prefer-global-this` on a
genuinely shadowed `window`:
- `vscode/src/vs/base/browser/dompurify/dompurify.js` (16) — `let window
= arguments.length > 0 ? arguments[0] : getGlobal()`
- `material-ui/packages-internal/core-docs/src/Demo/DemoSandbox.tsx` (5)
— `function IsolatedDemo({ children, cssVarPrefix, colorSchemeNode,
window })`, a destructured prop
- `sentry/src/sentry/templates/sentry/error-page-embed.js` (2) —
`(function (window, document, JSON) { ... })(window, document, JSON)`,
the classic IIFE parameter
In each file the real global references outside the shadowing scope are
still reported.
### Notes
- `no-console` uses `ident.is_global_reference(ctx.scoping())` rather
than the context helper. An existing fail case pins that `globals: {
console: "off" }` must still report, and the context helper treats
`"off"` as "not a global". The other eight sites use the context helper,
so they now respect that config, but this one doesn't.
- Five upstream ESLint pass cases that were commented out in
`no-constant-binary-expression` now pass and are re-enabled (`function
Boolean(n) { return n; }; Boolean(x) ?? foo` and friends). Two others in
that list stay commented — they are `function foo(undefined) { ... }`,
which is a separate problem: the rule matches `undefined` by name via
`Expression::is_undefined()`. Left a TODO pointing at it.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Signed-off-by: Cameron <cameron.clark@hey.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Cameron <cameron.clark@hey.com>
#25292 made isolated declaration emit report a false TS9025 for a defaulted parameter whose annotation is an indexed access type. This breaks Vite's `UserConfig["base"]` case when Rolldown upgrades Oxc, even though the indexed property already includes `undefined`.
Oxc's isolated declaration emitter has no type checker, so it cannot safely resolve indexed accesses, type references, conditional types, or similar annotations. This change uses a syntax-only classification: widen or diagnose types whose syntax is conclusive, and preserve checker-dependent types rather than emit an unstable error. The union/intersection rules retain the distinct behavior of `any`, `never`, `unknown`, and `void`, and an explicit `undefined` union member is never duplicated.
Regression coverage includes the Rolldown/Vite case and a compact matrix of the relevant type algebra. The implementation and tests were reduced to one commit after review.
Validated with the isolated-declarations tests, strict Clippy, the all-features workspace suite, lint, docs, AST generation, and TypeScript 5.6.1-rc/6.0.3 type-algebra checks. The full local `just ready` run stopped only at a runner-dependent source-map snapshot because the repository expects Node 26.5.0 and this machine has 25.8.1; the remaining suite passed with that and the known terminal-color snapshot group skipped.
Follow-up to #25292. Related Rolldown failure: https://github.com/rolldown/rolldown/actions/runs/32158377691/job/95782148042?pr=10707
Disclosure: this change was prepared and verified with AI assistance (Codex).
add `boolean_context` to `minimize_not` so negation folding can happen
in-place when possible, reducing extra AST rebuilds and allocations and
`!0` / `!1` can now collapse directly to `1` / `0` in boolean context
The 22 React Compiler rules split out by #25500, plus `eslint/no-unreachable-loop`, all first shipped in oxlint 1.79.0 but were still marked `version = "next"`. I think the release PR must've failed to run this part of the release task?
🤖 Generated with [Claude Code](https://claude.com/claude-code)
The shared React Compiler rule macro generated `react.dev` links for internal categories without public lint pages. Render those attributions without links and verify linked versus unlinked rule documentation.
Validated with `just ready`.
AI-assisted.
## Summary
- skip React Compiler transform and lint analysis for `node_modules` by default
- let explicit transform `sources` allowlists opt dependencies back in
- document the behavior and add regression coverage
## Validation
- focused Oxlint and transform-react checks
- Clippy with warnings denied
- `just ready` reached the all-features suite; three Oxlint ANSI-color snapshots differed in this environment
AI assistance: Codex was used to implement and verify this change.
Replaces the 639-arm known-global string match with a sorted static table and binary search. The table is guarded for sortedness, uniqueness, and representative lookups.
Release `oxlint`: 12,491,264 → 12,474,736 bytes (−16,528 bytes, −0.13%); `__text` is reduced by 29,252 bytes.
Prepared with AI assistance.
An unused addition can be side-effect-free even when constant folding keeps it. This happens when replacing the expression with its exact constant value would make the output longer.
For example, constant folding correctly keeps `0.1 + 0.2` instead of expanding it to `0.30000000000000004`. But when the result is unused, the whole expression can be removed.
This PR checks the existing side-effect analysis before running the string-addition cleanup. It removes the whole addition when it is safe. Additions that can run code or throw still use the existing cleanup and are preserved when needed.
Tests cover both the removable numeric addition and an addition containing `foo()` that must stay.
Verified with the full `oxc_minifier` test suite (652 passed, 34 ignored), Clippy, formatting, minsize, and allocation checks. Minsize and allocation snapshots are unchanged.
AI-assisted by OpenAI Codex.
Remove an unreachable React Compiler diagnostic for colons in JSX attribute identifiers. Oxc's parser represents namespaced attributes with `JSXNamespacedName`, so parser-produced identifiers cannot contain colons.
Validated with `cargo test -p oxc_react_compiler`. `just ready` passed formatting and workspace checks, but its full suite hit environment-sensitive ANSI snapshot mismatches in unrelated Oxlint CLI tests.
AI-assisted; reviewed and validated by the contributor.
## Summary
- avoid reporting forwarding constructors that declare TypeScript parameter properties
- share the modifier and decorator check across base and derived constructors
- cover private, public, protected, readonly, and combined parameter-property variants
Closes#25806
Generate `RuleEnum::to_configuration` arms only for the 33 rules that override the trait default, returning `None` for all other rules.
Release `oxlint`: 12,491,264 → 12,491,200 bytes (-64 bytes). `__text`: 10,589,512 → 10,585,376 bytes (-4,136 bytes).
AI-assisted; reviewed and validated by the contributor.
Oxc and Rolldown currently duplicate the N-API conversion between a JavaScript `RegExp` and owned Rust data.
This moves that conversion to `oxc_napi::JsRegExp`. It copies `source`, `flags`, and `lastIndex`, supports converting back to a JavaScript `RegExp`, and keeps regex compilation in each consumer. `oxc_minify_napi::JsRegExp` remains available as a re-export.
This is a good place to put since Rolldown already used `oxc_napi` and crate is exactly for napi related struct
Add a shared non-generic JS-style token update entry point so `oxc_linter` and `oxlint` do not each instantiate the ESTree token visitor.
On `aarch64-apple-darwin`, `cargo build -p oxlint --release --features allocator` reduces the `oxlint` binary by 49,616 bytes (48.5 KiB, 0.39%), from 12,756,960 to 12,707,344 bytes.
Validated with `just ready`.
AI assistance was used for implementation and measurement.
Statement transforms still use `take_in` after popping or consuming their parent nodes. Removing those dummies is less mechanical because references from discarded branches and pass mutations must remain accounted for.
Move the owned statement fields directly, centralize the shared return/throw conditional rewrite, and use explicit dropped-subtree or mutation reporting at each ownership boundary. The adjacent-`if` rewrite also uses the closure-based replacement API introduced at the bottom of this stack.
Relative to its parent, the tracked allocation fixtures record 2,039 fewer arena allocations and 31,552 fewer arena bytes. Across the complete stack, the improvement is 25,252 arena allocations and 404,352 arena bytes. Minsize output is unchanged.
Validated with `cargo test -p oxc_minifier`, `just minsize`, `cargo clippy -p oxc_minifier -- -D warnings`, `just fmt`, and `git diff --check`.
AI assistance was used for research, implementation, review, and testing. I reviewed and take responsibility for the changes.
Several peephole transforms call `take_in` after removing or consuming the parent AST node. At that point there is no borrowed slot to preserve, so allocating a dummy replacement is unnecessary.
Move those already-owned child nodes directly in the straightforward expression and declaration cases. This second branch stays intentionally mechanical and leaves the statement/reference-bookkeeping cases to the final PR in the stack.
Relative to its parent, the tracked allocation fixtures record 22,957 fewer arena allocations and 370,544 fewer arena bytes. Minsize output is unchanged.
Validated with `cargo test -p oxc_minifier`, `just minsize`, `cargo clippy -p oxc_minifier -- -D warnings`, `just fmt`, and `git diff --check`.
AI assistance was used for research, implementation, review, and testing. I reviewed and take responsibility for the changes.
`replace_expression` currently makes callers extract the old value before constructing its replacement, leaving an arena-backed dummy node behind.
Add a closure-based replacement path that owns the old expression and records the AST mutation. Its dropped-subtree contract remains explicit: callers report discarded subtrees, while values moved into the replacement stay live. Convert the logical-not unwrapping sites whose discarded wrappers contain no references.
This is the foundation of a three-PR Graphite stack. The tracked allocation fixtures record 256 fewer arena allocations and 2,256 fewer arena bytes. Minsize output is unchanged.
Validated with `cargo test -p oxc_minifier`, `just minsize`, `cargo clippy -p oxc_minifier -- -D warnings`, `just fmt`, and `git diff --check`.
AI assistance was used for research, implementation, review, and testing. I reviewed and take responsibility for the changes.
Refactors `try_minimize_if` to improve clarity:
- restructures the function around `alternate` presence rather than
`consequent` type
- removes a recursive `Self::try_minimize_if` call — the fallthrough
after branch-flip achieves the same result
- this also removes need for code duplication for inlining expressions
to `||` or `&&`
- `if (!a) {} else b();` → `a && b();`
- `if (!a) b();` → `a || b();`
- `if (a) {} else b();` → `a || b();`
- `if (a) b();` → `a && b();`
- we also do not have to always call for `wrap_to_avoid_ambiguous_else`
and we can do that after we update code (eg, after rotation, and never
when we convert it to expression)
----------------------
#### changes in stack:
- https://github.com/oxc-project/oxc/pull/25267
- https://github.com/oxc-project/oxc/pull/25178👈
- `main`
Three sorts pass a comparator that recomputes a derived key on every comparison. A sort instantiation expands to about eight functions — `quicksort`, `heapsort`, `small_sort_general`, `median3_rec`, `bidirectional_merge`, … — and the comparator is inlined into each of them, so an expensive key is duplicated eight times over and costs several KiB per call site:
- `OxlintRules::override_rules` sorted errors by `ToString::to_string`, which allocates a `String` and pulls the whole `Display` impl into the sort.
- `LintIgnoreMatcher::new` sorted nested configs by `Path::components().count()`.
- The `sort_imports` member fixer sorted specifiers by `cow_to_ascii_lowercase()`.
`sort_by_cached_key` computes each key once, up front, and sorts those.
For `sort_imports` the resulting order is identical: itertools' `sorted_by` and `sorted_by_cached_key` are both stable sorts (`Vec::sort_by` / `Vec::sort_by_cached_key`). The other two go from an unstable sort to a stable one, so entries with an equal key keep their input order instead of an arbitrary one. Both of those sort for deterministic output in the first place, so that is a small improvement rather than a change in behavior.
### Size
Release `oxlint`, `__text`: 10,582,632 → 10,553,076 bytes — **-29,556 bytes (-0.28%)**; stripped binary -33,024 bytes.
Where it comes from:
| call site | before | after | delta |
| --- | ---: | ---: | ---: |
| `override_rules` (`OverrideRulesError`) | 14,656 B / 11 symbols | 656 B / 4 symbols | -14,000 |
| `sort_imports` member fixer | 28,896 B / 18 symbols | 9,108 B / 11 symbols | -19,788 |
| `LintIgnoreMatcher::new` | 11,648 B / 10 symbols | 2,700 B / 3 symbols | -8,948 |
(The per-call-site figures cover each site's whole symbol group, so they overlap where a sort shares a monomorphization; `core::slice::sort::*` overall goes from 379,100 to 348,136 bytes.)
Validated with `cargo test -p oxc_linter -p oxlint` and `cargo clippy` with warnings denied.
AI assistance was used for implementation and measurement.
Share a non-generic JSON deserialization entry point across `oxc_linter` and `oxlint`, avoiding duplicate monomorphizations. Also deserialize well-known settings without deep-cloning the raw JSON value.
Validated with `just ready`.
AI assistance was used for implementation and measurement.
Enable React Compiler exhaustive effect dependency validation in Oxlint so the rule reports missing and extra dependencies instead of remaining inert.
Validated with `just ready`.
AI-assisted.
#25765 routed rule configuration parsing through `DefaultRuleConfig::from_value`, which deserializes from `&serde_json::Value`. Two call sites were missed and still went through `serde_json::from_value`, which instantiates the owned-`Value` deserializer for those configuration types on top of the borrowed-`Value` one every other rule uses:
- `react_perf_from_configuration`, shared by the `react_perf` rules.
- `ConsistentTestItConfig::from_configuration`, shared by the jest and vitest `consistent-test-it` rules. This one also cloned the configuration value before parsing it; deserializing by reference drops the clone.
### Size
Release `oxlint`, `__text`: **-2,072 bytes** — `consistent_test_it` 5,784 → 3,760 bytes (its `TestCaseName` owned-`Value` deserializer goes away entirely) and `react_perf` 10,004 → 9,956 bytes. The stripped binary comes out the same size, as a saving this small falls inside existing padding.
Mostly a consistency fix, then, rather than a size win on its own.
Validated with `cargo test -p oxc_linter` and `cargo clippy` with warnings denied.
AI assistance was used for implementation and measurement.
Improve `react/no-deriving-state-in-effects` diagnostics with labeled state updates, named reactive dependencies, and actionable render guidance. Adds fixture coverage for single and multiple dependencies.
AI assistance was used for this change.
## Summary
- skip prefer-mock-return-shorthand when the returned expression references this
- reuse the existing return-expression traversal without adding another AST pass
- cover the reported typed this parameter and mockImplementationOnce arrow callback cases
Closes#25796
Closes#25339.
## The problem
`no-redeclare` gated the entire rule on the file not being an ES module:
```rust
fn should_run(&self, ctx: &ContextHost) -> bool {
// ES modules run in their own scope, and don't conflict with existing globals
!ctx.source_type().is_module()
}
```
The comment justifies the globals half of the rule, and it is right
about that: an ES module has its own top-level scope, so declaring
`Object` or `self` there shadows nothing, which is why ESLint reports
`builtinGlobals` redeclarations against the global scope rather than
inside a module. But the gate took the rest with it — plain `var a = 3;
var a = 10;`, redeclarations in nested scopes, and the TS type/value
collision check added for #10396 all stopped running too.
**One correction to the issue's framing, from testing it rather than
reading it.** `.ts` is parsed as `ModuleKind::Unambiguous`, which
resolves to `Module` only when ESM syntax is actually present. So a
`.ts` file with no `import`/`export` is a script, and the rule *did* run
there — `var a = 3; var a = 10;` on its own is reported today. What was
dead is every `.ts` file that contains an import or an export, which in
practice is nearly all of them. The effect the issue describes is real;
the boundary is ESM syntax, not the extension.
The rule's own tests hid this either way. Every failing case runs under
`.change_rule_path_extension(".cts")` — CommonJS, never a module — and
the single `.ts` block asserts a *pass*, which it would do whether or
not the rule executed.
## The change
Drop `should_run`, and narrow the exemption to the thing the comment
actually describes:
```rust
// ES modules run in their own scope, so a top-level `Object` or `self` shadows nothing.
// Only the globals half of the rule is skipped for them -- redeclaring a local binding is
// still a redeclaration.
let builtin_globals = if self.builtin_globals && !ctx.source_type().is_module() {
Some(&GLOBALS_BUILTIN)
} else {
None
};
```
`builtin_globals` is already the single switch for that half — it drives
`is_builtin`, which chooses between
`no_redeclare_as_builtin_in_diagnostic` and the plain redeclaration
diagnostic — so `None` in modules disables exactly the globals
reporting, for the builtin table and user-configured `globals` alike,
and leaves both redeclaration loops running.
## Tests
A new `.ts` block under the `es-modules` snapshot suffix. Every case
carries ESM syntax so it resolves as a module — otherwise it would test
the script path by accident, which is the trap above:
- **pass** — `export {}; var Object = 0;` and `export {}; var globalThis
= 0;` (a module shadows nothing, so these must stay quiet), plus a
redeclaration-free case and a TS overload pair.
- **fail** — `export {}; var a = 3; var a = 10;`; `export {}; function
f() { var a; var a; }` (nested scope — nothing to do with global scope
at all, and previously silent); the #10396 `type foo = 1; export
function foo(): void; …` case; and `export {}; var Object = 0; var
Object = 0;`.
That last one is the seam this change creates, so it is worth pinning:
inside a module the first `var Object` is no longer reported as
shadowing a builtin, but the second is still reported as a redeclaration
of the first. Without it, narrowing the gate could quietly have turned
builtin-named symbols into a blind spot.
The existing `.cts` blocks and their snapshot are untouched — `.cts` is
CommonJS, so `is_module()` was already false there.
## Verification
Ran locally with `cargo test -p oxc_linter --lib no_redeclare`: passes,
the existing `eslint_no_redeclare.snap` is unchanged, and the new
`eslint_no_redeclare@es-modules.snap` is included. `cargo clippy -p
oxc_linter --lib` is clean.
> AI disclosure, per the contributing policy: I used an AI assistant
while investigating and writing this. I have read and understand the
change, ran the tests myself, and stand behind it.
---------
Co-authored-by: Cameron <cameron.clark@hey.com>
## Summary
- mark `unicorn/prefer-default-parameters` as suggestion-only
- prevent `--fix` from changing behavior for `null` and other falsy values
Closes#25799
## Summary
- represent variadic rule options as a severity followed by zero or more
option values
- regenerate the Oxlint configuration schema and TypeScript declarations
- add a type-level regression for mapped options spread into
`no-restricted-globals`
## Root cause
The schema wrapper materialized the first `additionalItems` entry as a
required tuple element and set `minItems` to 2. A dynamic TypeScript
spread has type `T[]` and may be empty, so it cannot satisfy that
required position even though the severity-only form is already valid
through `RuleNoConfig`.
Keeping severity as the only fixed tuple item and leaving the rule
options in `additionalItems` generates `[severity, ...options]`, which
accepts both an empty spread and populated spreads without changing
runtime rule behavior.
Closes#25666
## AI assistance
Implemented with assistance from OpenAI Codex. The contributor remains
responsible for reviewing, understanding, and submitting the change
under the repository AI usage policy.
---------
Co-authored-by: Cameron <cameron.clark@hey.com>
Use compact `Display` formatting for React Compiler terminals and reuse `ConfigBuilderError`'s existing `Display` implementation for `Debug`.
This reduces the release `oxlint` binary from 12,773,552 to 12,740,432 bytes: **-33,120 bytes (-0.26%)**, with `__text` reduced by 24,452 bytes.
Validated with the affected crate tests, workspace checks, and oxlint snapshot tests.
AI assistance was used for implementation and measurement.
## Summary
- classify typescript/no-unnecessary-type-conversion as suggestion-only
- prevent its runtime-changing removal from being advertised as a normal autofix
- keep TSGolint RuleSuggestion edits available through suggestion handling
Related to #25549.
## Summary
- anchor switch/if missing-return diagnostics on the array callback function head, matching ESLint
- preserve the inner control-flow statement as a secondary diagnostic label
- add regression coverage for diagnostic location and eslint-disable-next-line behavior
Fixes#25632
## Summary
- emit `any | undefined` for default-initialized `any` parameters followed by required parameters
- add a regression fixture for #25290 and update the existing parameter snapshot
- preserve the existing handling of `unknown`
Closes#25290
Switches order-independent sorts to unstable sorting and avoids cloning rule-table plugin names.
Reduces the stripped `oxlint` release binary from 12,773,568 to 12,757,040 bytes: 16,528 bytes (0.13%).
Validated with `cargo test -p oxc_linter` and focused oxlint JSON checks.
AI assistance was used for analysis and implementation.