Commit Graph

930 Commits

Author SHA1 Message Date
oxc-guard b4da00b621 release(apps): oxlint v1.82.0 && oxfmt v0.67.0 (#26384)
# Oxlint
### 🚀 Features

- 6a0e19c linter/eslint/no-unmodified-loop-condition: Support `checkConditionalExpressions` option (#26249) (camc314)

### 🐛 Bug Fixes

- 562dd14 jsx-a11y/anchor-has-content: Allow anchors passed as custom component props (#26360) (Mikhail Baev)
- 253cdb2 linter/eslint/id-length: Exempt TS interface/type-literal members with never (#26310) (Pearce Ropion)
- 8c7ea76 ast_visit: Account for trimmed source offsets (#26223) (Cameron)
- 5f9cffc linter/typescript/no-explicit-any: Fix rest parameter to `unknown[]` (#26279) (camc314)
- 4de9fa3 linter/react/jsx-no-literals: Check nested JSX expression literals (#26253) (camc314)
- 07851b9 parser: Fix debug assert failure when lexer error with tokens enabled (#26229) (overlookmotel)
- 9cee146 oxlint/lsp: Don't try to parse fix message, always fallback (#26204) (Sysix)
- a662c40 linter/eslint/no-useless-assignment: Handle destructuring assignments (#25925) (camc314)
- 304bd9a linter/eslint/no-array-constructor: Handle ASI hazards in fixer (#26166) (Hamody We)
- b41bb35 linter: Qualify rules in rules output (#26250) (camc314)
- 895c685 linter/typescript/no-extraneous-class: Avoid deleting class expressions (#26231) (camc314)
- 4ba33c8 linter/eslint/no-unused-vars: Handle stored arrow references (#26225) (camc314)

### 🛡️ Security

- 9a612d5 deps: Update npm packages (#26178) (renovate[bot])
# Oxfmt
### 💥 BREAKING CHANGES

- 2c9a947 parser: [**BREAKING**] Reduce `MAX_LEN` to 256 bytes below `u32::MAX` (#26352) (overlookmotel)

### 🚀 Features

- 68e12ab formatter_css: Follow the oxc-css-parser's acceptance line (#26337) (leaysgur)

### 🐛 Bug Fixes

- f7acdc0 formatter: Treat a JSDoc cast target as opaque in chain layouts (#26375) (leaysgur)
- 104061b formatter: Keep JSDoc cast parens with a comment inside them (#26374) (leaysgur)
- 3d00a76 formatter_css: Keep comment inside important and simple-vars colon (#26370) (leaysgur)
- 172ddb6 formatter_css: Keep a same-line line comment on its line (#26321) (leaysgur)
- cafaf32 formatter_css: Never drop comments inside an at-rule prelude (#26320) (leaysgur)
- 534a0fe formatter_css: Keep a line comment on its comma's line (#26319) (leaysgur)
- 99cfd75 formatter_css: Hide raw comment printing API, use strcut instead (#26316) (leaysgur)
- 2028896 formatter_css: Preserve comments around SCSS/Less variable values (#26276) (leaysgur)
- 6752abc formatter_css: Keep leading comments before (#26272) (leaysgur)
- 3b054de formatter_graphql: Align comment printing after open `{` (#26271) (leaysgur)
- b3c287a formatter_css: Fix SCSS bracket list printing (#26270) (leaysgur)
- bac770a formatter_css: Preserve comment in SCSS paren comma list (#26269) (leaysgur)
- c7b57ef formatter_css: Print SCSS map consisntent with and without comment (#26268) (leaysgur)
- 063e2b6 formatter_css: Preserve trailing comma in single-item scss lists (#26245) (leaysgur)
- 5f9580d oxfmt: Bump prettier-plugin-tailwindcss (#26273) (leaysgur)

### ⚡ Performance

- 1cad286 oxfmt: Match editorconfig once per file (#26239) (Yuji Sugiura)
- 260c5eb oxfmt: Match `overrides` once per file (#26238) (leaysgur)
- 61565bc oxfmt: Share resolved `FormatConfig` via `Arc` instead of cloning per file (#26237) (leaysgur)

### 📚 Documentation

- 32084d4 formatter_core: Clarify printer hard_line compression (#26312) (leaysgur)
- 4fabdcc formatter,formatter_css,formatter_graphql,formatter_yaml: Update DIVERGENCES.md (#26267) (leaysgur)
- 26a1fa4 formatter_core: Refine FORMATTER_POLICY (#26266) (leaysgur)

### 🛡️ Security

- 9a612d5 deps: Update npm packages (#26178) (renovate[bot])
2026-09-07 14:13:57 +00:00
camc314 aa38ddfbea fix(linter/unicorn/numeric-separators-style): correct schema defaults (#26393)
## Summary

Fix the generated defaults for `unicorn/numeric-separators-style`. The rule already uses `number.minimumDigits: 5`, matching Unicorn, but the generated documentation and JSON schema advertise `0`. The same schema issue also advertises `groupLength: 0` for every numeric base.

## Why the defaults are wrong

`NumericBaseConfig` is shared by binary, hexadecimal, octal, and decimal configuration. Its derived `Default` initializes both numeric fields to zero. The rule supplies the actual defaults in `NumericSeparatorsStyleConfig::default()` and `NumericNumberConfig::default()`.

Schema generation uses the shared type's defaults for its individual properties. In particular, flattening `NumericBaseConfig` into `NumericNumberConfig` preserves the zero-valued property defaults instead of the decimal defaults. This makes the documented threshold disagree with the rule's existing behavior:

```js
1234;   // Allowed with the default configuration.
12345;  // Reported; the fix is 12_345.
```

## Change

Add a single parameterized schema helper for `NumericBaseConfig`, then select the appropriate defaults with `schemars(schema_with = ...)` on each field. The helper retains the derived schema's property descriptions, types, and constraints, and overrides only the `groupLength` and `minimumDigits` default metadata.

The resulting defaults are:

| Configuration | `groupLength` | `minimumDigits` |
| --- | --- | --- |
| `binary` | 4 | 0 |
| `hexadecimal` | 2 | 0 |
| `octal` | 4 | 0 |
| `number` | 3 | 5 |

The schema annotation on the flattened decimal base also corrects `number.minimumDigits`. `number.fractionGroupLength` remains unchanged, and the documentation continues to display its default as `Infinity`.

Regenerate the JSON configuration schema and the TypeScript configuration types from it. The generated TypeScript types inline the binary, hexadecimal, and octal option objects because those properties now have individual schemas; their accepted configuration shapes are unchanged.

This changes schema and documentation metadata only. Runtime defaults, option parsing, diagnostics, and autofixes are unchanged.

Fixes #26391
2026-09-07 13:48:04 +00:00
renovate[bot] 8dd81f9bb8 chore(deps): update dependency @napi-rs/cli to v3.9.0 (#26256)
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Adoption](https://docs.renovatebot.com/merge-confidence/) |
[Passing](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|---|---|
| [@napi-rs/cli](https://napi.rs/)
([source](https://redirect.github.com/napi-rs/napi-rs)) | [`3.8.6` →
`3.9.0`](https://renovatebot.com/diffs/npm/@napi-rs%2fcli/3.8.6/3.9.0) |
![age](https://developer.mend.io/api/mc/badges/age/npm/@napi-rs%2fcli/3.9.0?slim=true)
|
![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@napi-rs%2fcli/3.9.0?slim=true)
|
![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@napi-rs%2fcli/3.8.6/3.9.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@napi-rs%2fcli/3.8.6/3.9.0?slim=true)
|

---

> [!WARNING]
> Some dependencies could not be looked up. Check the warning logs for
more information.

---

### Release Notes

<details>
<summary>napi-rs/napi-rs (@&#8203;napi-rs/cli)</summary>

###
[`v3.9.0`](https://redirect.github.com/napi-rs/napi-rs/compare/@napi-rs/cli@3.8.6...@napi-rs/cli@3.9.0)

[Compare
Source](https://redirect.github.com/napi-rs/napi-rs/compare/@napi-rs/cli@3.8.6...@napi-rs/cli@3.9.0)

</details>

---

### Configuration

📅 **Schedule**: (in timezone Asia/Shanghai)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/oxc-project/oxc).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC41Ny4zIiwidXBkYXRlZEluVmVyIjoiNDQuNjEuMyIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Cameron <cameron.clark@hey.com>
2026-09-04 14:22:16 +00:00
camc314 6a0e19cfaa feat(linter/eslint/no-unmodified-loop-condition): support checkConditionalExpressions option (#26249)
## Summary

- add the ESLint-compatible `checkConditionalExpressions` option to `no-unmodified-loop-condition`, defaulting to `false`
- port tests added by eslint/eslint#21175 and add regression coverage for repeated references within and across binary groups

Closes #26182.
2026-09-02 10:39:45 +00:00
oxc-guard 0b4e2e67f4 release(apps): oxlint v1.81.0 && oxfmt v0.66.0 (#26199)
# Oxlint
### 🚀 Features

- 60b945d linter/nextjs/no-typos: Implement suggestion (#26091) (Mikhail Baev)

### 🐛 Bug Fixes

- 33ac4b0 linter/lsp: Prevent tsgolint from holding onto processes (#25570) (Adrian Schaedle)
- baf4b1e linter/import/no-empty-named-blocks: Make empty value import removal a suggestion (#26155) (camc314)
- 77cfaec linter/eslint/object-shorthand: Preserve `__proto__` semantics (#26154) (camc314)
- fa3c082 linter/unicorn/prefer-set-size: Ignore shadowed `Set` constructors (#26153) (camc314)
- e412cf2 linter: Clamp invalid JS plugin locations (#26144) (camc314)
- d86c113 linter: Normalize reversed JS plugin locations (#26138) (camc314)
- 73c09b2 linter/eslint/no-use-before-define: Run on JS, JSX files (#26114) (camc314)
- 03ef0f2 linter/unicorn/no-useless-spread: Treat typed arrays as a distinct value hint (#26067) (Aadharsh  Pannirselvam)
- bd15905 linter/react/no-unstable-nested-components: Check nested component object property names (#26101) (camc314)
- 3910e2b linter/eslint/no-unassigned-vars: Skip Svelte and Vue files (#26042) (Hamody We)
- 047f7ca linter/plugins: Fix interaction between JS plugins and Vue rules (#26080) (overlookmotel)
- 8531b9b linter/plugins: Alter method for obtaining mutable `Program` when sending AST to JS plugins (#26077) (overlookmotel)
- dc464ff linter/unicorn/prefer-math-min-max: Avoid unsafe autofix (#26060) (camc314)

### 📚 Documentation

- 464ddd1 linter: Support a shared short description for jest/vitest rules (#26186) (connorshea)
- 9db5ad3 linter: Add short description to `vue/no-dupe-keys` (#26183) (connorshea)
- db66f58 linter: Correct export/import mismatch in bar and foo example (#25927) (billychannnnnn)
- d5be037 linter/typescript/switch-exhaustiveness-check: Clarify default case comment pattern (#26100) (camc314)
# Oxfmt
### 🚀 Features

- 1fb37b6 formatter/css: Format declaration-shaped raw-prelude rules (postcss nested config blocks) (#26194) (leaysgur)

### 🐛 Bug Fixes

- 57e8e22 formatter_css: Space a folded sign after a call in Less operations (#26134) (leaysgur)
- e4298fb formatter/jsdoc: Follow CommonMark for interrupting lists and guard wrapping from creating them (#26098) (leaysgur)
- a1e21c2 formatter: Apply head body policy everywhere (#26074) (leaysgur)
- 676b7e1 formatter: Keep comments in their for-head slot, before an empty-statement body and do-while (#26073) (leaysgur)
- 3bbcea6 formatter: Keep comments between a head and its body out of the braces across all constructs (#26071) (leaysgur)
- 57537a2 formatter: Place comments between a head and open paren (#26058) (leaysgur)
- e2d53e7 formatter: Place comments between a statement head and its body (#26043) (leaysgur)
- 662556c formatter: Print the idempotent placement for comments in dropped parens (#26041) (leaysgur)
- faf11d9 formatter_yaml: Keep trailing whitespace in block scalars (#26072) (leaysgur)

### ⚡ Performance

- ac4785a diagnostics: Use fixed ANSI styles (#26130) (Boshen)

### 📚 Documentation

- b879608 formatter,formatter_graphql,formatter_yaml: Annotate own-line comment inlining as known policy violation (#26131) (leaysgur)
- 181953b oxfmt,formatter_core,formatter,formatter_yaml,formatter_css,formatter_graphql: Extract `DIVERGENCES.md` out from `AGENTS.md` (#26121) (leaysgur)
- a67cb9d formatter,formatter_core: Document comment moving policy (#26075) (leaysgur)
- fc175b0 formatter_core: Clarify idempotency test infra (#26069) (leaysgur)
2026-09-01 08:25:16 +00:00
Yuji Sugiura cd00a2c635 chore(oxlint): regenerate config types by cargo lintgen (#26195)
Follow up on #26193. (Also fixes main CI failures)

`json-schema-to-typescript`: `^15.0.4` → `^16.0.0` changed the output.
2026-08-31 13:25:13 +09:00
camc314 d5be0375e6 docs(linter/typescript/switch-exhaustiveness-check): clarify default case comment pattern (#26100)
## Summary
- clarify that `defaultCaseCommentPattern` recognizes a trailing comment in place of an omitted `default` clause
- document the required location, absence of a live `default`, and the `considerDefaultExhaustiveForUnions` requirement for union switches
- regenerate the JSON schema and TypeScript configuration types

Fixes #26087
2026-08-26 08:14:27 +00:00
oxc-guard 97e99b8548 release(apps): oxlint v1.80.0 && oxfmt v0.65.0 (#26045)
# Oxlint
### 🚀 Features

- 70c3e35 linter/typescript/no-confusing-non-null-assertion: Implement suggestion (#26012) (Mikhail Baev)

### 🐛 Bug Fixes

- 8a353a7 linter/eslint/no-control-regex: Refine help message text (#25996) (Rahul Mishra)
- 8a9bdbd estree: Include decorators in `FormalParameterRest ` spans (#26021) (camc314)
- 8d94cd1 linter/eslint/no-useless-rename: Preserve type modifiers (#26020) (Cameron)
- 2cde1f6 rust: Address nightly deprecations (#25998) (Boshen)
- 51d36d7 linter/vue: Resolve `vue` imports via shared import helpers (#25903) (Connor Shea)
- 83a68d2 linter/react/no-react-children: Resolve `react` imports by symbol (#25901) (Connor Shea)
- 124e196 linter: Resolve globals by reference, not by name (#25905) (Connor Shea)
- a701bcc linter: Remove invalid React compiler doc links (#25900) (Boshen)

### 📚 Documentation

- 9b7e153 linter: Set `version` to 1.79.0 for rules shipped in 1.79.0 (#25902) (connorshea)
# Oxfmt
### 🐛 Bug Fixes

- bf37dd5 formatter: Preserve class decorators before export when the statement is suppressed (#26034) (leaysgur)
2026-08-24 11:33:15 +00:00
camc314 8a9bdbd6d8 fix(estree): include decorators in FormalParameterRest spans (#26021)
Serialize `FormalParameterRest` with its outer span so its range includes parameter decorators. Regenerate the raw-transfer deserializers and remove `sourceMapValidationDecorators.ts` from the ESTree mismatch baseline.

Fixes #26011.
2026-08-23 18:32:30 +00:00
renovate[bot] 32c2675084 chore(deps): update rust crates (#26024)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[javascript-globals](https://redirect.github.com/oxc-project/javascript-globals)
| workspace.dependencies | minor | `1.5.2` → `1.6.0` |
| [papaya](https://redirect.github.com/ibraheemdev/papaya) |
workspace.dependencies | patch | `0.2.4` → `0.2.5` |
| [saphyr](https://redirect.github.com/saphyr-rs/saphyr) |
workspace.dependencies | patch | `0.0.11` → `0.0.12` |
| [similar](https://redirect.github.com/mitsuhiko/similar) |
workspace.dependencies | minor | `3.1.2` → `3.2.0` |

---

### Release Notes

<details>
<summary>oxc-project/javascript-globals (javascript-globals)</summary>

###
[`v1.6.0`](https://redirect.github.com/oxc-project/javascript-globals/blob/HEAD/CHANGELOG.md#160---2026-08-18)

[Compare
Source](https://redirect.github.com/oxc-project/javascript-globals/compare/javascript-globals-v1.5.2...javascript-globals-v1.6.0)

##### Added

- add Bun globals
([#&#8203;275](https://redirect.github.com/oxc-project/javascript-globals/pull/275))

##### Other

- reduce Rust dev debug info
([#&#8203;271](https://redirect.github.com/oxc-project/javascript-globals/pull/271))

</details>

<details>
<summary>ibraheemdev/papaya (papaya)</summary>

###
[`v0.2.5`](https://redirect.github.com/ibraheemdev/papaya/releases/tag/v0.2.5):
0.2.5

[Compare
Source](https://redirect.github.com/ibraheemdev/papaya/compare/v0.2.4...v0.2.5)

- Added the `fast-barrier` feature to allow opting out of process wide
memory barriers, which can be expensive to initialize
([#&#8203;100](https://redirect.github.com/ibraheemdev/papaya/pull/100)).
- Fixed a bug where blocking resizes could lead to deadlocks
([#&#8203;92](https://redirect.github.com/ibraheemdev/papaya/pull/92)).
- `HashSet::retain` no longer takes a mutable reference
([#&#8203;101](https://redirect.github.com/ibraheemdev/papaya/pull/101)).

</details>

<details>
<summary>saphyr-rs/saphyr (saphyr)</summary>

###
[`v0.0.12`](https://redirect.github.com/saphyr-rs/saphyr/compare/v0.0.11...v0.0.12)

[Compare
Source](https://redirect.github.com/saphyr-rs/saphyr/compare/v0.0.11...v0.0.12)

</details>

<details>
<summary>mitsuhiko/similar (similar)</summary>

###
[`v3.2.0`](https://redirect.github.com/mitsuhiko/similar/blob/HEAD/CHANGELOG.md#320)

[Compare
Source](https://redirect.github.com/mitsuhiko/similar/compare/3.1.2...3.2.0)

- Added structured, line-oriented three-way merging through `TextMerge`,
with
merge and diff3 conflict output, configurable labels and marker sizes,
owned
and borrowed inputs, byte output, and whitespace-insensitive comparison.
- Added `WhitespaceMode` and `TextDiffConfig::whitespace_mode` for
Git-style
line comparisons that ignore changes in whitespace (`-b`) or all
whitespace
  (`-w`).
- Changed `Algorithm::Myers` to reduce unmatched/confusing records and
use
  Git-style bounded, non-minimal splits on expensive searches, and added
`Algorithm::RawMyers` for the previous shortest-edit-script behavior
without
  output-changing heuristics.
- Improved heuristics and performance for most algorithms other than
LCS.
- Improved large-input performance by avoiding quadratic Histogram
scans.

</details>

---

### Configuration

📅 **Schedule**: (in timezone Asia/Shanghai)

- Branch creation
  - "before 10am on monday"
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/oxc-project/oxc).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zOS4wIiwidXBkYXRlZEluVmVyIjoiNDQuMzkuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Cameron Clark <cameron.clark@hey.com>
2026-08-23 17:02:20 +00:00
Boshen 1193c9dbaf chore(oxfmt): dogfood operator position at line start (#25937)
dogfood
2026-08-20 14:36:47 +00:00
oxc-guard[bot] 0db127cc16 release(apps): oxlint v1.79.0 && oxfmt v0.64.0 (#25866)
# Oxlint
### 💥 BREAKING CHANGES

- 8c4552d linter: [**BREAKING**] Split react/react-compiler into
per-category rules (#25500) (Boshen)

### 🚀 Features

- 9b7394e linter/typescript/no-empty-object-type: Implement suggestion
(#25833) (Mikhail Baev)

### 🐛 Bug Fixes

- 345f981 react_compiler: Skip node_modules by default (#25859) (Boshen)
- 2f40afa linter/unicorn/no-array-callback-reference: Ignore effect
library imports (#25857) (Michaël Bitard)
- 7b565a0 linter: Align React Compiler rule categories (#25840) (Boshen)
- 228e8e0 linter: Resolve inactive React compiler rules (#25830)
(Boshen)
- f8e4884 linter/eslint/no-useless-constructor: Allow parameter
properties (#25811) (camc314)
- e4b6993 linter: Report exhaustive effect dependencies (#25829)
(Boshen)
- 742e25f linter/eslint/no-return-assign: Anchor diagnostic on return
stmt (#25803) (camc314)
- b831ca8 react-compiler: Improve derived state diagnostic (#25804)
(Boshen)
- 5908c87 linter/jest/prefer-mock-return-shorthand: Preserve
implementations using this (#25802) (camc314)
- f6b2265 linter/eslint/no-redeclare: Run in ES modules, skipping only
the globals check (#25691) (Hamody We)
- ca9f553 linter/unicorn/prefer-default-parameters: Mark fixer as a
suggestion (#25801) (camc314)
- aa49d86 linter: Allow spread rule options in config types (#25675)
(ch3rry)
- d5483f8 linter/typescript/no-useless-empty-export: Skip TS declaration
files (#25789) (Evyatar Daud)
- 57f2199 linter/typescript/no-useless-empty-export: Report after
imports (#25786) (camc314)
- 633bc19 linter/typescript/no-unnecessary-type-conversion: Mark fixer
as `suggestion` (#25787) (camc314)
- dea3339 linter/typescript/explicit-module-boundary-types: Anchor
diagnostics on arrows (#25779) (camc314)
- 5cd6f02 linter/eslint/array-callback-return: Anchor diagnostic on
callback (#25780) (camc314)
- ef8cebf linter/eslint/preserve-caught-error: Handle AggregateError
options (#25775) (camc314)
- c108d5c linter: Improve React Compiler diagnostics (#25742) (Boshen)
- c9ec55e react-compiler: Improve diagnostic spans (#25731) (Boshen)
- 1cbbcb7 linter/unicorn/prefer-string-replace-all: Apply fixes in one
pass (#25709) (Mikhail Baev)
- dec0a86 react-compiler: Standardize diagnostics (#25702) (Boshen)
- 5fd77f7 linter/react/display-name: Report curried HOC inner component
(#25662) (camc314)
- 4dbb80e linter/import/no-named-as-default: Report local export
conflicts (#25658) (camc314)
- e8a7214 linter/react/rules-of-hooks: Report hooks inside try blocks
(#25670) (camc314)
- 36f8451 linter/eslint/no-eval: Align indirect default with ESLint
(#25656) (camc314)
- d901d24 linter/react/exhaustive-deps: Handle destructured object
dependencies (#25669) (camc314)
- beb724d linter/eslint/no-unused-vars: Report bare underscore
parameters (#25663) (camc314)
- fa36f26 linter/react/no-this-in-sfc: Detect this in nested arrow
callbacks (#25653) (camc314)
- 44d1be3 linter/typescript/no-var-requires: Run rule on JavaScript
(#25664) (camc314)
- 4004c10 linter/eslint/no-irregular-whitespace: Check comments by
default (#25660) (camc314)
- 625401d linter/import/no-named-default: Flag type-only named defaults
(#25661) (camc314)
- 8eacb2d linter/typescript/no-non-null-asserted-optional-chain: Detect
assertions after continued optional chains (#25659) (camc314)
- d55b76c linter/react/no-direct-mutation-state: Detect computed state
mutations (#25654) (camc314)
- f92c651 linter/unicorn/no-abusive-eslint-disable: Use directive prefix
in diagnostic (#25657) (camc314)
- ee44996 linter/eslint/max-classes-per-file: Anchor diagnostic at
program start (#25652) (camc314)
- 403ec40 linter/eslint/no-multi-assign: Handle parenthesized declarator
initializers (#25651) (camc314)
- 6c9ba37 linter/jest/expect-expect: Detect assertions in nested
function declarations (#25650) (camc314)
- 285820e linter/no-large-snapshots: Precompile and document allowed
snapshot matchers (#25611) (Mikhail Baev)
- 1be1e20 linter/eslint/prefer-promise-reject-errors: Report on spread
arguments (#25648) (Mikhail Baev)
- a38f7b3 oxlint,oxfmt: Apply .gitignore only to walk targets, not
explicitly named files (#25531) (leaysgur)
- 509931b semantic: Classify global references per identifier (#25608)
(camc314)
- 0c68b7f estree: Emit `decorators` on `FormalParameterRest` (#25582)
(camc314)
- 1d22912 linter/plugins: Parse rule-less directive justifications
(#25559) (camc314)
- eaf80d8 linter/unicorn/prefer-node-protocol: Validate exact Node.js
built-in specifiers (#25558) (camc314)
- 57b94af linter/promise/no-multiple-resolved: Ignore unresolved globals
(#25530) (Tushar Singh)
- 80e64c2 linter/expect-expect: Validate assertion regex (#25504)
(Mikhail Baev)
- 7830604 linter/react/exhaustive-deps: Treat binary expressions as a
stable dependency (#25508) (Hamody We)
- 4df5835 linter: Allow capitalized built-in calls (#25516) (Boshen)
- 9d49d27 react_compiler: Bail out instead of panicking on "Expected a
node for all scopes" (#25506) (Boshen)
- d43b562 linter/vitest/prefer-expect-assertions: Handle parameterized
Vitest assertion suggestions (#25476) (camc314)

### ⚡ Performance

- e8303d6 linter: Shrink rule serialization dispatch (#25818) (Boshen)
- c84ede3 estree_tokens: Share JS token update entry point (#25826)
(Boshen)
- 35c8eb2 linter: Compute sort keys once with sort_by_cached_key
(#25821) (Boshen)
- f0121ed linter: Share config deserialization entry point (#25820)
(Boshen)
- 2dacf7a oxlint: Reduce debug formatting code size (#25797) (Boshen)
- 9ed10b7 linter: Use unstable sorts for unique keys (#25778) (Boshen)
- 63ff8ef linter: Outline diagnostic construction (#25762) (Boshen)
- 2dd7446 diagnostics: Preallocate graphical output (#25721) (Boshen)
- 9c8abab diagnostics: Batch graphical reports (#25710) (Boshen)
- 8e9b95f linter: Use table for rule names (#25458) (Boshen)
# Oxfmt
### 🚀 Features

- c07fe7c oxfmt: Support `experimentalOperatorPosition` (#25643)
(leaysgur)
- 2adb8fb formatter: Implement `operatorPosition` option (#25581)
(leaysgur)

### 🐛 Bug Fixes

- 44231fb formatter: Fix comment and indent issues around unions
(#25665) (leaysgur)
- 2465e87 formatter: Keep comments in place when dropping
`EmptyStatement` (#25730) (leaysgur)
- 7e4f3b7 formatter: Print `JSDocUnknownType` (#25729) (leaysgur)
- 5238d9e formatter: Keep nested awaited-paren member chain grouped in
call arguments (#25646) (leaysgur)
- a38f7b3 oxlint,oxfmt: Apply .gitignore only to walk targets, not
explicitly named files (#25531) (leaysgur)
- 5c0a5ff formatter_css: Fill own-line block comments inside
space-separated values (#25578) (leaysgur)
- 53debfa formatter_css: Keep trailing comma and indent after
comment-preceded last map value (#25577) (leaysgur)
- 1a83a8d oxfmt: Mirror printer line suppression and restore
dedent-to-root (#25573) (leaysgur)
- 7f350d1 formatter: Keep unary comment and print only needed parens
(#25526) (leaysgur)
- f405789 formatter_yaml: Consistent chomped eos behavior (#25523)
(leaysgur)
- a243311 formatter_yaml: Bump oxc-yaml-parser for contentless block
scalar (#25519) (leaysgur)
- 40d38a0 formatter_css: Keep multi value function args intact after
leading comment (#25518) (leaysgur)

### 📚 Documentation

- 223e785 oxfmt/conformance: Update notes on conformance (#25757) (Yuji
Sugiura)
- 673dc6d oxfmt: Move some docs from AGENTS.md to code comment (#25649)
(leaysgur)
- fed6681 oxfmt: Skip expanding overrides options (#25572) (leaysgur)

Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
2026-08-18 22:27:08 +08:00
Boshen 228e8e0f85 fix(linter): resolve inactive React compiler rules (#25830)
Enable React Compiler memo dependency validation so `react/memo-dependencies` reports missing and extra values. Remove `react/gating` until Oxlint exposes compiler gating options.

Validated with `just ready`.

AI-assisted.
2026-08-18 16:16:24 +08:00
ch3rry aa49d86046 fix(linter): allow spread rule options in config types (#25675)
## 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>
2026-08-17 14:11:07 +01:00
renovate[bot] 9c6f1912b5 chore(deps): update rust crates (#25756)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [futures](https://rust-lang.github.io/futures-rs)
([source](https://redirect.github.com/rust-lang/futures-rs)) |
workspace.dependencies | patch | `0.3.33` → `0.3.34` |
| [handlebars](https://redirect.github.com/sunng87/handlebars-rust) |
workspace.dependencies | patch | `6.4.3` → `6.4.4` |
|
[javascript-globals](https://redirect.github.com/oxc-project/javascript-globals)
| workspace.dependencies | patch | `1.5.1` → `1.5.2` |

---

### Release Notes

<details>
<summary>rust-lang/futures-rs (futures)</summary>

###
[`v0.3.34`](https://redirect.github.com/rust-lang/futures-rs/blob/HEAD/CHANGELOG.md#0334---2026-08-11)

[Compare
Source](https://redirect.github.com/rust-lang/futures-rs/compare/0.3.33...0.3.34)

- Preserve cloned waker identity.
([#&#8203;3032](https://redirect.github.com/rust-lang/futures-rs/issues/3032))
- Updato `syn` to 3.
([#&#8203;3028](https://redirect.github.com/rust-lang/futures-rs/issues/3028))

</details>

<details>
<summary>sunng87/handlebars-rust (handlebars)</summary>

###
[`v6.4.4`](https://redirect.github.com/sunng87/handlebars-rust/blob/HEAD/CHANGELOG.md#644---2026-08-12)

[Compare
Source](https://redirect.github.com/sunng87/handlebars-rust/compare/v6.4.3...v6.4.4)

- \[Changed] We have to revert `preserve_json_order` as a default
feature. Users
  who need this can still enable it for handlebars-rust, or enable
  `preserve_order` for you serde\_json.

</details>

<details>
<summary>oxc-project/javascript-globals (javascript-globals)</summary>

###
[`v1.5.2`](https://redirect.github.com/oxc-project/javascript-globals/blob/HEAD/CHANGELOG.md#152---2026-08-13)

[Compare
Source](https://redirect.github.com/oxc-project/javascript-globals/compare/javascript-globals-v1.5.1...javascript-globals-v1.5.2)

##### Other

- Auto update globals from upstream
([#&#8203;268](https://redirect.github.com/oxc-project/javascript-globals/pull/268))
- Auto update globals from upstream
([#&#8203;265](https://redirect.github.com/oxc-project/javascript-globals/pull/265))
- Auto update globals from upstream
([#&#8203;261](https://redirect.github.com/oxc-project/javascript-globals/pull/261))
- *(deps)* update rust crate serde\_json to v1.0.151
([#&#8203;259](https://redirect.github.com/oxc-project/javascript-globals/pull/259))
- *(deps)* update rust crate serde to v1.0.229
([#&#8203;256](https://redirect.github.com/oxc-project/javascript-globals/pull/256))
- update sponsor section
- *(deps)* update rust crate rustc-hash to v2.1.3
([#&#8203;247](https://redirect.github.com/oxc-project/javascript-globals/pull/247))
- standardize rustfmt config
- normalize README sponsor section
- add crates environment to release workflow

</details>

---

### Configuration

📅 **Schedule**: (in timezone Asia/Shanghai)

- Branch creation
  - "before 10am on monday"
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/oxc-project/oxc).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4yOS41IiwidXBkYXRlZEluVmVyIjoiNDQuMjkuNSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Cameron <cameron.clark@hey.com>
2026-08-17 08:30:18 +00:00
Boshen 892238149b refactor(linter): remove inactive react config rule (#25740)
Remove the inactive `react/config` rule and its generated metadata. Oxlint uses fixed, valid React Compiler options, so the rule cannot produce actionable diagnostics.

AI-assisted: Codex was used to implement and validate this change.
2026-08-16 12:39:27 +00:00
Boshen 8c4552dfa6 feat(linter)!: split react/react-compiler into per-category rules (#25500)
Splits the experimental `react/react-compiler` rule into 24 category-specific rules matching `eslint-plugin-react-hooks` v7.

- Runs React Compiler once per file and routes structured diagnostics to each enabled rule.
- Removes `react/react-compiler` and `reportAllBailouts`, with rules categorized by user-facing lint intent.
- Adds per-rule documentation and deduplicates shared React lint URLs.
- Preserves standardized compiler diagnostics while reporting each finding under its Oxlint rule name.

Breaking change: configurations using `react/react-compiler` must migrate to the category-specific rules.

Written with Claude Code and Codex.
2026-08-15 14:56:58 +00:00
camc314 beb724dce2 fix(linter/eslint/no-unused-vars): report bare underscore parameters (#25663)
## Summary

- report a bare underscore parameter when no args ignore pattern is configured
- preserve the optimized underscore-prefix behavior for explicit argsIgnorePattern configuration
- update focused rule coverage and generated documentation

Closes #25626
2026-08-14 13:16:16 +00:00
Mikhail Baev 285820eed6 fix(linter/no-large-snapshots): precompile and document allowed snapshot matchers (#25611)
issue #23594

- Move regex compilation to configuration parsing to avoid recompiling
patterns for every snapshot entry
- Document the matching behavior of allowedSnapshots (first interpret as
regex, if not valid match as string)
- Fix a small typo where both example sections were labeled “incorrect"
- Replace manual config parsing with DefaultRuleConfig
2026-08-14 10:47:51 +01:00
camc314 0c68b7ff8b fix(estree): emit decorators on FormalParameterRest (#25582)
This PR adds support for emitting `decorators` when serializing an ast to ESTree (both with/without raw transfer).

Given the following code:
```
class C { method(@dec ...args) {} }
```

Before we emitted the following ESTree shape:
```json
"params": [
  {
    "type": "RestElement",
    "decorators": [],
    "argument": {
      "type": "Identifier",
      "decorators": [],
      "name": "args",
      "optional": false,
      "typeAnnotation": null,
    },
    "optional": false,
    "typeAnnotation": null,
    "value": null,
  }
],
```

Now we emit:
```json
"params": [
  {
    "type": "RestElement",
    "decorators": [
      {
        "type": "Decorator",
        "expression": { "type": "Identifier", "name": "dec" }
      }
    ],
    "argument": {
      "type": "Identifier",
      "decorators": [],
      "name": "args",
      "optional": false,
      "typeAnnotation": null,
    },
    "optional": false,
    "typeAnnotation": null,
    "value": null,
  },
],
```

fixes https://github.com/oxc-project/oxc/issues/18981
closes https://github.com/oxc-project/oxc/pull/24736
2026-08-13 10:43:14 +00:00
camc314 1d22912cb4 fix(linter/plugins): parse rule-less directive justifications (#25559)
## Summary

- extract directive justifications before parsing directive labels, matching ESLint
- return an empty rule value for rule-less directives while preserving their justification
- cover block, enable, line, and next-line directives with both eslint and oxlint prefixes

Closes #25556
2026-08-12 16:44:01 +00:00
Boshen 4df5835fc3 fix(linter): allow capitalized built-in calls (#25516)
Fixes #24405.

The React Compiler global registry omitted `BigInt` and `Symbol`, causing `CapitalizedCalls` false positives. Register both primitives and expose the upstream-compatible `environment.validateNoCapitalizedCalls` option.

Validated with `just ready`.

AI-assisted: Codex was used to investigate and implement this change.
2026-08-12 03:51:52 +00:00
oxc-guard c42d6397ea release(apps): oxlint v1.78.0 && oxfmt v0.63.0 (#25473)
# Oxlint
### 💥 BREAKING CHANGES

- a33788e ast: [**BREAKING**] Group class heritage into `ClassHeritage` (#25360) (camc314)
- 5c5cdcd ast: [**BREAKING**] Narrow `TSInterfaceHeritage::expression` to TSTypeName (#24360) (camc314)
- 6be314f ast: [**BREAKING**] Remove duplicated `VariableDeclarator::kind` (#25319) (camc314)
- 44fd320 ast: [**BREAKING**] Split TS external modules & Namespace Declarations (#25284) (camc314)

### 🚀 Features

- ccb8fe8 linter/jsdoc: Implement `no-blank-blocks` rule (#25207) (Mikhail Baev)
- d4a897c linter/eslint: Implement `one-var` rule (#24470) (Cole Ellison)
- 5ab9340 linter/jsx-a11y/anchor-has-content: Add options to match eslint (#24571) (Cole Ellison)

### 🐛 Bug Fixes

- b746e00 linter/eslint/no-implicit-coercion: Preserve template coercion whitespace (#25470) (camc314)
- a92c541 linter: Preserve source text for JS plugin ignore fixes (#25280) (Norcleeh)
- 675c840 linter/eslint/prefer-promise-reject-errors: Handle parenthesized calls (#25378) (camc314)
- 1703739 linter/unicorn/new-for-builtins: Ignore optional chains (#25411) (tanakalucky)
- 95ece63 linter/unicorn/prefer-code-point: Downgrade the auto-fix to dangerous (#25412) (leemr)
- c451a0e linter/vitest: Validate `consistent-test-filename` regex patterns (#25408) (Mikhail Baev)
- 937825c react_compiler: Disable exhaustive memo validation by default (#25417) (Boshen)
- f0f7dae linter/eslint/no-unused-vars: Report invalid regex options (#25380) (Cameron)
- 44e73fd linter/unicorn/prefer-array-flat: Fix `concat.apply` suggestions (#25373) (Cameron)
- 6846a9a linter/react/rules-of-hooks: Detect constructor callbacks (#25377) (camc314)
- b247a9d linter/unicorn/new-for-builtins: Support `Float16Array` (#25382) (tanakalucky)
- 19109cd linter/unicorn/error-message: Support `SuppressedError` messages (#25375) (camc314)
- 9c13f5e linter: Assert token lookup invariants (#25368) (camc314)
- bc35f83 linter/eslint/no-unused-vars: Bound catch parameter lookup (#25367) (camc314)
- c159fb9 linter/unicorn/switch-case-braces: Bound token lookup (#25363) (camc314)
- 03b2eb2 linter/unicorn/no-static-only-class: Bound token lookup (#25361) (camc314)
- 0afc59e linter/unicorn/empty-brace-spaces: Bound token lookup (#25353) (camc314)
- 2963d98 linter/eslint/no-unreachable-loop: Do not report loops whose body has a finally block (#25335) (Todor Andonov)
- 589e5fb linter/eslint/no-param-reassign: Validate `ignorePropertyModificationsForRegex` property (#25346) (Mikhail Baev)
- aae5d8b linter/eslint/no-throw-literal: False positive on variable declared without initializer (#25275) (cjnoname)
- 6b1c479 oxlint: Normalize customized rule names (#25316) (camc314)
- d494eb5 linter/unicorn/consistent-existence-index-check: Bound token lookup (#25325) (camc314)
- 4266037 linter/typescript/prefer-namespace-keyword: Bound token lookup (#25322) (camc314)
- 4745b4e linter/typescript/no-namespace: Bound token lookup (#25321) (camc314)
- 648a481 linter/eslint/one-var: Avoid joining exported declarations (#25314) (camc314)
- 9573937 linter/typescript: Validate `ban-ts-comment` description_format (#25320) (Mikhail Baev)
- ebf7d18 linter/typescript/consistent-type-definitions: Bound token lookup (#25281) (camc314)
- 1501ccf linter/typescript/consistent-generic-constructors: Bound token lookup (#25258) (camc314)

### ⚡ Performance

- 8f784f3 linter: Reduce rule config dispatch size (#25461) (Boshen)
- 2de4ec2 linter: Reduce visitor code size (#25441) (Boshen)
- 6fb7f47 linter/unicorn/prefer-export-from: Narrow `ExportFromDeclaration` lookup (#25381) (camc314)
- e3f6263 linter/unicorn/prefer-default-parameters: Avoid reference allocation  (#25379) (camc314)
- d863473 linter/vue/max-props: Narrow AST dispatch (#25372) (camc314)
- 273d867 linter: Avoid diagnostic sorting after applying fixes (#25079) (Sysix)
- 4ec9189 oxlint/lsp: Avoid second lock for getting/removing unused directives (#25350) (Sysix)
- 6c0d01b oxlint/lsp: Preallocate fix-content vec (#25351) (Sysix)
- 3a94055 linter: Avoid per-call heap allocations in jest and unicorn helpers (#25210) (Connor Shea)
- 4abff11 linter: Avoid redundant message work in the agent reporter (#25315) (Connor Shea)
- 6bb5421 linter: Hoist `current_dir` out of the stylish reporter loop (#25313) (Connor Shea)
- 9a7c323 linter: Compute diagnostic `Info` once per diagnostic in junit reporter (#25312) (Connor Shea)
- 1cf7dde oxlint: Render JSON report into a single buffer (#25295) (connorshea)
- 8492cfd linter/typescript/ban-ts-comment: Bail early with substring guard (#25301) (Jacob Asper)
- 7607f04 linter/typescript/ban-tslint-comment: Replace regex with manual parser (#25299) (Jacob Asper)
# Oxfmt
### 💥 BREAKING CHANGES

- a33788e ast: [**BREAKING**] Group class heritage into `ClassHeritage` (#25360) (camc314)
- 5c5cdcd ast: [**BREAKING**] Narrow `TSInterfaceHeritage::expression` to TSTypeName (#24360) (camc314)
- 6be314f ast: [**BREAKING**] Remove duplicated `VariableDeclarator::kind` (#25319) (camc314)
- 44fd320 ast: [**BREAKING**] Split TS external modules & Namespace Declarations (#25284) (camc314)

### 🚀 Features

- fd02a89 oxfmt: Dispatch yaml-in-css(frontmatter) to `oxc_formatter_yaml` (#25336) (leaysgur)
- ab12665 formatter_core: Add `hardlineWithoutBreakParent` equivalent IR (#25273) (leaysgur)

### 🐛 Bug Fixes

- 95dc917 oxfmt: Drop IR Space at line start for js-in-xxx (#25460) (leaysgur)
- b63eccc formatter: Keep comments after TS this_param (#25459) (leaysgur)
- ab52a59 formatter: Format xxx-in-js inside JSDoc js fence (#25414) (leaysgur)
- 1a2c64a formatter,oxfmt: Apply effective print width for JSDoc fence (#25413) (leaysgur)
- 2eaede9 formatter_core: Unify leading-BOM handlings (#25340) (leaysgur)
- ef1d04b formatter: Break mapped type brackets (#25297) (leaysgur)
- 4e6f3f1 formatter: Break index signature brackets (#25296) (leaysgur)
- e23dccf formatter_css: Bump oxc-css-parser to accept unknown at-rule with interpolated (#25277) (leaysgur)
- c29b587 formatter_core: Measure decided-flat fill separator as flat during group re-measure (#25276) (leaysgur)
- f3c6953 formatter_yaml: Don't rewrite overflowing key to implicit (#25274) (leaysgur)

### ⚡ Performance

- c9d1a5b oxfmt: Spawn tinypool lazily (#25298) (leaysgur)

### 📚 Documentation

- 6eae5c9 formatter,oxfmt: Record embed-layer decisions in place (#25422) (leaysgur)
- 51224a7 formatter_yaml: Pin EOF blank lines divergence (#25269) (leaysgur)
2026-08-10 10:03:34 +00:00
camc314 a33788e13e feat(ast)!: group class heritage into ClassHeritage (#25360)
## Summary

- Groups `Class::super_class` and `Class::super_type_arguments` into `Class::heritage`.
- Introduces `ClassHeritage` containing the superclass expression and its optional TypeScript type arguments.
- Makes superclass type arguments without a superclass expression unrepresentable.

## Breaking Change

The Rust AST changes from:

```rust
pub struct Class<'a> {
    pub node_id: Cell<NodeId>,
    pub span: Span,
    pub r#type: ClassType,
    pub decorators: Vec<'a, Decorator<'a>>,
    pub id: Option<BindingIdentifier<'a>>,
    #[ts]
    pub type_parameters: Option<Box<'a, TSTypeParameterDeclaration<'a>>>,
    pub super_class: Option<Expression<'a>>,
    #[ts]
    pub super_type_arguments: Option<Box<'a, TSTypeParameterInstantiation<'a>>>,
    #[ts]
    pub implements: Vec<'a, TSClassImplements<'a>>,
    pub body: Box<'a, ClassBody<'a>>,
    #[ts]
    pub r#abstract: bool,
    #[ts]
    pub declare: bool,
    pub scope_id: Cell<Option<ScopeId>>,
}
```

to:

```rust
pub struct Class<'a> {
    pub node_id: Cell<NodeId>,
    pub span: Span,
    pub r#type: ClassType,
    pub decorators: Vec<'a, Decorator<'a>>,
    pub id: Option<BindingIdentifier<'a>>,
    #[ts]
    pub type_parameters: Option<Box<'a, TSTypeParameterDeclaration<'a>>>,
    pub heritage: Option<ClassHeritage<'a>>,
    #[ts]
    pub implements: Vec<'a, TSClassImplements<'a>>,
    pub body: Box<'a, ClassBody<'a>>,
    #[ts]
    pub r#abstract: bool,
    #[ts]
    pub declare: bool,
    pub scope_id: Cell<Option<ScopeId>>,
}

pub struct ClassHeritage<'a> {
    pub expression: Expression<'a>,
    #[ts]
    pub type_arguments: Option<Box<'a, TSTypeParameterInstantiation<'a>>>,
}
```

## Why?

ECMAScript defines the complete `extends` clause as `ClassHeritage`:

```text
ClassHeritage : extends LeftHandSideExpression
```

TypeScript additionally permits type arguments on the heritage expression:

```ts
class Derived extends Base<T> {}
```

Previously, the AST stored the expression and type arguments independently:

```text
Class {
    super_class: Some(Base),
    super_type_arguments: Some(<T>),
    ...
}
```

This allowed an invalid state to be constructed:

```text
Class {
    super_class: None,
    super_type_arguments: Some(<T>),
    ...
}
```

Superclass type arguments cannot exist without an `extends` expression.

The parser already treated these fields as a pair. It parsed a class heritage entry and then split its expression and type arguments into two independent fields. Builders and transforms therefore had to preserve their relationship manually.

Grouping them into `ClassHeritage` makes the syntactic dependency explicit and prevents consumers from observing or constructing contradictory class heritage.

## Class heritage forms

A class without an `extends` clause has no heritage:

```js
class Base {}
```

```text
Class {
    heritage: None,
    ...
}
```

A class extending an expression has heritage without type arguments:

```js
class Derived extends Base {}
```

```text
Class {
    heritage: Some(ClassHeritage {
        expression: Base,
        type_arguments: None,
    }),
    ...
}
```

TypeScript type arguments belong to the same heritage structure:

```ts
class Derived extends Base<T> {}
```

```text
Class {
    heritage: Some(ClassHeritage {
        expression: Base,
        type_arguments: Some(<T>),
    }),
    ...
}
```

The heritage expression may be any valid class heritage expression:

```js
class Derived extends mixin(Base) {}
class NullDerived extends null {}
```

## How to migrate

Code that previously accessed the superclass expression directly:

```rust
if let Some(super_class) = &class.super_class {
    // ...
}
```

can use the compatibility accessor:

```rust
if let Some(super_class) = class.super_class() {
    // ...
}
```

Code that needs both parts should access the grouped heritage:

```rust
if let Some(heritage) = &class.heritage {
    let expression = &heritage.expression;
    let type_arguments = heritage.type_arguments.as_deref();
}
```

Mutating consumers should update the nested fields:

```rust
if let Some(heritage) = &mut class.heritage {
    heritage.type_arguments = None;
}
```

Common migrations:

| Previous representation | New representation |
| --- | --- |
| `class.super_class` | `class.heritage.as_ref().map(\|h\| &h.expression)` or `class.super_class()` |
| `class.super_type_arguments` | `class.heritage.as_ref()?.type_arguments` or `class.super_type_arguments()` |
| `class.super_class.is_some()` | `class.heritage.is_some()` |
| Mutate `class.super_class` | Mutate `class.heritage.expression` |
| Clear `class.super_type_arguments` | Clear `class.heritage.type_arguments` |
| Pass superclass and type arguments separately to a `Class` builder | Construct and pass `ClassHeritage` |
| Clone both fields independently | Clone `class.heritage` |

```ts
superClass: Expression | null;
superTypeArguments?: TSTypeParameterInstantiation | null;
```

No `heritage` property or `ClassHeritage` node is added to the ESTree output.

fixes https://github.com/oxc-project/backlog/issues/216
2026-08-07 14:18:59 +00:00
camc314 5c5cdcd522 feat(ast)!: narrow TSInterfaceHeritage::expression to TSTypeName (#24360)
## Summary

Narrow `TSInterfaceHeritage` from a general JavaScript `Expression` to `TSTypeName`.

```rust
pub struct TSInterfaceHeritage<'a> {
    pub type_name: TSTypeName<'a>,
    pub type_arguments: Option<Box<'a, TSTypeParameterInstantiation<'a>>>,
}
```

## Breaking Change

The Rust AST field changes from:

```rust
expression: Expression<'a>
```

to:

```rust
type_name: TSTypeName<'a>
```

## Why?

The current AST can represent shapes such as:

```ts
interface A extends foo() {}
interface A extends A + B {}
interface A extends new Foo() {}
interface A extends true {}
```

Which is an overly wide type since all of the above variants are invalid.

This PR tightens up the AST, making these invalid variants irrepresentable.

## How to migrate?

This should be a trivial migration:
1. instead of accessing `expression` on `TSInterfaceHeritage`, now access `type_name`
2. change any pattern matching on the `type_name` field to use `TypeName` (this is a smaller subset so should allow deleting code!)

closes https://github.com/oxc-project/backlog/issues/215
2026-08-07 06:00:42 +00:00
Mikhail Baev ccb8fe89db feat(linter/jsdoc): implement no-blank-blocks rule (#25207)
this PR implements `jsdoc/no-blank-blocks` rule, issue #1170
2026-08-05 22:38:24 +01:00
Mikhail Baev 9573937df3 fix(linter/typescript): validate ban-ts-comment description_format (#25320)
adds validation for the `descriptionFormat` regex option from #23594 and
replaces manual config parsing with `DefaultRuleConfig`
2026-08-05 20:21:36 +01:00
camc314 6be314f226 feat(ast)!: remove duplicated VariableDeclarator::kind (#25319)
## Summary

- Removes `VariableDeclarator::kind`.
- Makes `VariableDeclaration::kind` the single source of truth for every declarator in its declaration list.
- Makes contradictory parent and child declaration kinds unrepresentable.

## Breaking Change

The Rust AST changes from:

```rust
pub struct VariableDeclaration<'a> {
    pub node_id: Cell<NodeId>,
    pub span: Span,
    pub kind: VariableDeclarationKind,
    pub declarations: Vec<'a, VariableDeclarator<'a>>,
    #[ts]
    pub declare: bool,
}

pub struct VariableDeclarator<'a> {
    pub node_id: Cell<NodeId>,
    pub span: Span,
    #[estree(skip)]
    pub kind: VariableDeclarationKind,
    #[estree(via = VariableDeclaratorId)]
    pub id: BindingPattern<'a>,
    #[ts]
    #[estree(skip)]
    pub type_annotation: Option<Box<'a, TSTypeAnnotation<'a>>>,
    pub init: Option<Expression<'a>>,
    #[ts]
    pub definite: bool,
}
```

to:

```rust
pub struct VariableDeclaration<'a> {
    pub node_id: Cell<NodeId>,
    pub span: Span,
    pub kind: VariableDeclarationKind,
    pub declarations: Vec<'a, VariableDeclarator<'a>>,
    #[ts]
    pub declare: bool,
}

pub struct VariableDeclarator<'a> {
    pub node_id: Cell<NodeId>,
    pub span: Span,
    #[estree(via = VariableDeclaratorId)]
    pub id: BindingPattern<'a>,
    #[ts]
    #[estree(skip)]
    pub type_annotation: Option<Box<'a, TSTypeAnnotation<'a>>>,
    pub init: Option<Expression<'a>>,
    #[ts]
    pub definite: bool,
}
```

## Why?

A variable declaration has one declaration kind shared by every declarator in its declaration list:

```js
const first = 1, second = 2;
```

Previously, the AST stored that kind on both the parent declaration and every child declarator:

```text
VariableDeclaration {
    kind: Const,
    declarations: [
        VariableDeclarator { kind: Const, ... },
        VariableDeclarator { kind: Const, ... },
    ],
}
```

This allowed contradictory ASTs to be constructed:

```text
VariableDeclaration {
    kind: Const,
    declarations: [
        VariableDeclarator { kind: Var, ... },
    ],
}
```

Different consumers read different copies:

- Code generation used `VariableDeclaration::kind`.
- Semantic binding used `VariableDeclarator::kind`.
- Lint rules, transforms, and minifier passes used a mixture of both.

As a result, one AST could be emitted as `const` while its binding was treated as function-scoped `var`.

Transforms also had to keep the copies synchronized manually. For example, const-to-let normalization updated the parent and then looped through every declarator to update each child. Explicit resource management performed similar paired mutations for `using` declarations.

Keeping the kind only on `VariableDeclaration` removes this synchronization requirement and prevents consumers from observing conflicting declaration semantics.

## Declaration forms

The declaration kind now belongs exclusively to the node that owns the declaration list:

```js
let value;
```

```text
VariableDeclaration {
    kind: Let,
    declarations: [
        VariableDeclarator { id: value, ... },
    ],
}
```

Multiple declarators share the same parent kind:

```js
const first = 1, second = 2;
```

```text
VariableDeclaration {
    kind: Const,
    declarations: [
        VariableDeclarator { id: first, ... },
        VariableDeclarator { id: second, ... },
    ],
}
```

## How to migrate

Code that previously read the kind from a declarator:

```rust
if declarator.kind.is_const() {
    // ...
}
```

should now read it from the containing declaration:

```rust
if declaration.kind.is_const() {
    // ...
}
```

Consumers operating through an AST node store should retrieve the parent `VariableDeclaration`:

```rust
let AstKind::VariableDeclaration(declaration) =
    nodes.parent_kind(declarator.node_id())
else {
    unreachable!();
};

let kind = declaration.kind;
```

Common migrations:

| Previous representation | New representation |
| --- | --- |
| `declarator.kind` | Containing `declaration.kind` |
| Match `VariableDeclarator::kind` during semantic binding | Read the parent `VariableDeclaration` from ancestry |
| Pass `kind` to `VariableDeclarator::new` | Remove the `kind` argument |
| Update parent and every child kind | Update only `VariableDeclaration::kind` |
| Recover kind after detaching a declarator | Capture or pass the parent kind before detaching it |
| Inspect a symbol’s declarator kind in lint rules | Resolve its parent declaration through the node store |

When constructing declarators, use the generated kindless `VariableDeclarator` builders and place them inside a `VariableDeclaration` carrying the required kind.

fixes https://github.com/oxc-project/backlog/issues/237
2026-08-05 16:31:46 +00:00
camc314 44fd320324 feat(ast)!: split TS external modules & Namespace Declarations (#25284)
## Summary

- Splits `TSModuleDeclaration` into two dedicated declaration nodes:
  - `TSExternalModuleDeclaration` for string-literal modules and module augmentations.
  - `TSNamespaceDeclaration` for identifier-based `module` and `namespace` declarations.
- Removes `TSModuleDeclaration`, `TSModuleDeclarationName`, `TSModuleDeclarationBody`, and `TSModuleDeclarationKind`.
- Makes invalid combinations of names, bodies, and declaration kinds unrepresentable.
- Ensures only namespace declarations introduce a normal binding.
- Updates all AST consumers, generators, traversal, formatting, code generation, semantic analysis, lint rules, transforms, and serialization.
- Keeps normal and eager-raw ESTree output compatible: both declarations remain `TSModuleDeclaration` nodes.
- Allows experimental lazy raw deserialization to expose the two new node types directly.

## Breaking Change

The Rust AST changes from:

```rust
pub enum Declaration<'a> {
    VariableDeclaration(Box<'a, VariableDeclaration<'a>>) = 32,
    FunctionDeclaration(Box<'a, Function<'a>>) = 33,
    ClassDeclaration(Box<'a, Class<'a>>) = 34,

    TSTypeAliasDeclaration(Box<'a, TSTypeAliasDeclaration<'a>>) = 35,
    TSInterfaceDeclaration(Box<'a, TSInterfaceDeclaration<'a>>) = 36,
    TSEnumDeclaration(Box<'a, TSEnumDeclaration<'a>>) = 37,
    TSModuleDeclaration(Box<'a, TSModuleDeclaration<'a>>) = 38,
    TSGlobalDeclaration(Box<'a, TSGlobalDeclaration<'a>>) = 39,
    TSImportEqualsDeclaration(Box<'a, TSImportEqualsDeclaration<'a>>) = 40,
}

pub struct TSModuleDeclaration<'a> {
    pub node_id: Cell<NodeId>,
    pub span: Span,
    pub id: TSModuleDeclarationName<'a>,
    pub body: Option<TSModuleDeclarationBody<'a>>,
    pub kind: TSModuleDeclarationKind,
    pub declare: bool,
    pub scope_id: Cell<Option<ScopeId>>,
}
```

to:

```rust
pub enum Declaration<'a> {
    VariableDeclaration(Box<'a, VariableDeclaration<'a>>) = 32,
    FunctionDeclaration(Box<'a, Function<'a>>) = 33,
    ClassDeclaration(Box<'a, Class<'a>>) = 34,

    TSTypeAliasDeclaration(Box<'a, TSTypeAliasDeclaration<'a>>) = 35,
    TSInterfaceDeclaration(Box<'a, TSInterfaceDeclaration<'a>>) = 36,
    TSEnumDeclaration(Box<'a, TSEnumDeclaration<'a>>) = 37,
    TSExternalModuleDeclaration(Box<'a, TSExternalModuleDeclaration<'a>>) = 38,
    TSNamespaceDeclaration(Box<'a, TSNamespaceDeclaration<'a>>) = 39,
    TSGlobalDeclaration(Box<'a, TSGlobalDeclaration<'a>>) = 40,
    TSImportEqualsDeclaration(Box<'a, TSImportEqualsDeclaration<'a>>) = 41,
}

pub struct TSExternalModuleDeclaration<'a> {
    pub node_id: Cell<NodeId>,
    pub span: Span,
    pub id: StringLiteral<'a>,
    pub body: Option<Box<'a, TSModuleBlock<'a>>>,
    pub declare: bool,
    pub scope_id: Cell<Option<ScopeId>>,
}

pub struct TSNamespaceDeclaration<'a> {
    pub node_id: Cell<NodeId>,
    pub span: Span,
    pub id: BindingIdentifier<'a>,
    pub body: TSNamespaceDeclarationBody<'a>,
    pub kind: TSNamespaceDeclarationKind,
    pub declare: bool,
    pub scope_id: Cell<Option<ScopeId>>,
}

pub enum TSNamespaceDeclarationBody<'a> {
    TSNamespaceDeclaration(Box<'a, TSNamespaceDeclaration<'a>>) = 0,
    TSModuleBlock(Box<'a, TSModuleBlock<'a>>) = 1,
}

pub enum TSNamespaceDeclarationKind {
    Module = 0,
    Namespace = 1,
}
```

The corresponding inherited `Statement` variants, `AstKind` variants, builders, and visitor methods have also changed.

## Why?

`TSModuleDeclaration` previously represented two declaration families with different syntax and semantics:

```ts
declare module "foo" {}
declare module "*.css";

module Foo {}
namespace Foo {}
namespace Foo.Bar {}
```

The shared representation allowed invalid states such as:

- A namespace with a string-literal name.
- An external module with an identifier name.
- An identifier namespace without a body.
- A dotted external module.
- An external module containing another module declaration as its body.
- A declaration whose `kind` disagreed with its name.

Consumers also had to inspect `id` before determining whether the node introduced a binding or represented an external module.

The two declaration families have stronger independent invariants:

### External modules

- Always have a string-literal name.
- Never introduce a normal binding identifier.
- May omit their body.
- Cannot use dotted names.
- Use module-body import and export rules.

### Namespace declarations

- Always have a binding identifier.
- Always have a body.
- May contain nested namespace declarations for dotted names.
- Explicitly preserve the `module` or `namespace` spelling.
- Introduce a namespace/module symbol.
- Use namespace-body restrictions.

Dedicated nodes encode these differences directly.

## Declaration forms

External modules use `TSExternalModuleDeclaration`:

```ts
declare module "foo" {}
declare module "*.css";
module "foo" {}
```

Identifier-based declarations use `TSNamespaceDeclaration`:

```ts
module Foo {}
namespace Foo {}
```

Dotted namespaces are represented as nested namespace declarations:

```ts
namespace Foo.Bar {}
```

```rust
TSNamespaceDeclaration {
    id: Foo,
    body: TSNamespaceDeclarationBody::TSNamespaceDeclaration(
        TSNamespaceDeclaration {
            id: Bar,
            body: TSNamespaceDeclarationBody::TSModuleBlock(...),
            // ...
        }
    ),
    // ...
}
```

Only `TSExternalModuleDeclaration::body` is optional.

## ESTree compatibility

Normal serialization and eager raw deserialization continue to emit the existing ESTree shape:

```ts
interface TSModuleDeclaration {
  type: "TSModuleDeclaration";
  id: BindingIdentifier | StringLiteral | TSQualifiedName;
  body: TSModuleBlock | null;
  kind: "module" | "namespace";
  declare: boolean;
  global: false;
}
```

Dotted namespaces continue to serialize as a single `TSModuleDeclaration` with a `TSQualifiedName`.

Experimental lazy raw deserialization is not compatibility-preserving. It now exposes `TSExternalModuleDeclaration` and `TSNamespaceDeclaration` directly, with separate constructors, layouts, and visitor type IDs.

## How to migrate

Code that previously matched all forms through one variant:

```rust
if let Declaration::TSModuleDeclaration(declaration) = declaration {
    // ...
}
```

should now match the required declaration family:

```rust
match declaration {
    Declaration::TSExternalModuleDeclaration(declaration) => {
        // String-literal external module
    }
    Declaration::TSNamespaceDeclaration(declaration) => {
        // Identifier-based module or namespace
    }
    _ => {}
}
```

The same applies to `Statement` and `AstKind`:

```rust
Statement::TSExternalModuleDeclaration(declaration)
Statement::TSNamespaceDeclaration(declaration)

AstKind::TSExternalModuleDeclaration(declaration)
AstKind::TSNamespaceDeclaration(declaration)
```

Common field migrations:

| Previous representation | New representation |
| --- | --- |
| `TSModuleDeclarationName::StringLiteral(id)` | `TSExternalModuleDeclaration::id` |
| `TSModuleDeclarationName::Identifier(id)` | `TSNamespaceDeclaration::id` |
| `body: None` | Only valid on `TSExternalModuleDeclaration` |
| `TSModuleDeclarationBody::TSModuleBlock` | External `body` or `TSNamespaceDeclarationBody::TSModuleBlock` |
| `TSModuleDeclarationBody::TSModuleDeclaration` | `TSNamespaceDeclarationBody::TSNamespaceDeclaration` |
| `TSModuleDeclarationKind::Module` | External module, or `TSNamespaceDeclarationKind::Module` |
| `TSModuleDeclarationKind::Namespace` | `TSNamespaceDeclarationKind::Namespace` |
| Inspect `id` to determine binding behavior | Match `TSNamespaceDeclaration` |
| `declaration.id()` for string modules | Now returns `None` |
| `visit_ts_module_declaration` | `visit_ts_external_module_declaration` or `visit_ts_namespace_declaration` |

When constructing nodes, use the generated `TSExternalModuleDeclaration` or `TSNamespaceDeclaration` builders rather than recreating the previous shared representation.

fixes https://github.com/oxc-project/backlog/issues/218
2026-08-05 14:37:35 +00:00
Cole Ellison d4a897ce22 feat(linter/eslint): implement one-var rule (#24470)
## Summary

Adds a native Oxlint implementation of [ESLint's `one-var`
rule](https://eslint.org/docs/latest/rules/one-var). This implementation
is a port of the [eslint rule
source](https://github.com/eslint/eslint/blob/main/lib/rules/one-var.js),
test suite, and autofix logic.

Related #479

## AI Disclosure

GPT 5.6 Sol was used to assist with implementation of this rule.

---------

Co-authored-by: Cameron <cameron.clark@hey.com>
2026-08-05 15:10:29 +01:00
Cole Ellison 5ab9340637 feat(linter/jsx-a11y/anchor-has-content): add options to match eslint (#24571)
## Description

Eslint supports [a `components`
option](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/anchor-has-content.md)
for `jsx-a11y/anchor-has-content` that specified additional components
to treat as anchor elements. This adds equivalent support for that
option.

Note: I am not certain if this is something that should instead be read
off of
[`settings.jsx-a11y.components`](https://oxc.rs/docs/guide/usage/linter/config-file-reference.html#settings-jsx-a11y-components),
as that could list `{ MyAnchor: 'a' }`. Doing that would enable implicit
application of rules to custom components based on rendered entity, but
that may be the wrong use case, as the custom component definition
itself could be responsible for rendering required children.

## AI disclosure

I used GPT 5.6 Sol to assist in implementation of this fix. I've
reviewed all generated code and test coverage.

---------

Signed-off-by: Cameron <cameron.clark@hey.com>
Co-authored-by: Cameron <cameron.clark@hey.com>
2026-08-05 11:57:23 +01:00
oxc-guard 9a423f2f48 release(apps): oxlint v1.77.0 && oxfmt v0.62.0 (#25251)
# Oxlint
### 💥 BREAKING CHANGES

- 4120da0 semantic: [**BREAKING**] Return borrowed JSDoc so the parse cache works (#25186) (Connor Shea)
- 067da8c ast: [**BREAKING**] Store single parameter in `TSIndexSignature::parameter` (#25154) (camc314)
- 1bdedd1 ast: [**BREAKING**] Introduce `ExportDeclaration`, `ExportFromDeclaration` (#25095) (camc314)
- c917f20 ast: [**BREAKING**] Introduce `ArrowFunctionBody` enum (#24987) (camc314)

### 🚀 Features

- 0b9f83c linter/oxc/bad-char-at-comparison: Expand coverage (#25001) (Mikhail Baev)
- 1fb3d70 oxlint: Show file:line:col in github format annotation messages (#25020) (Faris Tristan Fabian)

### 🐛 Bug Fixes

- 9d4592c linter: Reject duplicate JS plugin names (#25243) (camc314)
- 3213e7a linter: Ignore unsigned shifts in prefer-math-trunc (#25240) (camc314)
- 06579da linter/eslint/prefer-promise-reject-errors: Handle ambient error variables (#25238) (camc314)
- 6a7cd90 linter/oxc/no-async-await: Bound token lookup (#25222) (camc314)
- d8e390a linter/oxc/bad-bitwise-operator: Bound token lookups (#25220) (camc314)
- 351a777 linter/import/no-duplicates: Bound token lookup (#25219) (camc314)
- 4f70fb6 linter/import/consistent-type-specifier-style: Bound token lookup (#25218) (camc314)
- b89113c linter/eslint/yoda: Bound token lookup (#25202) (camc314)
- 7c7cda7 linter/oxc/no-map-spread: Avoid recursive declaration traversal (#25200) (camc314)
- 99efb30 linter/eslint/prefer-promise-reject-errors: Move category to `pedantic` (#25201) (camc314)
- 8edad2a linter/eslint/require-await: Bound token lookup (#25199) (camc314)
- 5aaec85 linter/eslint/prefer-template: Bound token lookup (#25197) (camc314)
- 0ea1af4 linter/unicorn/new-for-builtins: Align Date() diagnostic message with upstream (#25166) (tanakalucky)
- f6c8575 linter/eslint/prefer-object-spread: Bound token lookup (#25195) (camc314)
- 20f68e7 oxlint,oxfmt: Respect `.gitignore` for walk targets and explicit paths (#25133) (leaysgur)
- b83993b linter/eslint/prefer-const: Bound token lookup (#25194) (camc314)
- aeabf63 linter/eslint/object-shorthand: Bound token lookups (#25193) (camc314)
- 48f302c linter/eslint/no-var: Bound token lookup (#25192) (camc314)
- 1f595de linter/eslint/no-unused-vars: Bound token lookups (#25191) (camc314)
- e52f4c4 linter/eslint/no-unexpected-multiline: Use bounded token lookup (#25190) (camc314)
- ca80338 linter/eslint/eqeqeq: Use bounded token lookup (#25189) (camc314)
- df91684 linter: Make the remaining token lookups comment-aware (#25182) (connorshea)
- 2401bb8 linter/eslint/prefer-const: Skip Svelte and Vue files (#25148) (Pitiș Radu)
- b870897 linter: Don't match tokens inside comments when locating spans (#25181) (connorshea)
- b474da1 linter/typescript/consistent-type-imports: Make token lookups comment-aware (#25180) (connorshea)
- 81f82db linter: Don't insert an ASI semicolon into an unbraced statement body (#25160) (Vladexy88x)
- 31333be linter/no-magic-array-flat-depth: Scan for `(` by byte offset instead of character count (#25130) (connorshea)
- 56e9c83 linter: Index source text by byte offset instead of char count (#25131) (connorshea)
- 5c0fa61 linter/eslint/no-warning-comments: Unify config structs and remove manual options docs (#25151) (Mikhail Baev)
- a922355 docs: Incorrect quotations in `role_supports_aria_props.rs` (#25077) (Maximilian Franzke)
- e8c4c05 linter/eslint/no-unreachable-loop: Handle caught errors correctly (#25071) (camc314)
- 2b02711 oxlint: Correct --warn flag help text (#25059) (Faris Tristan Fabian)
- 97f084f linter/eslint/no-control-regex: Allow null escape (#25070) (camc314)

### ⚡ Performance

- 224c21a linter/vue/no-side-effects-in-computed-properties: Borrow property names in the mutation walk (#25212) (connorshea)
- d36e9c9 linter/unicorn/prefer-export-from: Skip non-violating imports early (#25183) (connorshea)
- 6f2b933 linter/import/no-cycle: Drop two Vec allocations per graph edge (#25004) (Connor Shea)
- 79ddb18 linter/import/no-cycle: Skip the graph walk for acyclic modules (#25003) (Connor Shea)

### 📚 Documentation

- f8392cd linter/eslint/prefer-promise-reject-errors: Recommend type aware rule (#25241) (camc314)
- 9dc7756 linter/typescript/no-unnecessary-condition: Clarify options (#25110) (camc314)
# Oxfmt
### 💥 BREAKING CHANGES

- 067da8c ast: [**BREAKING**] Store single parameter in `TSIndexSignature::parameter` (#25154) (camc314)
- a0c7788 ast: [**BREAKING**] Change `TSIndexSignatureName::name` to `Ident` (#25150) (camc314)
- 1bdedd1 ast: [**BREAKING**] Introduce `ExportDeclaration`, `ExportFromDeclaration` (#25095) (camc314)
- c917f20 ast: [**BREAKING**] Introduce `ArrowFunctionBody` enum (#24987) (camc314)
- 0c16cb5 oxfmt: [**BREAKING**] Format parser:yaml files by oxc_formatter_yaml (#24890) (leaysgur)

### 🚀 Features

- 1b57f78 oxfmt: Support tsx-in-vue (#25063) (leaysgur)
- be7f6da oxfmt: Colorize diff file list in check mode (#25061) (leaysgur)

### 🐛 Bug Fixes

- 68146bd formatter_css: Preserve glued plugin words in grid values (#25225) (leaysgur)
- 20f68e7 oxlint,oxfmt: Respect `.gitignore` for walk targets and explicit paths (#25133) (leaysgur)
- a9e76e9 oxfmt: Rework tsx-in-vue support (#25106) (leaysgur)
- dd28596 formatter_css: Bump oxc-css-parser for substituted at-rule preludes (#25104) (leaysgur)
- ca1ba71 formatter: Hug arrows with type-reference return annotations (#25044) (Pitiș Radu)
- f56009a oxfmt: Correct prose about comment width in fits measurement (#25054) (leaysgur)
- 22fdda4 oxfmt/conformance: Fix typo (#25053) (leaysgur)
- ee344bd formatter_yaml: Break long keys off a block scalar header (#25014) (leaysgur)
- d5e3476 formatter_yaml: Let ancestor collection values claim end comments after block scalars (#24897) (leaysgur)
- ec05297 formatter_yaml: Align sequence container end comments to the dash width (#24891) (leaysgur)
- e6e584b oxfmt: Type jsdoc. enum options (#25008) (leaysgur)

### ⚡ Performance

- b91d5a8 formatter_css,formatter_graphql,formatter_yaml,formatter_json: Pre alloc IR buffers (#25234) (leaysgur)

### 📚 Documentation

- eaa7c69 formatter_core: Extract FORMATTER_POLICY (#25233) (leaysgur)
- a1842e2 formatter_json: Fix outdated separeted.rs comments (#25144) (leaysgur)
- 193e16f formatter/jsdoc: Correct `str_width` attribution (#25142) (leaysgur)
2026-08-03 11:15:35 +00:00
renovate[bot] b937e3e2f1 chore(deps): update napi (#25019)
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Adoption](https://docs.renovatebot.com/merge-confidence/) |
[Passing](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) | Type |
Update |
|---|---|---|---|---|---|---|---|
| [@napi-rs/cli](https://napi.rs/)
([source](https://redirect.github.com/napi-rs/napi-rs)) | [`3.7.4` →
`3.8.2`](https://renovatebot.com/diffs/npm/@napi-rs%2fcli/3.7.4/3.8.2) |
![age](https://developer.mend.io/api/mc/badges/age/npm/@napi-rs%2fcli/3.8.2?slim=true)
|
![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@napi-rs%2fcli/3.8.2?slim=true)
|
![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@napi-rs%2fcli/3.7.4/3.8.2?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@napi-rs%2fcli/3.7.4/3.8.2?slim=true)
| pnpm.catalog.default | minor |
| [napi](https://redirect.github.com/napi-rs/napi-rs) | `3.11.0` →
`3.12.0` |
![age](https://developer.mend.io/api/mc/badges/age/crate/napi/3.12.0?slim=true)
|
![adoption](https://developer.mend.io/api/mc/badges/adoption/crate/napi/3.12.0?slim=true)
|
![passing](https://developer.mend.io/api/mc/badges/compatibility/crate/napi/3.11.0/3.12.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/crate/napi/3.11.0/3.12.0?slim=true)
| workspace.dependencies | minor |
| [napi-build](https://redirect.github.com/napi-rs/napi-rs) | `2.3.2` →
`2.4.0` |
![age](https://developer.mend.io/api/mc/badges/age/crate/napi-build/2.4.0?slim=true)
|
![adoption](https://developer.mend.io/api/mc/badges/adoption/crate/napi-build/2.4.0?slim=true)
|
![passing](https://developer.mend.io/api/mc/badges/compatibility/crate/napi-build/2.3.2/2.4.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/crate/napi-build/2.3.2/2.4.0?slim=true)
| workspace.dependencies | minor |
| [napi-derive](https://redirect.github.com/napi-rs/napi-rs) | `3.6.0` →
`3.6.2` |
![age](https://developer.mend.io/api/mc/badges/age/crate/napi-derive/3.6.2?slim=true)
|
![adoption](https://developer.mend.io/api/mc/badges/adoption/crate/napi-derive/3.6.2?slim=true)
|
![passing](https://developer.mend.io/api/mc/badges/compatibility/crate/napi-derive/3.6.0/3.6.2?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/crate/napi-derive/3.6.0/3.6.2?slim=true)
| workspace.dependencies | patch |

---

### Release Notes

<details>
<summary>napi-rs/napi-rs (@&#8203;napi-rs/cli)</summary>

###
[`v3.8.2`](https://redirect.github.com/napi-rs/napi-rs/compare/@napi-rs/cli@3.8.1...@napi-rs/cli@3.8.2)

[Compare
Source](https://redirect.github.com/napi-rs/napi-rs/compare/@napi-rs/cli@3.8.1...@napi-rs/cli@3.8.2)

###
[`v3.8.1`](https://redirect.github.com/napi-rs/napi-rs/compare/@napi-rs/cli@3.8.0...@napi-rs/cli@3.8.1)

[Compare
Source](https://redirect.github.com/napi-rs/napi-rs/compare/@napi-rs/cli@3.8.0...@napi-rs/cli@3.8.1)

###
[`v3.8.0`](https://redirect.github.com/napi-rs/napi-rs/compare/@napi-rs/cli@3.7.4...@napi-rs/cli@3.8.0)

[Compare
Source](https://redirect.github.com/napi-rs/napi-rs/compare/@napi-rs/cli@3.7.4...@napi-rs/cli@3.8.0)

</details>

---

### Configuration

📅 **Schedule**: (in timezone Asia/Shanghai)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/oxc-project/oxc).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODAuMCIsInVwZGF0ZWRJblZlciI6IjQ0LjMuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Cameron <cameron.clark@hey.com>
2026-08-03 11:21:03 +01:00
camc314 9d4592c72f fix(linter): reject duplicate JS plugin names (#25243)
## Summary
- reject JS plugins whose normalized names collide
- keep registered plugin names isolated per LSP workspace
- add a CLI regression fixture covering two plugins that expose the same rule name

Fixes #25164
2026-08-03 09:40:27 +00:00
Mikhail Baev 5c0fa61ddb fix(linter/eslint/no-warning-comments): unify config structs and remove manual options docs (#25151)
this PR unifies 2 config structs for `eslint/no-warning-comments` and
removes the manually written options doc, related issue: #14743.

Doc after fix:

<img width="919" height="1295" alt="image"
src="https://github.com/user-attachments/assets/dab8f999-fffa-4a77-8d6d-39746cfa3860"
/>
2026-08-01 19:26:30 +01:00
camc314 067da8c4e7 feat(ast)!: store single parameter in TSIndexSignature::parameter (#25154) 2026-07-31 20:35:37 +00:00
camc314 1bdedd11ca feat(ast)!: introduce ExportDeclaration, ExportFromDeclaration (#25095)
## Summary

Split the overloaded Rust `ExportNamedDeclaration` into syntax-specific AST nodes:

- `ExportDeclaration` for exported declarations
- `ExportNamedDeclaration` for local exports
- `ExportFromDeclaration` for re-exports

## Breaking Change

The Rust AST changes from:

```rust
pub struct ExportNamedDeclaration<'a> {
    pub node_id: Cell<NodeId>,
    pub span: Span,
    pub declaration: Option<Declaration<'a>>,
    pub specifiers: Vec<'a, ExportSpecifier<'a>>,
    pub source: Option<StringLiteral<'a>>,
    pub export_kind: ImportOrExportKind,
    pub with_clause: Option<Box<'a, WithClause<'a>>>,
}

pub enum ModuleDeclaration<'a> {
    // ...
    ExportNamedDeclaration(Box<'a, ExportNamedDeclaration<'a>>),
    // ...
}
```

to:

```rust
pub struct ExportDeclaration<'a> {
    pub node_id: Cell<NodeId>,
    pub span: Span,
    pub declaration: Declaration<'a>,
}

pub struct ExportNamedDeclaration<'a> {
    pub node_id: Cell<NodeId>,
    pub span: Span,
    pub specifiers: Vec<'a, ExportSpecifier<'a>>,
    pub export_kind: ImportOrExportKind,
}

pub struct ExportFromDeclaration<'a> {
    pub node_id: Cell<NodeId>,
    pub span: Span,
    pub specifiers: Vec<'a, ExportSpecifier<'a>>,
    pub source: StringLiteral<'a>,
    pub export_kind: ImportOrExportKind,
    pub with_clause: Option<Box<'a, WithClause<'a>>>,
}

pub enum ModuleDeclaration<'a> {
    // ...
    ExportDeclaration(Box<'a, ExportDeclaration<'a>>),
    ExportNamedDeclaration(Box<'a, ExportNamedDeclaration<'a>>),
    ExportFromDeclaration(Box<'a, ExportFromDeclaration<'a>>),
    // ...
}
```

## Why?

The previous node represented three distinct syntax forms through optional and mutually exclusive fields:

```text
export const value = 1;       -> ExportDeclaration
export { value };             -> ExportNamedDeclaration
export { value } from "mod";  -> ExportFromDeclaration
```

This allowed invalid combinations such as declarations with specifiers or sources, and import attributes without a source. The new nodes make these states unrepresentable and remove repeated `declaration`/`source` branching from consumers.

## How to migrate

Match the syntax-specific `ModuleDeclaration`, `Statement`, or `AstKind` variant instead of inspecting optional fields. Generated builders, visitors, traversal ancestors, and formatter wrappers now expose corresponding APIs for all three nodes.

Common field migrations:

| Previous representation | New representation |
| --- | --- |
| `declaration: Some(declaration)` | `ExportDeclaration { declaration }` |
| `declaration.as_ref()` | `&export.declaration` |
| `source.is_none()` for local exports | Match `ExportNamedDeclaration` |
| `source: Some(source)` | `ExportFromDeclaration { source }` |
| `source.as_ref().unwrap()` | `&export.source` |
| `with_clause` | Only available on `ExportFromDeclaration` |
| Stored `export_kind` on exported declarations | `ExportDeclaration::export_kind()` |
| `ExportNamedDeclaration::boxed_plain_declaration(...)` | `ExportDeclaration::boxed(...)` |
| `ExportNamedDeclaration::boxed(..., None, specifiers, None, ...)` | `ExportNamedDeclaration::boxed(..., specifiers, ...)` |
| `ExportNamedDeclaration::boxed(..., None, specifiers, Some(source), ...)` | `ExportFromDeclaration::boxed(..., specifiers, source, ...)` |

closes https://github.com/oxc-project/backlog/issues/219
2026-07-31 10:25:47 +00:00
camc314 9dc7756729 docs(linter/typescript/no-unnecessary-condition): clarify options (#25110)
## Summary

- document the exact allowConstantLoopConditions behavior, including the four directly allowed literals
- explain how always differs from only-allowed-literals
- add a checkTypePredicates example and regenerate the published configuration schema

Closes #25098
2026-07-30 10:29:51 +00:00
camc314 c917f204a7 feat(ast)!: introduce ArrowFunctionBody enum (#24987)
## Summary

- Introduces `ArrowFunctionBody` to represent concise expression and block bodies explicitly.
- Removes the `ArrowFunctionExpression::expression` boolean.
- Makes invalid arrow body combinations unrepresentable.

## Breaking Change

The Rust AST changes from:

```rust
pub struct ArrowFunctionExpression<'a> {
    pub expression: bool,
    pub body: Box<'a, FunctionBody<'a>>,
}
```

to:

```rust
pub enum ArrowFunctionBody<'a> {
    FunctionBody(Box<'a, FunctionBody<'a>>) = 64,
    INHERIT(Expression<'a>),
}

pub struct ArrowFunctionExpression<'a> {
    pub body: ArrowFunctionBody<'a>,
}
```

Concise arrow bodies are now stored directly as expressions instead of synthetic `FunctionBody` and `ExpressionStatement` nodes. Block bodies continue to use `FunctionBody`.

## Why?

The previous representation required consumers to maintain this implicit invariant:

```text
expression == true
→ no directives
→ exactly one statement
→ that statement is an ExpressionStatement
```

Invalid combinations could cause panics, skipped work, or fallback behavior. The enum encodes the grammar directly and makes those invalid states unrepresentable.

Concise expressions also now have `ArrowFunctionExpression` as their direct traversal ancestor, without synthetic `FunctionBody` or `ExpressionStatement` nodes.

## How to migrate

Use the arrow body accessors or match on `ArrowFunctionBody` rather than inspecting `expression` and synthetic statements.

Common field migrations:

| Previous representation | New representation |
| --- | --- |
| `arrow.expression` | `arrow.is_expression()` |
| `arrow.get_expression()` | `arrow.get_expression()` |
| `&arrow.body.statements` | `arrow.get_function_body().map(\|body\| &body.statements)` |
| `&mut arrow.body.statements` | `arrow.get_function_body_mut().map(\|body\| &mut body.statements)` |
| Synthetic expression statement in `arrow.body` | Direct `ArrowFunctionBody` expression variant |
| `arrow.body = function_body` | `arrow.body = ArrowFunctionBody::FunctionBody(function_body)` |
| Expression-to-block conversion | Create a `FunctionBody` containing a return statement |
| Block-to-expression conversion | Assign the expression directly to `arrow.body` |
| Builder `(expression, body)` arguments | Pass a single `ArrowFunctionBody` |

closes https://github.com/oxc-project/backlog/issues/211
2026-07-29 13:32:32 +00:00
oxc-guard 65fe65d842 release(apps): oxlint v1.76.0 && oxfmt v0.61.0 (#24976)
# Oxlint
### 🚀 Features

- 8d31dfa linter: Verify eslint/no-restricted-globals config schema (#24598) (vigneshwar)
- 7069621 linter: Verify jest/vitest prefer-lowercase-title config schema (#24724) (Bartok)
- 016cf2a linter/oxc: Add bad-match-all-arg rule (#24900) (camc314)
- cdc941e linter/n: Implement `exports-style` rule (#24087) (Mikhail Baev)
- 1ad6f6c linter/eslint: Implement `id-denylist` rule (#24632) (Mikhail Baev)
- 678bbb5 linter/typescript-eslint: Implement suggestion for `class-literal-property-style` rule (#24766) (Mikhail Baev)

### 🐛 Bug Fixes

- a5f3a0e linter: Mark missing suggestions as pending (#24956) (Mikhail Baev)
- a065946 oxlint: Absolutize explicit CLI paths even with --no-ignore (#24646) (Bez Sahara)
- 17688bb linter/jsx-a11y/interactive-supports-focus: Match eslint behavior for custom components (#24780) (Cole Ellison)
- 0aef19e linter/typescript/no-confusing-non-null-assertion: Report `in` and `instanceof` (#24825) (Mikhail Baev)
- 361dce9 linter: Unicorn/no-array-reverse and no-array-sort replacements should be suggestions (#24848) (klem)
- 9213560 config: Preserve defineConfig field JSDoc (#24326) (周星星同学)
- 334d884 linter/node/no-top-level-await: Clarify diagnostic (#24803) (camc314)
- b9fc6af linter/eslint/func-names: Ignore overloads (#24801) (camc314)
- e80574f estree: Handle empty spans serializing `ImportMeta` and `NewTarget` (#24775) (overlookmotel)

### ⚡ Performance

- c75dc60 linter: Avoid `Vec` allocations via `bound_names` (#24959) (connorshea)
- 9f9f39d linter/eslint/no-const-assign: Avoid `Vec` allocation per `const` declarator (#24953) (connorshea)
- 10a621e linter/typescript/adjacent-overload-signatures: Avoid collecting vec in some cases (#24874) (connorshea)
- ed167e1 linter/node/exports-style: Iterate once over global references (#24877) (connorshea)
- 69908fe linter: Avoid allocations in jest/no-deprecated-functions (#24866) (Connor Shea)
- a3585d7 linter: Speed up jest/vitest prefer-each (#24872) (Connor Shea)
- 62fe640 linter/eslint/prefer-rest-params: Run once per file (#24873) (Connor Shea)
- 7a7aa54 linter/eslint/no-this-before-super: Skip files without classes (#24869) (Connor Shea)
- 4ad0c94 linter/plugins: Faster copying comments to JS allocator (#24858) (overlookmotel)
- 4c25b91 linter/plugins: Test booleans with explicit `=== false` (#24830) (overlookmotel)
- b7add00 linter/plugins: Remove check in loop in `getDisableDirectives` (#24833) (overlookmotel)

### 📚 Documentation

- 3ff2e0e linter: Clarify config extends types (#24936) (Boshen)
# Oxfmt
### 🚀 Features

- eabfe01 oxfmt/lsp: Support `oxc.fmt.disableNestedConfig` (#24965) (leaysgur)
- 2357a10 formatter_yaml: Implement YAML formatter (#24534) (leaysgur)

### 🐛 Bug Fixes

- 761a882 formatter_css: Keep leading `+` in An+B to enable idempotency check (#24973) (leaysgur)
- e037709 formatter: Stop preserving indent for embedded template exprs (#24972) (leaysgur)
- ae1a39b formatter_css: Align wrapped selector-arg indent (#24971) (leaysgur)
- 143fd1f formatter: Align quoted `new` signature (#24883) (leaysgur)
- 07ff12f formatter_yaml: Fix indent, blank, and spacing issues (#24837) (leaysgur)
- d076b40 formatter: Check calee chain is_simple (#24871) (leaysgur)
- fb34196 formatter_css: Keep non-ASCII strings with quotes (#24870) (leaysgur)
- 9213560 config: Preserve defineConfig field JSDoc (#24326) (周星星同学)
- 31783e9 formatter_css: Print nested SCSS map with consistent indent (#24789) (leaysgur)
- 8eb9eca formatter/jsdoc: Respect `singleQuote` option in `@import` (#24787) (leaysgur)
- 6f05ac4 formatter: Fix template literal formatting (#24786) (leaysgur)

### ⚡ Performance

- bb73b23 formatter_core: Bound the thread-local scratch cache (#24793) (leaysgur)
- a5f7b15 formatter: Stage assignment-like left hand side on the heap (#24613) (leaysgur)
- 94de05f formatter: Accumulate JSX child-list builders on the heap (#24585) (leaysgur)
- 7810e8a formatter_core: Share one thread-cached scratch vector across staging buffers (#24583) (leaysgur)
- c191f51 formatter_core: Stage IR buffers on the heap to reduce arena memory (#24582) (leaysgur)

### 📚 Documentation

- 69126a0 formatter_css,fomatter_graphql,formatter_yaml: Update AGENTS.md (#24821) (leaysgur)
2026-07-27 15:17:12 +00:00
Boshen 3ff2e0e6fa docs(linter): clarify config extends types (#24936)
The generated config reference only described the JSON schema's `string[]` form. Clarify that `oxlint.config.ts` accepts imported `OxlintConfig[]`, add an example and public JSDoc, and regenerate the derived artifacts.

Closes #20238.

Validated with the website generator suite, targeted TypeScript checks, and the relevant Oxlint tests. The full `just ready` run reached an unrelated parallel suppression-fixture cleanup race; the failing test passes in isolation.

AI-assisted.
2026-07-27 01:51:16 +00:00
vigneshwar 8d31dfa393 feat(linter): verify eslint/no-restricted-globals config schema (#24598)
Part of #22955. Follow-up to the resolved #23617.

## What

`eslint/no-restricted-globals` stayed in `NO_VERIFIED_VALID_SCHEMA`
after #23617 was resolved, because the derived schema described the
internal `NoRestrictedGlobalsConfig` struct (a `globals` hash map)
rather than the user-facing positional-array format the rule actually
parses.

This PR adds a hand-written `JsonSchema` following the existing
`no-restricted-imports` pattern, describing the three accepted
positional item forms:

1. `"event"` — a global name string
2. `{ "name": "event", "message": "…" }` — a name/message object
3. `{ "globals": [ … ], "checkGlobalObject": true, "globalObjects": [ …
] }` — the object form added in #23617

Generated TS declaration:

```ts
"no-restricted-globals"?:
  RuleNoConfig | [AllowWarnDeny, NoRestrictedGlobalsConfigEnum, ...NoRestrictedGlobalsConfigEnum[]];
export type NoRestrictedGlobalsConfigEnum = string | RestrictedGlobal | NoRestrictedGlobalsObjectConfig;
```

Verified against the #22955 checklist: reflects all accepted user
configuration forms, denies unknown fields on object forms, and produces
no `[k: string]: unknown` in the TS declaration. `from_configuration`
and rule behavior are unchanged; rule tests pass.

Note: this branch removes only the `no-restricted-globals` entry from
`NO_VERIFIED_VALID_SCHEMA`; #24586 (separate PR) removes the
`filename-case` entry, so whichever merges second will have a trivial
conflict in that array.

## Disclosure

This contribution was developed with assistance from Claude Code
(Anthropic); I have reviewed and tested all changes.

---------

Signed-off-by: Alexander S. <sysix@sysix-coding.de>
Co-authored-by: Alexander S. <sysix@sysix-coding.de>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-07-26 16:55:55 +02:00
Bartok 7069621199 feat(linter): verify jest/vitest prefer-lowercase-title config schema (#24724)
## Summary

- Unskip `jest/prefer-lowercase-title` and
`vitest/prefer-lowercase-title` from `NO_VERIFIED_VALID_SCHEMA`.
- PreferLowercaseTitleConfig already derives `Deserialize` +
`JsonSchema` with `deny_unknown_fields` and docs for all public options,
so the generated schema/types can describe the real config.
- Regenerates `npm/oxlint/configuration_schema.json` and
`apps/oxlint/src-js/package/config.generated.ts`.

## Motivation

Part of #22955. These two plugin names shared a clean config struct
already used at runtime; they were still emit-as-`DummyRule` only
because of the broader #23186 split note (mainly about `valid-title`
option divergence). Leaving `valid-title` skipped.

Generated config now exposes:

- `allowedPrefixes: string[]` (default `[]`)
- `ignore: string[]` (default `[]`)
- `ignoreTopLevelDescribe: boolean` (default `false`)
- `lowercaseFirstCharacterOnly: boolean` (default `true`)
- `additionalProperties: false` / no `[k: string]: unknown`

## Verification

- `cargo test -p website_linter` — 8 passed
- `cargo test -p oxc_linter --features ruledocs
test_rules_with_custom_configuration_have_schema` — passed
- `cargo test -p oxc_linter prefer_lowercase_title --lib` — 2 passed
(jest + vitest)
- Inspected generated schema/TS: not DummyRule; no index signature

## AI disclosure

Assisted by AI (Hermes/Sera). I reviewed the existing
PreferLowercaseTitleConfig against the GFI checklist, regenerated
schema/types locally, and ran the tests above.

---
**Agent-Owner:** `sera` · **Platform:** hermes · **Claim:** `sera`

---
<!-- fleet-pr-claim: agent_id=sera platform=hermes -->
**Agent-Owner:** `sera` · **Platform:** hermes · **Claim-TTL:** 24h

---------

Co-authored-by: Bartok9 <259807879+Bartok9@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-07-26 10:30:37 +08:00
camc314 016cf2acd6 feat(linter/oxc): add bad-match-all-arg rule (#24900)
## Summary

- add oxc/bad-match-all-arg for non-global regular expressions passed to matchAll
- share cycle-safe RegExp flag resolution with bad-replace-all-arg
- support callable and global-qualified RegExp constructors
- update generated metadata, diagnostics, timings, and CLI rule-count snapshots

Closes #24823.
2026-07-24 14:48:45 +00:00
overlookmotel 99d263b123 refactor(linter/plugins): simplify getDisableDirectives (#24852)
Pure refactor, except for fixing a TS type, and correcting some comments. Runtime behavior is unaltered.

- `LABEL_PATTERN` captures the directive type as well as the label, so the multi-line check is a
single comparison, and `type` no longer comes from `label.slice(7)`.
- Numbered capture groups instead of named ones, so the match check is just `match === null`.
- `match` is no longer reused for a second, unrelated regex.
- `justification` is always set, so it's not optional - correct the type def accordingly.
- Simplify splitting off `justification`.
- Doc comment referenced `match_disable_directive` / `match_enable_directive`. The Rust function is
`match_directive` - correct the comment.
2026-07-23 16:59:45 +00:00
overlookmotel c126eebef6 refactor(linter/plugins): remove dead code in getDisableDirectives (#24851)
`LINE_DIRECTIVE_PATTERN` had a stray hyphen (`disable-(?:-next)?-line`), so it only matched
`disable--line` / `disable--next-line` - strings `LABEL_PATTERN` can never produce. Therefore it was dead code - remove it.

If the regex _was_ correctly written, the behavior would be wrong. Looks like this is a hangover from the code being taken from ESLint.
2026-07-23 16:59:44 +00:00
overlookmotel 3446ee7ebc test(linter/plugins): check comments and tokens within bounds of source text (#24832)
Add more debug assertions to debug build-only code which checks the validity of comments and tokens.

Make sure all comments and tokens have spans which are wihin bounds of source text. In particular, this will surface any problems where the source text contains a BOM, which causes us to adjust spans on Rust side when trimming off the BOM.
2026-07-23 09:29:53 +00:00
overlookmotel f5b9e01cf6 refactor(linter/plugins): remove unnecessary type asserts (#24831)
Pure refactor. Remove some type assertions which were unnecessary - TS already knows these vars can't be `null`.
2026-07-23 09:29:53 +00:00
overlookmotel 4c25b91c64 perf(linter/plugins): test booleans with explicit === false (#24830)
Tiny perf optimization to linter plugins.

`if (x === false)` is longer than `if (!x)`, but is more performant. The 1st compiles down to a simple equality check between `<value x>` and `kFalse` constant, whereas the 2nd is more like `coerceToBoolean(<value x>) === kFalse` - a more expensive operation.

This follows our convention in all JS plugins code of always using explicit `=== false` / `=== true` comparisons.
2026-07-23 09:29:53 +00:00
overlookmotel f85e47d7e6 refactor(linter/plugins): add debug asserts (#24829)
Pure refactor. Use debug asserts instead of type assertions in code for deserializing comments and tokns. This gives better error messages if we break the invariants in tests. Makes no difference in release build.
2026-07-23 09:29:52 +00:00