mirror of
https://github.com/oxc-project/oxc.git
synced 2026-09-14 19:36:11 +08:00
agent/react-compiler-dynamic-import
2006 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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. |
||
|
|
2dd7446b8f |
perf(diagnostics): preallocate graphical output (#25721)
Preallocate graphical reporter output from observed per-diagnostic size. Criterion: single ASCII -13.7%, batch ASCII -5.7%, Unicode/tab -2.0%. AI-assisted. <sub>Stack created with <a href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub> |
||
|
|
9c8abab7a7 |
perf(diagnostics): batch graphical reports (#25710)
Batch graphical diagnostics so reports sharing a source reuse line indexing, and route oxlint diagnostic batches through the new API. AI assistance: Codex was used. The contributor remains responsible for this change. <sub>Stack created with <a href="https://github.com/github/gh-stack">GitHub Stacks CLI</a></sub> |
||
|
|
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. |
||
|
|
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 |
||
|
|
4004c101ca |
fix(linter/eslint/no-irregular-whitespace): check comments by default (#25660)
## Summary - align the skipComments default with ESLint - report irregular whitespace in line and block comments by default - preserve the skipComments: true opt-out - verify suppressed comment diagnostics count disable directives as used - regenerate the published configuration schema Fixes #25616. |
||
|
|
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 |
||
|
|
a38f7b3d57 |
fix(oxlint,oxfmt): apply .gitignore only to walk targets, not explicitly named files (#25531)
Possibly fixes #25259, and partial revert of #25133. --- - `.gitignore` applies only to discovery (walking directory targets, cwd, globs) - An explicitly named file target is linted / formatted even when gitignored - = Restoring the pre-[#25133]() behavior for files, while fully keeping the [#25107]() fix for walk roots | Target | Current | This PR | | --- | --- | --- | | Explicit file (`oxlint dist/a.js`) | skipped | linted | | Explicit directory (`oxlint dist`) | skipped | skipped | | cwd inside ignored tree | skipped | skipped | The underlying principle: > `.gitignore` is a message addressed to git, not to tools. > Borrowing it to scope discovery is a useful heuristic, and a heuristic may narrow what the walk finds, but never refuse what the user names. > Only tool's own ignore config can refuse. (which remain hard for the husky staged-file case). This also re-aligns the CLI with stdin and LSP, which deliberately do not consult `.gitignore` (#19206). 👉🏻 This is the main motivation. ### Why not full revert A directory target names where to search, not what to process. The files under it are still discovered by the walk, so discovery rules apply. Reverting that would bring back [#25107](), whose old behavior was not even a statable spec: whether running inside an ignored tree processed anything depended on the ignore pattern's form (bare `generated` did, `generated/**` didn't), an artifact of walker pruning, not a design. ### Regarding to `--no-ignore` This flag remains orthogonal as a walk-level opt-out (`--no-ignore=vcs dist`) and for filling gap between existing tools. However, with explicit files working again, I'm inclined to close those PRs and revisit if demand shows up. For [#25259]()'s use case: name the files, e.g. `oxlint dist/foo.js` (or shell-expanded glob). |
||
|
|
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
|
||
|
|
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 |
||
|
|
9771ee151c |
test(linter): give the prune test its own suppression fixture directory (#25445)
`test_suppressing_errors_update_the_file_when_errors_are_decreased` and `test_prunning_errors_update_the_file_when_errors_are_decreased` both point at `fixtures/suppression/with_arg_and_decreased_errors`. Every other `SuppressionTester` fixture has a single owner. Both of these run oxlint in that directory, which rewrites `oxlint-suppressions.json`, and both then delete it and restore it from the backup in `Drop`. It showed up as an intermittent red in `just ready` while I was working on something unrelated, and it cost enough re-runs that I went looking. I flagged it at the end of #25412. This is that fix. Measured with `cargo test -p oxlint suppress`, ten runs per setting, on an 18 core machine: ``` --test-threads failures 1 0/10 12 0/10 16 0/10 17 0/10 18 3/10 20 0/10 24 0/10 ``` 18 is `hw.ncpu` there, and it is what `cargo test` picks by default. 20 and 24 are more parallel and never failed, so this is not load and it is not machine speed. The two tests have to land in the same dispatch wave, which depends on the divisor. The `Test Linux` job runs `cargo test --all-features` and stays green, which I read as a different core count rather than anything about the runner. Three distinct failure modes came out of the one shared directory: ``` tester.rs:249 one test's opening assert runs while the other sits between remove_file and fs::copy tester.rs:295 both Drop calls delete the same path, and the second gets ENOENT tester.rs:274 one test reads the file while the other is inside a truncating write ``` Before settling on the fixture split I checked whether repairing `Drop` would be enough, since deleting before copying is what opens the widest window. It is not enough. Guarding the delete with `&& !self.have_backup_file`, so the file is never absent, left the rate where it was and only changed the message: ``` Drop shape directory failures delete then copy, as today shared 3/20 copy only shared 4/40 unchanged separate 0/40 ``` To find out what the reader was actually getting in that third mode, I patched the panic at `tester.rs:274` to print the observed content. That patch was throwaway and is not in this diff: ``` PROBE observed len=0 serde=EOF while parsing a value at line 1 column 0 first80="" ``` Length zero, not a torn file. `SuppressionFile::save` uses `fs::write`, which is `File::create` plus `write_all`, and `File::create` opens with `O_TRUNC`. The truncate commits at open time and the bytes arrive on the next syscall, so the file is briefly empty. A separate directory is the only change that closes both that window and the `Drop` one. Calling out one thing up front: the new directory is a byte for byte copy of the old one. `--suppress-all` and `--prune-suppressions` converge in the decreased case, so the expected content is the same for both tests. The directory exists for isolation, not for content. `with_arg_and_increased_errors` and `with_arg_and_increased_errors_prune` are the same split for the case where the two commands diverge, so five of six files match there and six of six match here. This is the same shape as #20717, where `--init` writes leaked across parallel tests. With the change in, the suppression module is 0/20 at 18 threads and 0/10 at the default. The rest of `just ready` is green as well: `typos`, `cargo lintgen`, `just fmt`, `just check`, `just test`, `just lint`, `just doc` and `just ast`, with 4446 tests passing under `--test-threads=1`. Three other suppression fixtures have more than one owner, and I left all three alone. `fixed_violations_are_reported` has two readers. `type_check_only_with_regular_rule` also has two, and although the second passes `--suppress-all` and `--prune-suppressions`, `lint.rs:426` rejects that combination before any lint runs, so nothing writes. `diagnostics_filtered_if_count_is_the_same` is the only other one where a write really happens, so it carries the truncating write window in principle, but that window is a single `fs::write` over a few hundred bytes, where the one this PR fixes spanned a whole `Drop` delete-then-copy plus the other test's entire run. Forty runs with those two tests forced to overlap found nothing. I did not want to change something I cannot show is broken. Happy to fold it in if the whole class should close in one go. Disclosure, per CONTRIBUTING.md: I used Claude for the investigation and for the patch. I have reviewed and tested all of it myself. |
||
|
|
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. |
||
|
|
82c924496c |
refactor(diagnostics): clean up vendored renderer (#25501)
Clean up the diagnostics renderer vendored after removing `oxc-miette`: simplify source attachment and multiline labels, tighten visibility, and correct JSON escaping and debug formatting. Validated with `just ready`. AI-assisted; contributor review is required before merge. |
||
|
|
00e1b762e0 |
refactor(diagnostics): vendor oxc-miette (#25499)
We no longer need to maintain the `oxc-miette` repo as most of the code is now removed, the remaining code is minimal and can be vendored. |
||
|
|
2d7a75d46b |
chore(deps): update oxc to ^0.144.0 (#25483)
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/) | |---|---|---|---|---|---| | [@oxc-project/types](https://oxc.rs) ([source](https://redirect.github.com/oxc-project/oxc/tree/HEAD/npm/oxc-types)) | [`^0.143.0` → `^0.144.0`](https://renovatebot.com/diffs/npm/@oxc-project%2ftypes/0.143.0/0.144.0) |  |  |  |  | | [oxc-parser](https://oxc.rs/docs/guide/usage/parser) ([source](https://redirect.github.com/oxc-project/oxc/tree/HEAD/napi/parser)) | [`^0.143.0` → `^0.144.0`](https://renovatebot.com/diffs/npm/oxc-parser/0.143.0/0.144.0) |  |  |  |  | --- ### Release Notes <details> <summary>oxc-project/oxc (@​oxc-project/types)</summary> ### [`v0.144.0`](https://redirect.github.com/oxc-project/oxc/blob/HEAD/npm/oxc-types/CHANGELOG.md#01440---2026-08-10) ##### 💥 BREAKING CHANGES - [`44fd320`](https://redirect.github.com/oxc-project/oxc/commit/44fd320) ast: \[**BREAKING**] Split TS external modules & Namespace Declarations ([#​25284](https://redirect.github.com/oxc-project/oxc/issues/25284)) (camc314) </details> <details> <summary>oxc-project/oxc (oxc-parser)</summary> ### [`v0.144.0`](https://redirect.github.com/oxc-project/oxc/blob/HEAD/napi/parser/CHANGELOG.md#01440---2026-08-10) ##### 💥 BREAKING CHANGES - [`a33788e`](https://redirect.github.com/oxc-project/oxc/commit/a33788e) ast: \[**BREAKING**] Group class heritage into `ClassHeritage` ([#​25360](https://redirect.github.com/oxc-project/oxc/issues/25360)) (camc314) - [`5c5cdcd`](https://redirect.github.com/oxc-project/oxc/commit/5c5cdcd) ast: \[**BREAKING**] Narrow `TSInterfaceHeritage::expression` to TSTypeName ([#​24360](https://redirect.github.com/oxc-project/oxc/issues/24360)) (camc314) - [`6be314f`](https://redirect.github.com/oxc-project/oxc/commit/6be314f) ast: \[**BREAKING**] Remove duplicated `VariableDeclarator::kind` ([#​25319](https://redirect.github.com/oxc-project/oxc/issues/25319)) (camc314) - [`44fd320`](https://redirect.github.com/oxc-project/oxc/commit/44fd320) ast: \[**BREAKING**] Split TS external modules & Namespace Declarations ([#​25284](https://redirect.github.com/oxc-project/oxc/issues/25284)) (camc314) ##### 🐛 Bug Fixes - [`2a1058a`](https://redirect.github.com/oxc-project/oxc/commit/2a1058a) napi: Omit parser header from WASI declarations ([#​25254](https://redirect.github.com/oxc-project/oxc/issues/25254)) (camc314) </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 these updates 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:eyJjcmVhdGVkSW5WZXIiOiI0NC4xMi4wIiwidXBkYXRlZEluVmVyIjoiNDQuMTIuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
c42d6397ea |
release(apps): oxlint v1.78.0 && oxfmt v0.63.0 (#25473)
# Oxlint ### 💥 BREAKING CHANGES - |
||
|
|
030857b509 |
refactor(diagnostics): update oxc-miette to v4 (#25395)
Remove the miette `Report` wrapper and update oxc-miette to v4's narrowed diagnostic and source protocol. AI-assisted by OpenAI Codex. |
||
|
|
a92c5410a1 |
fix(linter): preserve source text for JS plugin ignore fixes (#25280)
Closes #25278 ## Overview This PR resolves an oxlint language server crash that could occur when requesting code actions for diagnostics reported by JS plugins, particularly when the diagnostic appears after the beginning of a file. JS plugin diagnostics can now safely provide regular fixes as well as line-level and file-level disable actions. ## Root cause 1. In `run_external_rules()`, the `semantic` is being taken to run the external JS plugin rules, leaving the former `semantic` inside the context host empty: https://github.com/oxc-project/oxc/blob/e23dccf338d568ac0c2be3b1223f213c797923f7/crates/oxc_linter/src/lib.rs#L539 2. The language server enables `with_ignore_fixes` to generate ignore fixes, but inside the `add_ignore_fix()`, it doesn't check the `section_source_text`. 3. The context host with the empty `semantic` passes the empty source text to the `add_ignore_fix()` as `section_source_text`, and the empty string just causes the crash. https://github.com/oxc-project/oxc/blob/e23dccf338d568ac0c2be3b1223f213c797923f7/crates/oxc_linter/src/context/host.rs#L329-L334 ## What changed A new property `source_text` is added to the context sub host, which stores a reference to the real source text string. Even if the `semantic` is taken and becomes empty, the reference can still get the real string and make things work. ```diff pub struct ContextSubHost<'a> { /// Semantic information about the file being linted, which includes scopes, symbols and AST nodes. /// See [`Semantic`]. pub(super) semantic: Semantic<'a>, // ... + /// Stable source text for this script section + /// which remains available even after `semantic` is taken while running JS plugins. + pub(super) source_text: &'a str, /// The source text offset of the sub host pub(super) source_text_offset: u32, } ``` And I added a new utility method to get the `source_text` from the context sub host. ```rs #[inline] pub fn source_text(&self) -> &'a str { self.current_sub_host().source_text() } ``` When passing source text to `add_ignore_fix()`, just use the new `source_text()` method. ```diff if self.with_ignore_fixes { - let source_text = self.semantic().source_text(); + let source_text = self.source_text(); for diagnostic in &mut diagnostics { diagnostic.add_ignore_fix(self.current_sub_host().source_text_offset, source_text); } } // (the same as other occurs ``` Also, I added the necessary check for the `section_source_text` in `add_ignore_fix()`. ## Notes This is my first contribution to oxc project. Thanks for reviewing! |
||
|
|
c7583238a0 |
refactor(lsp): add ToolBuildResult struct for optional client message (#25386)
Added a new `ToolBuildResult` struct, so an optional `ClientMessage` can be passed to `Backend` (in a later PR). This allows us later to send the custom message to the clients interface when some config errors happened on the (re)creation. There is no message sent yet, this will be integrated in another PR too. This PR is just the base for the `ToolInterface`. |
||
|
|
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
|
||
|
|
4ec9189b26 |
perf(oxlint/lsp): avoid second lock for getting/removing unused directives (#25350)
Avoids a second lock for `.map` inside `DirectivesStore` when consuming the directives on `--lsp` side. |
||
|
|
6c0d01b8de |
perf(oxlint/lsp): preallocate fix-content vec (#25351)
After https://github.com/oxc-project/oxc/pull/24958 we know the size of `Vec<FixedContent>` , because we are only consuming now `Messages.fixes` which are directly mapped into `FixedContent` |
||
|
|
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
|
||
|
|
6b1c4795b2 |
fix(oxlint): normalize customized rule names (#25316)
## Summary - normalize LSP `rulesCustomization` keys using the linter config rule-name parser - support `eslint/` prefixes and existing plugin aliases such as `@typescript-eslint` - cover prefixed severity and autofix customization paths Closes #25311 |
||
|
|
ccb8fe89db |
feat(linter/jsdoc): implement no-blank-blocks rule (#25207)
this PR implements `jsdoc/no-blank-blocks` rule, issue #1170 |
||
|
|
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` |
||
|
|
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
|
||
|
|
4abff11c80 |
perf(linter): avoid redundant message work in the agent reporter (#25315)
Generated with Claude Code, Opus 5. Reviewed and tested by me. Mainly just avoiding extra, unneeded allocations per-diagnostic. This shouldn't matter much at normal scales, but given that many people are using Claude Code, Codex, etc for setting up their linter config or to mass-resolve lint violations, I think the tradeoff in extra code here is probably worth it because there are definite cases where this will be getting triggered with large diagnostic counts. I will admit the `is_already_compact` method here is jank, though. --- Two small changes to `format_agent`, both removing work that was already done. **1. Borrow already-compact messages.** `compact_message` rebuilt every message into a fresh `String` by splitting on whitespace and rejoining, even though nearly every rule message is already compact and comes out byte-for-byte identical. It now checks first and borrows when there is nothing to collapse, falling back to the rebuild otherwise. **2. Reuse the message `Info` already rendered.** `Info::new` calls `diagnostic.to_string()` internally; `format_agent` discarded that and rendered it a second time. It now takes the message from `Info`. `Info` only fills the message in when the diagnostic has a resolvable label, so the direct render is kept for the label-less case — which the existing `reporter_error_without_label` test covers. ## Allocations Measured with a counting global allocator, `--threads=1` for deterministic counts, on a corpus of 20k small files producing exactly 2,400,000 diagnostics. `unix` is a control (untouched by this PR) and `--silent` is the no-formatter baseline. | format | main allocs | branch allocs | diff | change | | --- | ---: | ---: | ---: | ---: | | silent (baseline) | 55,672,894 | 55,672,894 | 0 | 0.00% | | unix (control) | 91,353,791 | 91,353,791 | 0 | 0.00% | | agent | 124,894,389 | 104,194,389 | -20,700,000 | -16.57% | Subtracting the baseline to isolate the formatter itself: | | main | branch | change | | --- | ---: | ---: | ---: | | agent formatter allocations | 69,221,495 | 48,521,495 | **-29.9%** | | per diagnostic | 28.84 | 20.22 | -8.62 | | bytes requested | 8.39 GB | 7.66 GB | -729.7 MB | Worth noting that the saving is much larger than the two `String`s the diff visibly removes. `diagnostic.to_string()` is not one allocation — rendering an `Error` goes through miette formatting, which allocates repeatedly — so removing the duplicate render is worth around 8 allocations per diagnostic, not one (we should maybe consider figuring out if we can fix that separately to reduce the allocations per diagnostic, but usually there aren't too many diagnostics so it's a minor improvement). ## Timing Paired-difference measurement: samples interleaved one-for-one between the two binaries and differenced pairwise, so drift cancels. `unix` again as control. | corpus | format | main | branch | diff | 95% CI | change | | --- | --- | ---: | ---: | ---: | :---: | ---: | | 20k small files (2.4M diagnostics) | agent | 3837ms | 3272ms | -564.4ms | [-590.7, -538.2]ms | -14.7% | | 20k small files (2.4M diagnostics) | unix (control) | 2846ms | 2832ms | -14.2ms | [-39.4, +10.9]ms | -0.5% | | vscode `-D all` (1.37M diagnostics) | agent | 13721ms | 13381ms | -339.8ms | [-511.6, -168.0]ms | -2.5% | | vscode `-D all` (1.37M diagnostics) | unix (control) | 12794ms | 12781ms | -12.9ms | [-70.1, +44.4]ms | -0.1% | ## Equivalence Confirmed byte-identical output from the formatter on main vs this branch over VS Code. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
6bb5421c4a |
perf(linter): hoist current_dir out of the stylish reporter loop (#25313)
AI Disclosure: Generated with Claude Code, reviewed and tested by me. Just a micro-optimization. The stylish reporter calls `std::env::current_dir()` once per file group, in order to canonicalize each filename for display. That is a syscall, and the result is identical for every group, so this reads it once before the loop and borrows it. Output is unchanged — `current_dir()` is not expected to vary mid-run, and the value is used the same way. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
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
|
||
|
|
9a7c323500 |
perf(linter): compute diagnostic Info once per diagnostic in junit reporter (#25312)
AI Disclosure: Generated with Claude Code, Opus 5. Tested and reviewed by me for correctness. --- `format_junit` built an `Info` for every diagnostic twice: once to group diagnostics by filename, then again inside the render loop. `Info::new` reads the span out of the source, so this doubled the most expensive part of the reporter. Build it once and group by index instead. Also drop two other duplicated pieces of work in the same loop: the message was `xml_escape`d twice (once for the attribute, once for the description), and the rule name was re-derived via `code().to_string()` even though `Info` already carries it as `rule_id`. And the nested `Vec<String>` + `join` is now a single output buffer. Benchmarked with 3 runs x 2 format options (checkstyle as the control) x 3 repos, shows small reductions on junit in RSS thanks to this change, and 40-47% drops in runtime (`oxlint -D all --format=NAME`): | repo | diagnostics | format | main | branch | delta | change | RSS main | RSS branch | | --- | ---: | --- | ---: | ---: | ---: | ---: | ---: | ---: | | vscode | 1,366,572 | checkstyle | 11832ms | 11645ms | -187ms | -1.6% | 3272 MB | 3273 MB | | vscode | 1,366,572 | **junit** | 22022ms | 11611ms | -10410ms | **-47.3%** | 3325 MB | 3287 MB | | gitlab | 363,895 | checkstyle | 1749ms | 1723ms | -26ms | -1.5% | 966 MB | 971 MB | | gitlab | 363,895 | **junit** | 2895ms | 1718ms | -1177ms | **-40.7%** | 989 MB | 948 MB | | canvas-lms | 350,637 | checkstyle | 2207ms | 2155ms | -52ms | -2.3% | 917 MB | 915 MB | | canvas-lms | 350,637 | **junit** | 3944ms | 2139ms | -1805ms | **-45.8%** | 921 MB | 886 MB | On a more reasonable number of diagnostics (running on canvas-lms with the default ruleset) the numbers are less pronounced but still show a 17% drop: | repo | ruleset | diagnostics | format | main | branch | delta | change | | --- | --- | ---: | --- | ---: | ---: | ---: | ---: | | canvas-lms | default | 3,149 | checkstyle | 218ms | 219ms | +1ms | +0.5% | | canvas-lms | default | 3,149 | junit | 265ms | 219ms | -46ms | -17.3% | On a repo with 0 violations, the runtime difference for junit on main vs. this branch is entirely noise. Realistically this won't have much of an impact in a user's actual run, as most of the time a lint run results in one of: - 0 diagnostics - a single digit number of diagnostics in a junit run due to new violations introduced by code changes - or there are only a few hundred to a few thousand max (due to, for example, warnings which are considered safe and are only used for a "transition" period where a rule is soft-enabled until all existing violations of it are fixed). But I think it's worthwhile regardless to help on smaller #s of diagnostics. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
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> |
||
|
|
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> |
||
|
|
1cf7ddea46 |
perf(oxlint): render JSON report into a single buffer (#25295)
AI Disclosure: Generated with Claude Code, Opus 5. Reviewed and tested by me. ## What `format_json` rendered each diagnostic into its own `String`, collected them into a `Vec<String>`, then `join`ed them. That allocates once per diagnostic and copies the entire report a second time to build the joined result. This renders straight into one output buffer instead. ## Why On the vscode corpus with `-D all` — 1.37M diagnostics, ~500 MB of JSON output: | | before | after | | --- | --- | --- | | `--format=json` wall clock | 13.3 s | 12.6 s | | peak RSS | 4668 MB | 3576 MB | Measured as best-of-3 with the two binaries interleaved, output redirected to `/dev/null`. ## Correctness Output is byte-identical before and after. Verified on `apps/oxlint/fixtures/cli/output_formatter_diagnostic` and on a 365k-diagnostic subset of vscode (170 MB of JSON compared byte-for-byte). Note that oxlint's diagnostic ordering is nondeterministic run-to-run under parallelism, so the comparison was run with `--threads=1`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
72bbbe240a | chore(deps): update dependency oxc-parser to ^0.143.0 (#25260) | ||
|
|
cc01bd7f0f |
chore(deps): update dependency @oxc-project/types to ^0.143.0 (#25255)
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/) | |---|---|---|---|---|---| | [@oxc-project/types](https://oxc.rs) ([source](https://redirect.github.com/oxc-project/oxc/tree/HEAD/npm/oxc-types)) | [`^0.142.0` → `^0.143.0`](https://renovatebot.com/diffs/npm/@oxc-project%2ftypes/0.142.0/0.143.0) |  |  |  |  | --- ### 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:eyJjcmVhdGVkSW5WZXIiOiI0NC4zLjIiLCJ1cGRhdGVkSW5WZXIiOiI0NC4zLjIiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
9a423f2f48 |
release(apps): oxlint v1.77.0 && oxfmt v0.62.0 (#25251)
# Oxlint ### 💥 BREAKING CHANGES - |
||
|
|
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) |  |  |  |  | pnpm.catalog.default | minor | | [napi](https://redirect.github.com/napi-rs/napi-rs) | `3.11.0` → `3.12.0` |  |  |  |  | workspace.dependencies | minor | | [napi-build](https://redirect.github.com/napi-rs/napi-rs) | `2.3.2` → `2.4.0` |  |  |  |  | workspace.dependencies | minor | | [napi-derive](https://redirect.github.com/napi-rs/napi-rs) | `3.6.0` → `3.6.2` |  |  |  |  | workspace.dependencies | patch | --- ### Release Notes <details> <summary>napi-rs/napi-rs (@​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> |
||
|
|
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 |
||
|
|
d0c45aaf7c |
chore(deps): update npm packages (#25205)
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/wasm-runtime](https://napi.rs/) ([source](https://redirect.github.com/napi-rs/napi-rs/tree/HEAD/wasm-runtime)) | [`1.1.6` → `1.2.1`](https://renovatebot.com/diffs/npm/@napi-rs%2fwasm-runtime/1.1.6/1.2.1) |  |  |  |  | | [degit](https://redirect.github.com/Rich-Harris/degit) | [`3.6.2` → `3.6.5`](https://renovatebot.com/diffs/npm/degit/3.6.2/3.6.5) |  |  |  |  | | [eslint](https://eslint.org) ([source](https://redirect.github.com/eslint/eslint)) | [`10.7.0` → `10.8.0`](https://renovatebot.com/diffs/npm/eslint/10.7.0/10.8.0) |  |  |  |  | | [playwright](https://playwright.dev) ([source](https://redirect.github.com/microsoft/playwright)) | [`1.61.1` → `1.62.1`](https://renovatebot.com/diffs/npm/playwright/1.61.1/1.62.1) |  |  |  |  | | [svelte](https://svelte.dev) ([source](https://redirect.github.com/sveltejs/svelte/tree/HEAD/packages/svelte)) | [`5.56.7` → `5.56.8`](https://renovatebot.com/diffs/npm/svelte/5.56.7/5.56.8) |  |  |  |  | --- ### Release Notes <details> <summary>napi-rs/napi-rs (@​napi-rs/wasm-runtime)</summary> ### [`v1.2.1`](https://redirect.github.com/napi-rs/napi-rs/blob/HEAD/wasm-runtime/CHANGELOG.md#121-2026-07-30) [Compare Source](https://redirect.github.com/napi-rs/napi-rs/compare/@napi-rs/wasm-runtime@1.2.0...@napi-rs/wasm-runtime@1.2.1) ##### Bug Fixes - **wasm-runtime:** preserve emnapi v1 compatibility ([#​3426](https://redirect.github.com/napi-rs/napi-rs/issues/3426)) ([856326b](https://redirect.github.com/napi-rs/napi-rs/commit/856326b3051028b0d9992227f02167227f46b07b)) ### [`v1.2.0`](https://redirect.github.com/napi-rs/napi-rs/blob/HEAD/wasm-runtime/CHANGELOG.md#120-2026-07-28) [Compare Source](https://redirect.github.com/napi-rs/napi-rs/compare/@napi-rs/wasm-runtime@1.1.6...@napi-rs/wasm-runtime@1.2.0) ##### Features - **cli:** support non-threaded WASI targets ([#​3353](https://redirect.github.com/napi-rs/napi-rs/issues/3353)) ([b5ecfa3](https://redirect.github.com/napi-rs/napi-rs/commit/b5ecfa3d6a9fcf8e66c59e05dd4027b832b44d61)), closes [#​3352](https://redirect.github.com/napi-rs/napi-rs/issues/3352) [#​3400](https://redirect.github.com/napi-rs/napi-rs/issues/3400) [#​3405](https://redirect.github.com/napi-rs/napi-rs/issues/3405) #### [1.1.6](https://redirect.github.com/napi-rs/napi-rs/compare/@napi-rs/wasm-runtime@1.1.5...@napi-rs/wasm-runtime@1.1.6) (2026-06-24) **Note:** Version bump only for package [@​napi-rs/wasm-runtime](https://redirect.github.com/napi-rs/wasm-runtime) #### [1.1.5](https://redirect.github.com/napi-rs/napi-rs/compare/@napi-rs/wasm-runtime@1.1.4...@napi-rs/wasm-runtime@1.1.5) (2026-06-10) ##### Bug Fixes - **wasm-runtime:** preserve Buffer return values in fs-proxy ([#​3250](https://redirect.github.com/napi-rs/napi-rs/issues/3250)) ([c70f205](https://redirect.github.com/napi-rs/napi-rs/commit/c70f205a071c39acbd792b071bb95b2f5d2f39e8)) #### [1.1.4](https://redirect.github.com/napi-rs/napi-rs/compare/@napi-rs/wasm-runtime@1.1.3...@napi-rs/wasm-runtime@1.1.4) (2026-04-15) ##### Bug Fixes - **wasm-runtime:** preserve full bigint values in fs proxy codec ([#​3233](https://redirect.github.com/napi-rs/napi-rs/issues/3233)) ([0cb8eef](https://redirect.github.com/napi-rs/napi-rs/commit/0cb8eefad83938daa6a0f377f2708890d9f4b6bf)) #### [1.1.3](https://redirect.github.com/napi-rs/napi-rs/compare/@napi-rs/wasm-runtime@1.1.2...@napi-rs/wasm-runtime@1.1.3) (2026-04-08) **Note:** Version bump only for package [@​napi-rs/wasm-runtime](https://redirect.github.com/napi-rs/wasm-runtime) #### [1.1.2](https://redirect.github.com/napi-rs/napi-rs/compare/@napi-rs/wasm-runtime@1.1.1...@napi-rs/wasm-runtime@1.1.2) (2026-03-28) ##### Bug Fixes - ensure emnapi version is synced ([#​3151](https://redirect.github.com/napi-rs/napi-rs/issues/3151)) ([bc728d0](https://redirect.github.com/napi-rs/napi-rs/commit/bc728d0a289360b199d9dbd3b512a975f4d75d5a)) #### [1.1.1](https://redirect.github.com/napi-rs/napi-rs/compare/@napi-rs/wasm-runtime@1.1.0...@napi-rs/wasm-runtime@1.1.1) (2025-12-30) **Note:** Version bump only for package [@​napi-rs/wasm-runtime](https://redirect.github.com/napi-rs/wasm-runtime) </details> <details> <summary>Rich-Harris/degit (degit)</summary> ### [`v3.6.5`](https://redirect.github.com/Rich-Harris/degit/compare/v3.6.4...v3.6.5) [Compare Source](https://redirect.github.com/Rich-Harris/degit/compare/v3.6.4...v3.6.5) ### [`v3.6.4`](https://redirect.github.com/Rich-Harris/degit/compare/v3.6.3...v3.6.4) [Compare Source](https://redirect.github.com/Rich-Harris/degit/compare/v3.6.3...v3.6.4) ### [`v3.6.3`](https://redirect.github.com/Rich-Harris/degit/compare/v3.6.2...v3.6.3) [Compare Source](https://redirect.github.com/Rich-Harris/degit/compare/v3.6.2...v3.6.3) </details> <details> <summary>eslint/eslint (eslint)</summary> ### [`v10.8.0`](https://redirect.github.com/eslint/eslint/releases/tag/v10.8.0) [Compare Source](https://redirect.github.com/eslint/eslint/compare/v10.7.0...v10.8.0) #### Features - [`2fee9bb`](https://redirect.github.com/eslint/eslint/commit/2fee9bb7416116cbed4d8c8100b1ae713b6356a1) feat: export `ConfigObject` from `eslint/config` ([#​21082](https://redirect.github.com/eslint/eslint/issues/21082)) (sethamus) #### Bug Fixes - [`6b8d2f7`](https://redirect.github.com/eslint/eslint/commit/6b8d2f7589b8a7c8b91b8ca2a2ef6d46178760d8) fix: escape reserved characters in rule id in `html` formatter ([#​21129](https://redirect.github.com/eslint/eslint/issues/21129)) (Francesco Trotta) - [`9091071`](https://redirect.github.com/eslint/eslint/commit/90910715011211a20d011d807d398a7005127f35) fix: prevent `no-unreachable-loop` crash when all loop types are ignored ([#​21116](https://redirect.github.com/eslint/eslint/issues/21116)) (Pixel) - [`e23fafe`](https://redirect.github.com/eslint/eslint/commit/e23fafe8d4b15355adef6cdebef414c3a2019454) fix: prefer-object-spread add semicolon when adding parenthesis ([#​21081](https://redirect.github.com/eslint/eslint/issues/21081)) (synthex-byte) - [`20b5ad0`](https://redirect.github.com/eslint/eslint/commit/20b5ad052360a443786a202e94624a3f81846511) fix: quadratic-time regex in `prefer-template` ([#​21096](https://redirect.github.com/eslint/eslint/issues/21096)) (Milos Djermanovic) - [`8b6f6c0`](https://redirect.github.com/eslint/eslint/commit/8b6f6c0b33411f34485512456d94f221daf7321f) fix: apply ignore configs to computed methods in class-methods-use-this ([#​21094](https://redirect.github.com/eslint/eslint/issues/21094)) (Pixel) - [`b2c608c`](https://redirect.github.com/eslint/eslint/commit/b2c608c014a396800a24a89343265d0616bee2d8) fix: NewExpression with parenthesized callee in `preserve-caught-error` ([#​21083](https://redirect.github.com/eslint/eslint/issues/21083)) (Francesco Trotta) #### Documentation - [`6ddf858`](https://redirect.github.com/eslint/eslint/commit/6ddf8587e5cfeeb7328332601bb76d98b8a198ea) docs: fix broken Specify Parser Options anchor link ([#​21106](https://redirect.github.com/eslint/eslint/issues/21106)) (Minsu) - [`784dfbe`](https://redirect.github.com/eslint/eslint/commit/784dfbe98f0222426fd200153a5ce2e5624151f0) docs: Clarify `no-eq-null` description ([#​21120](https://redirect.github.com/eslint/eslint/issues/21120)) (Park Harin) - [`7ec733a`](https://redirect.github.com/eslint/eslint/commit/7ec733a3ba5acb053a73ac656030a3879aa48fda) docs: Fix typos and grammar in glossary ([#​21095](https://redirect.github.com/eslint/eslint/issues/21095)) (Marry (Subin Yang)) - [`92bb13f`](https://redirect.github.com/eslint/eslint/commit/92bb13f13065db72d62454b9830d3ae52db15c76) docs: replace quake link ([#​21108](https://redirect.github.com/eslint/eslint/issues/21108)) (Jung Hyeon Jun) - [`68eb4a5`](https://redirect.github.com/eslint/eslint/commit/68eb4a57572409dbdcfeb3bc5c92ddbba46bc770) docs: fix broken Specify Globals anchor links in rule pages ([#​21103](https://redirect.github.com/eslint/eslint/issues/21103)) (Minsu) - [`d28f697`](https://redirect.github.com/eslint/eslint/commit/d28f697e0d32d7446c825fd89c362db028450134) docs: replace Code Climate CLI links with Qlty CLI links ([#​21099](https://redirect.github.com/eslint/eslint/issues/21099)) (Jung Hyeon Jun) - [`eccc68d`](https://redirect.github.com/eslint/eslint/commit/eccc68d42564e46bc9020d19ec52d2988f3b7bfa) docs: correct --suppressions-location option description ([#​21093](https://redirect.github.com/eslint/eslint/issues/21093)) (Ga eun Lee) - [`c5963f7`](https://redirect.github.com/eslint/eslint/commit/c5963f74bfa82a5b7ccc0607dcdcc695b8c97a31) docs: Update README (GitHub Actions Bot) #### Chores - [`4fbf46d`](https://redirect.github.com/eslint/eslint/commit/4fbf46d140120ae838db08cbe49544c985956490) test: pin `webpack` version to 5.108.4 ([#​21137](https://redirect.github.com/eslint/eslint/issues/21137)) (Francesco Trotta) - [`2d063e2`](https://redirect.github.com/eslint/eslint/commit/2d063e224e9bb0ccb0a28c120f7e380a8d62f320) chore: update HTTP URLs to HTTPS in JSDoc and comments ([#​21101](https://redirect.github.com/eslint/eslint/issues/21101)) (Bo Hyun Kim) - [`eccbe7b`](https://redirect.github.com/eslint/eslint/commit/eccbe7bc9257a6c99880468e452c8dfafbf47f74) test: add error locations to `no-class-assign` ([#​21123](https://redirect.github.com/eslint/eslint/issues/21123)) (devoil) - [`e7d1e43`](https://redirect.github.com/eslint/eslint/commit/e7d1e4373bf626f8da76d62ce024c28928bc99bc) ci: bump actions/setup-go from 6 to 7 ([#​21118](https://redirect.github.com/eslint/eslint/issues/21118)) (dependabot\[bot]) - [`e9d66d0`](https://redirect.github.com/eslint/eslint/commit/e9d66d0cde1a7752c29dee53ab7b62632835a87a) ci: bump actions/setup-node from 6 to 7 ([#​21119](https://redirect.github.com/eslint/eslint/issues/21119)) (dependabot\[bot]) - [`ee225b6`](https://redirect.github.com/eslint/eslint/commit/ee225b60c26f0cc5f4d71641888a5bd2ec5626d6) test: Add error location details to `no-eq-null` rule ([#​21117](https://redirect.github.com/eslint/eslint/issues/21117)) (Park Harin) - [`044a627`](https://redirect.github.com/eslint/eslint/commit/044a627fa3e28ee1410d515acc5378eb4b49f8ba) chore: update minimatch to ^10.2.5 ([#​21107](https://redirect.github.com/eslint/eslint/issues/21107)) (김채영) - [`fb09aa8`](https://redirect.github.com/eslint/eslint/commit/fb09aa8ff09730d3ccf68859e065f99666b52466) chore: update ecosystem plugins ([#​21115](https://redirect.github.com/eslint/eslint/issues/21115)) (ESLint Bot) - [`5abd878`](https://redirect.github.com/eslint/eslint/commit/5abd878740fe417fd8a910cac3741f2a0317b365) test: add error locations to `no-proto` ([#​21114](https://redirect.github.com/eslint/eslint/issues/21114)) (Gihyeon Jeong / 정기현) - [`9715887`](https://redirect.github.com/eslint/eslint/commit/9715887ec94a5ff936447d7b680d039fbe2f0541) test: Add error location details to `no-div-regex` ([#​21110](https://redirect.github.com/eslint/eslint/issues/21110)) (Park Harin) - [`a746ec6`](https://redirect.github.com/eslint/eslint/commit/a746ec6ea4a2249b1eb3f512264da5f4d5f7c886) test: add error locations to `no-new-wrappers` ([#​21109](https://redirect.github.com/eslint/eslint/issues/21109)) (Gihyeon Jeong / 정기현) - [`8dde645`](https://redirect.github.com/eslint/eslint/commit/8dde64570e240f3ef8af873d59a752db6d8519aa) test: add error locations to `no-ex-assign` ([#​21102](https://redirect.github.com/eslint/eslint/issues/21102)) (devoil) - [`13ab0ec`](https://redirect.github.com/eslint/eslint/commit/13ab0ec447650c079d8a5e5d67222f79e69c741e) test: add error locations to `no-label-var` ([#​21098](https://redirect.github.com/eslint/eslint/issues/21098)) (Gihyeon Jeong / 정기현) - [`a99906f`](https://redirect.github.com/eslint/eslint/commit/a99906ffb8342dde03336b5c6372b5658f21d5f2) test: Add error location details to `no-delete-var` rule ([#​21105](https://redirect.github.com/eslint/eslint/issues/21105)) (Park Harin) - [`c47e8dc`](https://redirect.github.com/eslint/eslint/commit/c47e8dc9bbfba797430db45ae08cb6f7392cfc9d) chore: add missing backticks to `languages/js/index.js` ([#​21104](https://redirect.github.com/eslint/eslint/issues/21104)) (beeen) - [`0174428`](https://redirect.github.com/eslint/eslint/commit/0174428dd7543d118cf67a823b98dd97032fe68c) chore: add missing backticks to `translate-cli-options.js` ([#​21097](https://redirect.github.com/eslint/eslint/issues/21097)) (dongkyu lee) - [`3d36589`](https://redirect.github.com/eslint/eslint/commit/3d36589a4917326500f0707bb41745160f387d00) chore: add missing backticks to `serialization.js` ([#​21091](https://redirect.github.com/eslint/eslint/issues/21091)) (이규환) - [`dcc9312`](https://redirect.github.com/eslint/eslint/commit/dcc9312c1081931de0fe1b555fbb6aa82fe696b9) test: add error locations to `eqeqeq` ([#​21090](https://redirect.github.com/eslint/eslint/issues/21090)) (Ga eun Lee) - [`2710b18`](https://redirect.github.com/eslint/eslint/commit/2710b182472cd1a95e4aff6186cb2c4fbadb4ee0) ci: Add explicit permissions to rebuild-docs-sites workflow ([#​21089](https://redirect.github.com/eslint/eslint/issues/21089)) (Marry (Subin Yang)) - [`5d2f866`](https://redirect.github.com/eslint/eslint/commit/5d2f8663ee60701e9036b0b0933a12efd9d93269) chore: update dependency prettier to v3.9.5 ([#​21086](https://redirect.github.com/eslint/eslint/issues/21086)) (renovate\[bot]) - [`d584e31`](https://redirect.github.com/eslint/eslint/commit/d584e31098f262563b97dc5d5f23a63a187879a0) chore: fix failing ecosystem test for `eslint-plugin-unicorn` ([#​21084](https://redirect.github.com/eslint/eslint/issues/21084)) (Francesco Trotta) - [`bf3eda0`](https://redirect.github.com/eslint/eslint/commit/bf3eda049bd690f1e9a5a0c4520a6329b3e4ec85) chore: update ecosystem plugins ([#​21079](https://redirect.github.com/eslint/eslint/issues/21079)) (ESLint Bot) </details> <details> <summary>microsoft/playwright (playwright)</summary> ### [`v1.62.1`](https://redirect.github.com/microsoft/playwright/compare/v1.62.0...26a9e470a7b3c7822084b09fb7f13902c5f37b51) [Compare Source](https://redirect.github.com/microsoft/playwright/compare/v1.62.0...v1.62.1) ### [`v1.62.0`](https://redirect.github.com/microsoft/playwright/releases/tag/v1.62.0) [Compare Source](https://redirect.github.com/microsoft/playwright/compare/v1.61.1...v1.62.0) ##### 🧱 New component testing model [Component testing](https://playwright.dev/docs/test-components) moves to a **stories and galleries** model. A **story** wraps your component in one specific scenario — hard-coded props, mock data, providers — and a **gallery** page that you serve renders stories on demand. The new [fixtures.mount()](https://playwright.dev/docs/api/class-fixtures#fixtures-mount) fixture navigates to the gallery, mounts a story by id, and returns a [Locator](https://playwright.dev/docs/api/class-locator) scoped to the story's root element: ```js test('click should expand', async ({ mount }) => { const component = await mount('components/Expandable/Stateful'); await component.getByRole('button').click(); await expect(component.getByTestId('expanded')).toHaveValue('true'); }); ``` Pass a story type as a template argument to type-check its props, and use `update(props)` / `unmount()` on the returned locator to re-render or tear down within a test. ##### 🛑 Cancel operations with AbortSignal Most operations and web-first assertions now accept a `signal` option that takes an [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal), letting you cancel long-running actions, navigations, waits, and assertions: ```js const controller = new AbortController(); setTimeout(() => controller.abort(), 1000); await page.getByRole('button', { name: 'Submit' }).click({ signal: controller.signal }); await expect(page.getByText('Done')).toBeVisible({ signal: controller.signal }); ``` Providing a signal does not disable the default timeout; pass `timeout: 0` to disable it. ##### 🖼️ WebP screenshots [expect(page).toHaveScreenshot()](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1) and [expect(locator).toHaveScreenshot()](https://playwright.dev/docs/api/class-locatorassertions#locator-assertions-to-have-screenshot-1) can now store snapshots in the WebP format — just give the snapshot a `.webp` name: ```js // Visual comparisons store the golden snapshot as lossless WebP. await expect(page).toHaveScreenshot('homepage.webp'); // Standalone screenshots can trade quality for size with lossy WebP. await page.screenshot({ path: 'homepage.webp', quality: 50 }); ``` [page.screenshot()](https://playwright.dev/docs/api/class-page#page-screenshot) and [locator.screenshot()](https://playwright.dev/docs/api/class-locator#locator-screenshot) also accept `webp` as a `type`, where quality `100` (the default) is lossless and lower values use lossy compression. ##### 🧩 Custom test filtering with Reporter.preprocess() New [reporter.preprocess()](https://playwright.dev/docs/api/class-reporter#reporter-preprocess) hook runs after the configuration is resolved and before [reporter.onBegin()](https://playwright.dev/docs/api/class-reporter#reporter-on-begin), letting a reporter mark individual tests as skipped, excluded, fixed, or failing through a [TestRun](https://playwright.dev/docs/api/class-testrun) object: ```js class MyReporter { async preprocess({ config, suite, testRun }) { for (const test of suite.allTests()) { if (shouldSkip(test)) testRun.skip(test); } } } ``` ##### 🔁 Isolated retries New [testConfig.retryStrategy](https://playwright.dev/docs/api/class-testconfig#test-config-retry-strategy) controls when failed tests are retried. The default `'immediate'` retries as soon as a worker is free; `'isolated'` runs all retries at the end, one by one in a single worker, to minimize interference with the rest of the suite: ```js // playwright.config.ts export default defineConfig({ retries: 2, retryStrategy: 'isolated', }); ``` ##### New APIs ##### Browser and Context - New option [`credentials`](https://playwright.dev/docs/api/class-browsercontext#browser-context-storage-state-option-credentials) includes the context's virtual WebAuthn [Credentials](https://playwright.dev/docs/api/class-credentials) (passkeys) in the storage state, so they can be persisted and re-seeded into later contexts. ##### Actions - New `scroll` option (`"auto"` | `"none"`) on actions to opt out of Playwright's automatic scroll-into-view. ##### Network - New [apiResponse.timing()](https://playwright.dev/docs/api/class-apiresponse#api-response-timing) returns resource timing information for an API response. ##### Evaluation - New [locator.waitForFunction()](https://playwright.dev/docs/api/class-locator#locator-wait-for-function) waits until a function — called with the matching element — returns a truthy value. - [page.evaluate()](https://playwright.dev/docs/api/class-page#page-evaluate) and related methods now accept functions as evaluate arguments. - [page.addInitScript()](https://playwright.dev/docs/api/class-page#page-add-init-script) / [browserContext.addInitScript()](https://playwright.dev/docs/api/class-browsercontext#browser-context-add-init-script) now accept functions as init-script arguments. ##### Command line & MCP - Playwright now bundles the [Playwright MCP](https://playwright.dev/docs/getting-started-mcp) server and [`playwright-cli`](https://playwright.dev/docs/getting-started-cli), runnable via `npx playwright mcp` and `npx playwright cli`. ##### Reporters - The HTML report's **Merge files** grouping — previously only a UI toggle — can now be enabled from the config with the new `mergeFiles` reporter option: ```js // playwright.config.ts export default defineConfig({ reporter: [['html', { mergeFiles: true }]], }); ``` ##### Announcements - ⚠️ Debian 11 is not supported anymore. ##### Browser Versions - Chromium 151.0.7922.34 - Mozilla Firefox 153.0 - WebKit 26.5 This version was also tested against the following stable channels: - Google Chrome 151 - Microsoft Edge 151 </details> <details> <summary>sveltejs/svelte (svelte)</summary> ### [`v5.56.8`](https://redirect.github.com/sveltejs/svelte/blob/HEAD/packages/svelte/CHANGELOG.md#5568) [Compare Source](https://redirect.github.com/sveltejs/svelte/compare/svelte@5.56.7...svelte@5.56.8) ##### Patch Changes - fix: call `onerror` and provide a working `reset` when hydrating a failed boundary ([#​18556](https://redirect.github.com/sveltejs/svelte/pull/18556)) - fix: preserve select selection when spread attributes omit value ([#​18561](https://redirect.github.com/sveltejs/svelte/pull/18561)) </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:eyJjcmVhdGVkSW5WZXIiOiI0NC4zLjIiLCJ1cGRhdGVkSW5WZXIiOiI0NC4zLjIiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=--> --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Cameron <cameron.clark@hey.com> |
||
|
|
20f68e74a3 |
fix(oxlint,oxfmt): respect .gitignore for walk targets and explicit paths (#25133)
Fixes #25107. The `ignore` crate walker enforces gitignore's "everything under an ignored directory is ignored" rule only by pruning ignored directories during traversal. And it never filters its walk roots. So when a walk target (based on cwd or an explicit CLI target path) is already inside a gitignored tree, pruning never happens and a bare directory pattern like `generated` matches nothing file-level. (even though `git check-ignore` says they are ignored) See also BurntSushi/ripgrep#2595 ### Changes - oxc_config: added `GitignoreChecker` - a pre-walk check that replays git's resolution order over the ancestor chain - Matchers and `.git`/`.jj` probes are cached per directory - oxlint / oxfmt: filter all CLI targets through this check before walking ### Behavior changes - Explicitly passed gitignored files are now skipped (previously always linted/formatted) - `oxlint --no-ignore` no longer force-lints gitignored targets - The same behavior as `--no-ignore` does not disable during walk `.gitignore` <details> <summary>FYI: Current our ignore model overview</summary> Two independent families, AND-ed (a path excluded by any layer is skipped): | Layer | Source | oxlint | oxfmt | | -------------------------------------------- | ------------------------------------------------------ | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------- | | git-derived (always on, not user-disablable) | nested `.gitignore`, `.git/info/exclude` (during walk) | walker via shared `configure_walk_builder` | same (shared) | | | walk roots / explicit CLI targets | `GitignoreChecker` (this PR) | `GitignoreChecker` (this PR) | | tool-owned | ignore file | `.eslintignore` / `--ignore-path`; disabled by `--no-ignore` | `.prettierignore` / `--ignore-path`; no disable flag | | | CLI patterns | `--ignore-pattern`; disabled by `--no-ignore` | `!pattern` path args | | | config `ignorePatterns` | `LintIgnoreMatcher` (already containment-correct via `matched_path_or_any_parents`); always on | scope-local `is_path_ignored` (same); always on | NOTE: `ignorePatterns` never had this bug, only the walker-backed gitignore layer did; this PR brings it to the same level. A `!` negation in `ignorePatterns` cannot re-include gitignored paths (unchanged; the layers are independent). </details> |
||
|
|
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" /> |
||
|
|
067da8c4e7 |
feat(ast)!: store single parameter in TSIndexSignature::parameter (#25154)
|
||
|
|
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
|
||
|
|
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 |
||
|
|
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
|
||
|
|
1fb3d7073c |
feat(oxlint): show file:line:col in github format annotation messages (#25020)
In GitHub Actions the annotation parameters (`file=`, `line=`, `col=`) only feed the annotations panel, so the log line itself has no location: ``` Error: Function 'foo' is declared but never used. ``` A teammate hit this in my repo's CI and could not tell which file broke the lint job. My workaround was re-running oxlint with `--format=default` on failure, same as csvn in #21574. This prefixes the message with the location, same layout as [Ruff's GitHub renderer](https://github.com/astral-sh/ruff/blob/main/crates/ruff_db/src/diagnostic/render/github.rs): ``` ::error file=test.js,line=5,endLine=5,col=1,endColumn=10,title=eslint(no-debugger)::test.js:5:1: `debugger` statement is not allowed ``` The location does get duplicated in the annotation bubble, which is already anchored to the line. Ruff accepted that trade for a readable log. The filename is escaped twice on purpose, property rules for `file=` and data rules for the message text, with a unit test covering the difference. Related to #21574 but this does not implement multi-format output. Updated the unit tests, the CLI snapshots, and the github e2e fixture. `cargo test -p oxlint` passes (396) and so does the apps/oxlint vitest suite. I used Claude Code to help investigate and draft this. I reviewed the change and ran the tests myself. |
||
|
|
2ff0ccc594 |
refactor(oxlint/linter/lsp): extend "ignore fixes" on diagnostic creation (#24958)
This PR refactors the "ignore fixes" code, to be created on diagnostic creation.
With an extra flag in `LintOptions` and `LintRunner`, the caller can include automatically the fix for ignoring the diagnostic.
This flag is only enabled on `oxlint --lsp` side and is not effected by normal CLI usage.
Important changes:
- The "fixes" are working now with `Spans` instead of `Position`
- The calculation of the right span is not depending on the partial source text, instead of the full source text
- new `FixKind` for the `ignore` fixes.
Generated by GPT-5.3-Codex 🤖 Reviewed by myself
|
||
|
|
2b027111db |
fix(oxlint): correct --warn flag help text (#25059)
The `-W, --warn` help text says "Deny the rule or category (emit a
warning)", copied from the `-D, --deny` entry.
With that wording, `--warn` and `--deny` look like they do the same
thing in `--help`, but `-W` reports a warning and `-D` reports an error.
Evidence why I think this is not intentional, and instead a typo:
- The other two entries start with their own flag's verb ("Allow the
rule...", "Deny the rule..."). Only the `-W` entry starts with its
sibling's verb, in a sentence identical to the `-D` one except the
parenthetical.
- These flags mirror rustc and clippy's `-A`/`-W`/`-D`, where warn and
deny are two different levels and deny specifically means "make it an
error".
- In this same file, `-W` maps to `AllowWarnDeny::Warn` and `-D` maps to
`AllowWarnDeny::Deny` (`into_tuple`). The internal name for what `-W`
does is warn, not deny.
What changed:
- The `-W` help text is now "Warn on the rule or category (emit a
warning)"
- Updated the two website_linter snapshots, so the generated CLI docs
page picks up the fix
I used Claude Code to help find and fix this.
Co-authored-by: Cameron <cameron.clark@hey.com>
|
||
|
|
7807304a70 |
refactor(oxlint/linter/lsp): move ignore logic to oxc_linter (#24951)
The start for fixing https://github.com/oxc-project/oxc/issues/24570 At the moment the "ignore this line" / "ignore this section" logic is living inside `oxlint/lsp` directory. Because we now need to know the AST parents, the code should live inside `oxc_linter`. This PR refactors the 2 methods into a new `oxc_linter` file. |