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.
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.
Rejects initialized `let` and `const` declarations in `for...in` during parsing while preserving Annex B's non-strict `var` form.
Adds misc coverage for valid and invalid initializer forms.
Verified with `just ready` and parser conformance.
Closes#25149.
AI-assisted.
Quoted constructor methods bypassed the AST-based constructor validation. Validate type parameters after resolving the method key, preserving the AST shape.
Validation: `just ready`, parser conformance, and allocation checks.
Closes#25692.
AI-assisted with Codex.
## 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
## Summary
- run typescript/no-var-requires on JavaScript files
- match typescript-eslint behavior and prevent false unused-disable diagnostics
Fixes#25623.
## Summary
- flag declaration-level TypeScript type-only named default imports
- preserve inline type specifier behavior to match eslint-plugin-import
- add regression and disable-directive coverage
- regenerate rule dispatch and timing metadata
Closes#25613
NOTE: For now, behavior is the same as Prettier.
- Default is `end`
- This works on intersection(`&`) type, but has no effect on union(`|`) type
For future refs: https://github.com/oxc-project/oxc/issues/16367
## Summary
Fix private-name mangling for `get #x()` / `set #x(value)` accessor pairs.
JavaScript treats an accessor pair as one private name, but the mangler previously assigned a candidate per element before collecting into a name-keyed map. The setter overwrote the getter’s mapping, while still consuming an extra candidate.
### Before
```js
class Outer {
get #x() {}
set #x(value) {}
#longName;
nested() {
return class {
#nestedName;
};
}
}
```
```js
class Outer {
get #t() {}
set #t(e) {}
#n;
nested() {
return class {
#r;
};
}
}
```
### After
```js
class Outer {
get #e() {}
set #e(e) {}
#t;
nested() {
return class {
#n;
};
}
}
```
## Implementation
- Deduplicate private names during map construction with `HashMap::entry`.
- Derive nested-class offsets from already-built lexical parent mappings, preserving collision avoidance.
- Pre-size mappings from the number of private elements.
Quoted JSX attribute values do not use ECMAScript escape sequences. Skip strict-mode legacy escape validation for JSX attributes and cover the behavior in misc conformance.
AI-assisted by Codex.
Slots were assigned to non-manglable symbols as well. This made the slot re-use non-optimal.
This PR fixes that.
I used AI to find out this bug and to generate the code and then reviewed the code.
## Summary
Make Codegen conformance failures visible when the Rust reference panics.
- Preserve `null` for source text with parser diagnostics.
- Return a N-API error for a caught reference panic.
- Let Vitest fail the affected fixture instead of silently skipping it.
Pin the Codegen benchmark fixture to an immutable `benchmark-files` commit. This makes benchmark inputs reproducible and prevents `main` updates from silently changing results.
Stop parsing delimited-list elements after a separator when EOF or an undetermined token follows, preventing malformed tuple syntax from creating reversed spans during error recovery.
Validated with `cargo coverage -- parser --filter oxc-23670 --detail`.
AI assistance was used to prepare this change.
Closes#23670.
Add `oxc-codegen` package - a printer written in TS.
### Features
- Prints JS, JSX, TS, TSX.
- Matches `oxc_codegen` exactly on all Test262, TypeScript, Acorn-JSX fixtures.
- Very fast.
### Deficiencies
- Pretty-printing only (no compact/minified output).
- No support for printing comments.
- Source map support is semi-there, but largely untested, and poor API (design doc has some ideas on how to improve it).
### This PR adds
- The printer code.
- Conformance testing infra.
- Further tests for edge cases.
- README.
- Design doc - how it differs from `oxc_codegen` and why, what produces the perf.
### This PR doesn't add
- Not integrated into CI or release pipeline.
### Notes
This started as a slop port of `oxc_codegen`. I've iterated on that base, cleaned it up a lot, and at least skimmed through all of it. I think it's in fairly decent shape.
The design doc is I think worth a read. It explains the rationale for the choices, in particular the "1 codebase, 4 builds" approach.
I've put it in a new top-level directory called `packages`. It's not an app, so didn't seem to me to fit alongside `apps/oxlint` and `apps/oxfmt`. It's pure JS, so not like e.g. `napi/parser`. And it felt too heavyweight to put into `npm` dir. But maybe there's a better place for it.
Co-authored-by: Cameron <cameron.clark@hey.com>
Fixes#23681.
Preserve initial fatal parser errors during top-level `await` reparsing, preventing malformed recovery AST nodes from reaching Oxlint.
Validated with parser unit/conformance suites and allocation snapshots. `just ready` only fails three unrelated ANSI snapshot checks in the current environment.
AI-assisted.
Fix the transformer conformance runner incorrectly marking a fixture as passed that specified `throws` when Oxc produces no error.
Failed conformance cases now always record a diagnostic. This exposes previously hidden failures in the Babel snapshot, including the nested ambient-module fixtures.
Remove the Prettier related stuff from the conformance, which is purely aimed at JS/TS.
Instead, `oxc_formatter_tests` manage Prettier's test fixtures along with Oxfmt.
Replace the generated `RuleEnum::name` match with an ID-indexed static table. This reduced the macOS arm64 release binary by 16,512 bytes (0.118%).
AI assistance was used to analyze binary size and prepare this change. The author reviewed the generated code and measurements.
Co-authored-by: Cameron Clark <cameron.clark@hey.com>
The automated submodule bump #25261 regenerated `runtime.snap` on a loaded CI runner where two tests hit the global timeout, recording transient `timeout: global` failures (`expressions/arrow-function/name.js`, `function-code/10.4.3-1-13-s.js`) and dropping the pass count from 17306 to 17304. Both tests pass on a normal run, so monitor-oxc's Test262 drift check has failed on every run since ([example](https://github.com/oxc-project/monitor-oxc/actions/runs/31359248351/job/93364683855)).
This restores the snapshot to what `cargo coverage runtime` actually produces. Rather than regenerating locally (which could bake in this machine's own timeouts), the CI-reported diff was applied directly and verified byte-identical to CI's output (`git hash-object` matches the diff's `65e3fa9` blob).
Timeouts can get baked in again whenever an automated regen lands on a slow runner; retrying timed-out tests before recording them would close that hole and is left for a follow-up.
This PR was assisted by Claude.
Generate `from_configuration` match arms only for the 341 rules that override the default implementation. The other 508 rules clone their default value from `RULES`.
This reduces the release oxlint binary from 13,963,312 to 13,946,800 bytes (-16,512 bytes).
AI-assisted.
As JSDoc is always contained within the ` * ` fenced comments, the `printWidth` option should not have been used as is.
The dedicated `jsdocPrintWidth` option has not yet been implemented. #24633
- dispatcher
- string_embedder
- tailwind_sorter
Group these 3 together as `SessionServices`, make them available to `FormatSession`, and pass them around.
In theory, the group id needs to function across embedded boundaries.
To achieve this, a "session" mechanism that can be carried over those boundaries was required.
revert #24813 currently there is no way to validate if stmt can be
removed if its inside a block
correct issue with incorrect removal of `return` stmt not at termination
points
```js
(function() {
label: {
console.log('before return');
return;
}
console.log('unreachable!');
})();
```
ref: https://github.com/rolldown/rolldown/issues/10555
## Summary
- parse ordinary class field initializers as `AssignmentExpression`
- reject unparenthesized comma expressions while preserving
parenthesized sequence expressions
- add paired misc conformance fixtures and update the generated
snapshots
## Root cause
Ordinary class field initializers used `parse_expr`, which accepts a
top-level comma and constructs a sequence expression. The ECMAScript
`Initializer` grammar requires an `AssignmentExpression`, so the
unparenthesized comma must remain for the class-element terminator check
to reject.
## Summary
- Align auto-accessor initializer parsing with class-field initializer grammar.
- Add regressions for `in` in a `for` initializer and disallowed inherited `await`/`yield` contexts.
## Root cause
The auto-accessor path only enabled `new.target`. It therefore inherited outer `~In`, `Await`, and `Yield` grammar contexts: `a in b` could not parse in a `for` initializer, while `await` and `yield` could incorrectly parse from enclosing async/generator functions. The fix applies the same `In | NewTarget` addition and `Yield | Await` removal already used for class fields, while retaining AssignmentExpression parsing.
## References
- [ECMAScript `FieldDefinition` grammar](https://tc39.es/ecma262/#prod-FieldDefinition)
- [ECMAScript `Initializer` grammar](https://tc39.es/ecma262/#prod-Initializer)
- [TC39 decorators proposal: class auto-accessors](https://github.com/tc39/proposal-decorators#introduction)
## Summary
- Track trailing-comma spans only for array and object literals ending in a spread.
- Consume the stored span while covering a rest assignment target.
## Rationale
Avoids parser-state map work for ordinary trailing commas while retaining constant-time diagnostics for invalid rest-target trailing commas.
## 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
## 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
Quoted module names are only valid in ambient contexts in TypeScript, but we were accepting them in regular TypeScript files.
This reports TS1035 when a quoted module name appears outside a declaration file or ambient declaration. The conformance snapshots now cover both TypeScript cases, and the old invalid codegen fixture has been replaced with a valid internal module declaration.