This PR contains the following updates:
| Package | Type | Update | Change |
|---|---|---|---|
|
[sort-package-json](https://redirect.github.com/oxc-project/sort-package-json)
| workspace.dependencies | major | `0.0.15` → `1.0.0` |
---
### Release Notes
<details>
<summary>oxc-project/sort-package-json (sort-package-json)</summary>
###
[`v1.0.0`](https://redirect.github.com/oxc-project/sort-package-json/blob/HEAD/CHANGELOG.md#100---2026-08-16)
[Compare
Source](https://redirect.github.com/oxc-project/sort-package-json/compare/v0.0.15...v1.0.0)
##### Changed
- **Breaking:** Stabilize the public `SortOptions` API and refresh crate
metadata and documentation
([#​158](https://redirect.github.com/oxc-project/sort-package-json/pull/158))
</details>
---
### Configuration
📅 **Schedule**: (in timezone Asia/Shanghai)
- Branch creation
- At any time (no schedule defined)
- Automerge
- At any time (no schedule defined)
🚦 **Automerge**: Enabled.
♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.
🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.
---
- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box
---
This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/oxc-project/oxc).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4yOS41IiwidXBkYXRlZEluVmVyIjoiNDQuMjkuNSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->
---------
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Boshen <boshenc@gmail.com>
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.
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>
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.
## 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
- 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.
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
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).
## 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
`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.
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.
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.
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.
Prettier uses the `conditionalGroup` IR for JS and YAML.
When this appeared in JS(containing `conditionalGroup`)-in-HTML(`script` tags)-in-JS (`oxc_formatter`), we previously bypassed the `Doc` to IR conversion.
This PR adds support for this conversion and removes the string format fallback path.
Pure renaming.
- `DispatchOutcome` -> `DispatchResponse` (counter part of `DispatchRequest`)
- `DispatchResult` -> `DispatchPayload` (lives in `DispatchResponse`)
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
Consolidated the criteria for determining which languages are handled by?
- natively by Rust
- passed to Prettier
when formatting embedded code, as these were previously scattered across various places.
Due to historical reasons, the IR was passed as `[Doc, (Doc, ...Doc)]` only when processing `gql-in-js`, whilst for other cases such as `css-in-js` and `html-in-js`, it was always `[Doc]`.
Now, every result is single `Doc`.
- dispatcher
- string_embedder
- tailwind_sorter
Group these 3 together as `SessionServices`, make them available to `FormatSession`, and pass them around.
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!
Previously, as Prettier was required for embedded formatting, so embedding was only supported in `napi` builds.
However, as the number of rewritten Rust components has increased recently, we have enabled embedded formatting in `pure` builds as well, thereby reducing the scope of the `napi` gate.
In the embedding format, issuing a `DispatchRequest` returns a `DispatchOutcome`.
Additionally, by managing the nesting depth, made it possible to limit the number of recursion.