fixes https://github.com/oxc-project/oxc/issues/28729
Generated by Claude Sonnet 5.5 🤖
The upstream rules uses regex to detect if it is a combining character with the `\p` shorthand:
https://github.com/eslint/eslint/blob/main/lib/rules/utils/unicode/is-combining-character.js#L11
Because there is no similar utility in rust, we currently have a self-managed list of character detection.
This list now get extended to detect more characters for other languages like Arabic, Hebrew, Thai ...
Verified manually that the failing test cases also fails upstream.
Did not verfify if the list is really valid and covers all possible combining characters.
I hope that the AI did no mistakes and included characters which are still valid.
Addresses one problem in #27736.
Clients should respect the the `ServerCapabilities` from the `intialize` response.
When no `diagnosticProvider` is provided, the server says to the client that `textDocument/diagnostic` is not supported.
```
/**
* The server has support for pull model diagnostics.
*
* @since 3.17.0
*/
diagnosticProvider?: DiagnosticOptions | DiagnosticRegistrationOptions;
```
_https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#pull-diagnostics_
Sadly the client does not need to respect them and can requzest `textDocument/diagnostic` even if we told him not to do.
To avoid duplicate linting processes on push mode (server is sending diagnostics to the client on `didOpen/didChange`, we check if we are in the right mode, or else bail out earlier.
## Summary
This PR improves the oxfmt LSP server's error reporting by propagating root configuration resolution errors to the language server client as notification messages. Previously, configuration errors were only logged via `warn!` macros, making them invisible to users in their editors.
## Problem
When the oxfmt LSP server encountered configuration errors (e.g., invalid `.oxfmtrc.json`, missing required files), these errors were silently logged on the server side. Users had no visibility into why formatting wasn't working or configuration wasn't being applied, resulting in poor debugging experience.
## Solution
The PR modifies the configuration loading pipeline to:
1. Capture configuration errors as `ClientMessage` structs containing the error message and message type
2. Propagate these messages through the `ServerFormatterBuilder` and `ServerFormatter::new()` initialization flow
3. Return collected messages alongside the formatter instance
4. Display these messages to the client via LSP `ShowMessage` notifications during initialization and on config changes
_PR description generated by AI 🤖_
Instead of silently ignoring config-resolve errors, and not formatting the document,
`oxfmt --lsp` now returns an `Err` instead, allowing users to see on their LSP client a meaningful message.
Hitting Format on a file, could produce a `toast` like in this following example:
<img width="463" height="173" alt="grafik" src="https://github.com/user-attachments/assets/7d549ab1-b65b-41bc-9fa0-f5f9d10989dc" />
It is always a good idea to send the message the `stderr` channel too, because the client can filter a stack of messages out (like VSCode does).
Instead of having the responsibility on `oxfmt` and `oxlint`, we can now move logic to the `Backend`.
Surface Oxlint configuration failures to LSP clients as `window/showMessage` notifications during workspace initialization.
Report root, nested, and custom-config-path loading/build failures to the client while preserving fallback linting behavior.
VSCode only show a max of 5 messages from a short time, but with #25962 we already reduce the communication to a maximum of 5 messages.
Here is a screenshot of the `oxc` project where no `oxc.configPath` is defined in the VSCode setting (loading all our fixtures configs)
<img width="459" height="581" alt="grafik" src="https://github.com/user-attachments/assets/9a39e5b7-b049-414b-a487-16a505eb278b" />
Related: https://github.com/oxc-project/oxc-vscode/pull/310#issuecomment-4762272418
Adds a regression test for code-action requests being blocked by slow pull diagnostics, which can delay code actions on save when `tsgolint` takes longer to finish. The test sends five diagnostic requests with a 100 ms delay each, followed by a code-action request, and checks that the code action returns before all five diagnostic delays elapse.
The test remains ignored because it still reproduces the blocking behavior on the current base: 525 ms elapsed against a 500 ms limit. All 102 active language-server tests pass. Formatting and the workspace compile check pass; `just ready` stops at formatter conformance because DNS access prevents downloading the Prettier suite.
AI assistance was used to resolve rebase conflicts and update this description.
When multiple workspaces did not get started on `initialize` (because the client did not send `initizialzeOptions`), the language server did iterate over each worker + each known URI.
Fixed the code so the `known_uris` are only iterate once.
`run_file` is an internal function, which does not get called by the language server.
Instead, it calls the parent function `run_diagnostic`. Refactor the code, so internal implication is kept secret in tests.
Refactors the `oxc_language_server::Tool` trait and associated LSP plumbing to pass `TextDocument` and `CodeActionParams` by value, aligning tool APIs with “consume” semantics and simplifying call sites that previously had to keep borrowed values alive.
<summary>Pull request overview</summary>
This PR refactors the language server’s `WorkspaceWorker::collect_diagnostics_with` to avoid building an intermediate map when collecting tool diagnostics, returning the tool’s `DiagnosticResult` directly.
This was an old code path when `oxc_language_server` did used both tools (`oxlint` & `oxfmt`) at the same time
With https://github.com/oxc-project/oxc/pull/23329 the conversion from offset to line/column position is now done by a helper function in `oxc_language_server`.
There was a helper function inside `oxlint` to call the function. Instead, call it directly now.
Moved the tests to the correct place, and removed duplicated ones.
The `Option<>` wrap for `Vec<LinterCodeAction>` is not needed, after each lint-run we save an entry (even if empty) to the map.
There is no different code branch for `None` as a value.
We had at the beginning some rules' diagnostics like `<rule-name>: diagnostic message`, from that message we did create a code action `Fix this <rule-name> problem`, but this is buggy.
I searched in `crates/oxc_linter` for `OxcDiagnostic::\w+\(".*:` and found only `no-invalid-regexp` to be a useful case.
For other rules this could be wrong like:
- Unexpected `javascript:` url
- `<Document />` from `next/document` should not be imported outside of `pages/_document.js`. See: https:/..`
- Always prefer `const x: T = { ... }`.
**Before:**
Converting `Fix` to `FixContent` did convert `Cow` into `String` and stored into the `ServerLinter.code_action` Map, to get requested later by the client, where we convert `FixContent` to `CodeAction` (where we need the `String` format)
**After:**
Consume directly `Fix` `Cow` fields, and delay to conversion to `String` until the `CodeAction` is requested to be converted.
So only downside I see, is that `textDocument/codeAction` is requested more times than a `textDocument/diagnostic` request. So the conversion does happen more times, but get released quickly.
Updated the `LanguageId` docs, to reflect how the real implementation works.
We did a "rollback" to check for the file extension first, to align with the CLI.
This was specially a problem for jsonc LanguageId with json file extension, where a trailing comma was always added by the editor.
Related https://github.com/oxc-project/oxc/issues/25893
> ## Pull request overview
>
> This PR refactors the language server’s client-notification flow to avoid flooding editors with too many `window/showMessage` notifications by capping the number of messages sent in a batch to 5.
>
Test generated with GPT-5.3-Codex 🤖
> ## Pull request overview
>
> Refactors the language-server tool initialization/restart plumbing to support emitting multiple `ClientMessage`s (instead of a single optional message), so tools can surface more than one warning/error to the client during startup and config changes.
>
> ## Pull request overview
>
> This PR updates the language server’s dynamic worker startup paths to surface `ClientMessage` warnings/errors to the client when a worker is created/started dynamically, and adds a regression test for single-file mode.
>
`oxlint --fix` already presorts the messages by it `fixes` spans, before applying it into the source text.
Resorting the unapplied diagnostics after the operation is only useful for display usages.
I thought maybe the suppression manager needs the right order, but AI🤖 did scan the project is answered the following:
> So the line at mod.rs:413 is mainly for deterministic, source-order diagnostics after fixing. It is not required for correctness of applying fixes, but it is needed for stable and intuitive reporting order.
> Yes, for that specific final sort you highlighted, you can skip it if your only concern is suppression-file correctness.
> Why this is safe:
> Suppression counting is order-independent because it just increments counts by rule key while iterating messages: diff.rs:90.
Runtime suppression aggregation is also additive by rule and filename, not positional: mod.rs:30.
Suppression file output is deterministically sorted at serialization time (BTreeMap), independent of incoming message order: tracking.rs:35.
Important caveat:
> Keep the earlier sort used before applying fixes, since fix application logic depends on processing by fix span: mod.rs:364.
Only the final sort of filtered messages is optional for your case: mod.rs:413.
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`
> ## Pull request overview
>
> This PR refactors the linter’s fixer diagnostics plumbing by removing the unused `fixed` state from `fixer::Message`, relying instead on the existing behavior where `Fixer::fix()` returns only the messages that were _not_ applied.
>
> **Changes:**
>
> * Remove `fixed: bool` from `Message` and simplify `Message::new` accordingly.
>
> * Simplify the fix-application loop by no longer mutating `Message` instances solely to toggle `fixed`.
This struct was introduced by Bulk-Suppressions (https://github.com/oxc-project/oxc/pull/19328).
`OxcDiagnostic` already contains `OxcCode` with the relevant information.
Downside: The `oxc_parser` diagnostics can be included now in the suppression file.
With moving the ignore logic into `oxc_linter`, nobody is now interested in `Message.section_offset`.
The last PR https://github.com/oxc-project/oxc/pull/24958 did remove the last/only dependency of this property.
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
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.
Working on the stack https://github.com/oxc-project/oxc/pull/23768 I created a local test with many responses in a quick time. This code change did resolve the issue.
Auto-merge because it only effects tests, even if not perfect :)
Autogenerated by Codex AI Agent 🤖
This PR comes from different use cases, and I hope I did not have a wrong understanding about spawning child.
### `std::spawn` in `tokio` runtime
Because the LSP is in a `tokio` runtime, we should avoid spawning threads with `std`, instead using `tokio::spawn`.
I try to work already with `tokio::spawn` in the `oxc_language_server` side with #23768
So this will spawn the complete diagnostic path into one separate process. We already need to wait for the `tsgolint` result, so spawning one thread there is suboptimal(?)
### `disable_directives_map` lock for the whole thread spawn
Asked Codex Terra 5.6 where a lock could be generated in #23768, and it found this long-lock.
> The problematic lock scope is tsgolint.rs line 403: the stdout-reader takes disable_directives_map.lock() before iterating the entire TsGoLintMessageStream. The diagnostic reader therefore serializes all type-aware runs, including code actions. This is especially visible after introducing concurrent diagnostics.
### tsgolint process still running
Some users did report that many tsgolint processes are still running, even if not typed. My first guess is these are zombie processes and can be safely killed.
I did not find the exact issue but https://github.com/oxc-project/oxc-vscode/issues/264 should be good enough for a reference.
Some clients can send code actions for documents, which are not opened and already analyzed with a lint process.
A good example is the IntelliJ plugin, which allows the "fix all" code action from the file explorer.
> This PR refactors the language-server → tool code-action API to pass a single request struct (including an “is document open” flag), enabling the oxlint LSP linter to avoid re-running lint for code-action requests when the document is already open (and presumably already linted/cached).
This is mostly needed for https://github.com/oxc-project/oxc/pull/23768
When a user defined a custom config path, like `fmt.configPath` or `configPath`, the watch pattern returned the same path.
VS Code does not respect this as a valid pattern and does not watch for files defined like `./define-config.ts`.
Resulting into an LSP client, which will not send a watched-file-change requests to the server, when the user edited an important config path.
Closes https://github.com/oxc-project/oxc/issues/23617
Added the missing option `checkGlobalObject`, which detect globals, which are accessed by global object like `globalThis` or `window`.
`globalsObjects` option can extend the searching of globals.
Upstream implementation: https://github.com/eslint/eslint/pull/19939
Regenerated the tests with the just command.
Added some comments to skipped tests, explaining what is missing.
PS: this rule sounds like it can be resolved via `run_once` and the unresolved reference table. With the globals check like `window["foo"]`, `foo` is not longer a reference. Maybe someone has a great idea to run it only once
- Avoided looping over `array` of `array`, we only want to know the first level of structure for detecting a tuple config
- refactored some code and introduced a `.clone()` at the beginning. Hope this is fine for the rule doc code path. Feeling sometimes stupid without AI quick fixes :')
- enabled `node-callback-return` schema, which is the only rule that accepts a array as a config
- https://github.com/eslint-community/eslint-plugin-n/blob/master/docs/rules/callback-return.md
Fixed the new failing test from upstream, after we implemented the new upstreams test in #23524.
Added more tests for some use-cases, which could fail when fixing. Everything looks good 👍
This PR enables `strictIndexSignatures` option when generating `oxlint` config type declarations, allowing us to implement rule config schemas where the generation would produce a TS error.
See https://github.com/oxc-project/oxc/issues/23299 for the problem.
The generated code now appends `undefined` for some rule config options.
The docs of the option:
```
/**
* Append all index signatures with `| undefined` so that they are strictly typed.
*
* This is required to be compatible with `strictNullChecks`.
*/
strictIndexSignatures: boolean;
```
Added a new struct for 3 rules:
- `eslint/func-name-matching`
- `import/extension`
- `react/jsx-no-script-url`
These rules accept an enum configuration like:
```rust
enum ConfigOptions {
First(Option1),
Second(Option2),
Both(Option1, Option2)
}
```
Added the new struct for `eslint/func-name-matching` to test if the expected result matches the upstream configuration.
Changed the rule schema generation code, so enums (`subschema with any_of`), will be folded, Allowing us to support the 3 rules.
Because `RuleNoConfig` is already `AllowWarnDeny | [AllowWarnDeny]` we can reuse the reference for all other rules config and saving us some bytes on the TS config types generation.
It sounds stupid to create a snapshot from an already existing file.
Works on https://github.com/oxc-project/oxc/issues/22955 showed they will always match.
The PR changes the tests so it just checks if the existing file matches the output, without snapshots.
- Used `DefaultRuleConfig` to parse the `serde_json` value
- Moved the 25 cap, to the `Deserializer`
- added schema validation + deny unknown fields
- removed test cases where the upstream rule auto-generated options for every rule
With the changes from https://github.com/oxc-project/oxc/pull/23329, `Rope` does not need to be created and passed into the functions.
This PR removes all references to `Rope`, because we never access it.
The upstream rule has an option we do not to support:
```
/** Whether to not error when running with a tsconfig that has strictNullChecks turned. */
allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing?: boolean;
```
https://typescript-eslint.io/rules/no-unnecessary-condition/
The upstream rules does support one more option, but I guess we do not want this:
```
/** Unless this is set to `true`, the rule will error on every file whose `tsconfig.json` does _not_ have the `strictNullChecks` compiler option (or `strict`) set to `true`. */
allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing?: boolean;
```
https://typescript-eslint.io/rules/prefer-nullish-coalescing
Another little difference: The upstream rule marks as `true | IgnorePrimitivesOptions`, we support the `false` value too.
> ```
> /// This rule enforces consistency in which method is used to create parameterized tests.
> /// This configuration affects different test function types (`test`, `it`, `describe`, `suite`).
> ///
> /// ### Why is this bad?
> ///
> /// Without a consistent way to create parameterized tests, we rely on the developer to remember that
> /// `.for` spreads the values as different arguments while `.each` passes the array as a single argument.
> ```
For me this sounds more like `style`, because both ways are valid.
Because `oxc_parser` skips every file with over `u32::MAX` bytes, every option in `oxc_linter` can be safely `u32` too.
Refactored all rules which accepts in some for `usize` into `u32`.
- Added clippy-expects with a simple description why the cast is safe.
- Updated the schema to reflect the changes
Generated By 🧠 and ✋