## Summary
Fix the generated defaults for `unicorn/numeric-separators-style`. The rule already uses `number.minimumDigits: 5`, matching Unicorn, but the generated documentation and JSON schema advertise `0`. The same schema issue also advertises `groupLength: 0` for every numeric base.
## Why the defaults are wrong
`NumericBaseConfig` is shared by binary, hexadecimal, octal, and decimal configuration. Its derived `Default` initializes both numeric fields to zero. The rule supplies the actual defaults in `NumericSeparatorsStyleConfig::default()` and `NumericNumberConfig::default()`.
Schema generation uses the shared type's defaults for its individual properties. In particular, flattening `NumericBaseConfig` into `NumericNumberConfig` preserves the zero-valued property defaults instead of the decimal defaults. This makes the documented threshold disagree with the rule's existing behavior:
```js
1234; // Allowed with the default configuration.
12345; // Reported; the fix is 12_345.
```
## Change
Add a single parameterized schema helper for `NumericBaseConfig`, then select the appropriate defaults with `schemars(schema_with = ...)` on each field. The helper retains the derived schema's property descriptions, types, and constraints, and overrides only the `groupLength` and `minimumDigits` default metadata.
The resulting defaults are:
| Configuration | `groupLength` | `minimumDigits` |
| --- | --- | --- |
| `binary` | 4 | 0 |
| `hexadecimal` | 2 | 0 |
| `octal` | 4 | 0 |
| `number` | 3 | 5 |
The schema annotation on the flattened decimal base also corrects `number.minimumDigits`. `number.fractionGroupLength` remains unchanged, and the documentation continues to display its default as `Infinity`.
Regenerate the JSON configuration schema and the TypeScript configuration types from it. The generated TypeScript types inline the binary, hexadecimal, and octal option objects because those properties now have individual schemas; their accepted configuration shapes are unchanged.
This changes schema and documentation metadata only. Runtime defaults, option parsing, diagnostics, and autofixes are unchanged.
Fixes#26391
## Summary
- add the ESLint-compatible `checkConditionalExpressions` option to `no-unmodified-loop-condition`, defaulting to `false`
- port tests added by eslint/eslint#21175 and add regression coverage for repeated references within and across binary groups
Closes#26182.
# Oxlint
### 🚀 Features
- 60b945d linter/nextjs/no-typos: Implement suggestion (#26091) (Mikhail Baev)
### 🐛 Bug Fixes
- 33ac4b0 linter/lsp: Prevent tsgolint from holding onto processes (#25570) (Adrian Schaedle)
- baf4b1e linter/import/no-empty-named-blocks: Make empty value import removal a suggestion (#26155) (camc314)
- 77cfaec linter/eslint/object-shorthand: Preserve `__proto__` semantics (#26154) (camc314)
- fa3c082 linter/unicorn/prefer-set-size: Ignore shadowed `Set` constructors (#26153) (camc314)
- e412cf2 linter: Clamp invalid JS plugin locations (#26144) (camc314)
- d86c113 linter: Normalize reversed JS plugin locations (#26138) (camc314)
- 73c09b2 linter/eslint/no-use-before-define: Run on JS, JSX files (#26114) (camc314)
- 03ef0f2 linter/unicorn/no-useless-spread: Treat typed arrays as a distinct value hint (#26067) (Aadharsh Pannirselvam)
- bd15905 linter/react/no-unstable-nested-components: Check nested component object property names (#26101) (camc314)
- 3910e2b linter/eslint/no-unassigned-vars: Skip Svelte and Vue files (#26042) (Hamody We)
- 047f7ca linter/plugins: Fix interaction between JS plugins and Vue rules (#26080) (overlookmotel)
- 8531b9b linter/plugins: Alter method for obtaining mutable `Program` when sending AST to JS plugins (#26077) (overlookmotel)
- dc464ff linter/unicorn/prefer-math-min-max: Avoid unsafe autofix (#26060) (camc314)
### 📚 Documentation
- 464ddd1 linter: Support a shared short description for jest/vitest rules (#26186) (connorshea)
- 9db5ad3 linter: Add short description to `vue/no-dupe-keys` (#26183) (connorshea)
- db66f58 linter: Correct export/import mismatch in bar and foo example (#25927) (billychannnnnn)
- d5be037 linter/typescript/switch-exhaustiveness-check: Clarify default case comment pattern (#26100) (camc314)
# Oxfmt
### 🚀 Features
- 1fb37b6 formatter/css: Format declaration-shaped raw-prelude rules (postcss nested config blocks) (#26194) (leaysgur)
### 🐛 Bug Fixes
- 57e8e22 formatter_css: Space a folded sign after a call in Less operations (#26134) (leaysgur)
- e4298fb formatter/jsdoc: Follow CommonMark for interrupting lists and guard wrapping from creating them (#26098) (leaysgur)
- a1e21c2 formatter: Apply head body policy everywhere (#26074) (leaysgur)
- 676b7e1 formatter: Keep comments in their for-head slot, before an empty-statement body and do-while (#26073) (leaysgur)
- 3bbcea6 formatter: Keep comments between a head and its body out of the braces across all constructs (#26071) (leaysgur)
- 57537a2 formatter: Place comments between a head and open paren (#26058) (leaysgur)
- e2d53e7 formatter: Place comments between a statement head and its body (#26043) (leaysgur)
- 662556c formatter: Print the idempotent placement for comments in dropped parens (#26041) (leaysgur)
- faf11d9 formatter_yaml: Keep trailing whitespace in block scalars (#26072) (leaysgur)
### ⚡ Performance
- ac4785a diagnostics: Use fixed ANSI styles (#26130) (Boshen)
### 📚 Documentation
- b879608 formatter,formatter_graphql,formatter_yaml: Annotate own-line comment inlining as known policy violation (#26131) (leaysgur)
- 181953b oxfmt,formatter_core,formatter,formatter_yaml,formatter_css,formatter_graphql: Extract `DIVERGENCES.md` out from `AGENTS.md` (#26121) (leaysgur)
- a67cb9d formatter,formatter_core: Document comment moving policy (#26075) (leaysgur)
- fc175b0 formatter_core: Clarify idempotency test infra (#26069) (leaysgur)
## Summary
- clarify that `defaultCaseCommentPattern` recognizes a trailing comment in place of an omitted `default` clause
- document the required location, absence of a live `default`, and the `considerDefaultExhaustiveForUnions` requirement for union switches
- regenerate the JSON schema and TypeScript configuration types
Fixes#26087
## Summary
- represent variadic rule options as a severity followed by zero or more
option values
- regenerate the Oxlint configuration schema and TypeScript declarations
- add a type-level regression for mapped options spread into
`no-restricted-globals`
## Root cause
The schema wrapper materialized the first `additionalItems` entry as a
required tuple element and set `minItems` to 2. A dynamic TypeScript
spread has type `T[]` and may be empty, so it cannot satisfy that
required position even though the severity-only form is already valid
through `RuleNoConfig`.
Keeping severity as the only fixed tuple item and leaving the rule
options in `additionalItems` generates `[severity, ...options]`, which
accepts both an empty spread and populated spreads without changing
runtime rule behavior.
Closes#25666
## AI assistance
Implemented with assistance from OpenAI Codex. The contributor remains
responsible for reviewing, understanding, and submitting the change
under the repository AI usage policy.
---------
Co-authored-by: Cameron <cameron.clark@hey.com>
Remove the inactive `react/config` rule and its generated metadata. Oxlint uses fixed, valid React Compiler options, so the rule cannot produce actionable diagnostics.
AI-assisted: Codex was used to implement and validate this change.
Splits the experimental `react/react-compiler` rule into 24 category-specific rules matching `eslint-plugin-react-hooks` v7.
- Runs React Compiler once per file and routes structured diagnostics to each enabled rule.
- Removes `react/react-compiler` and `reportAllBailouts`, with rules categorized by user-facing lint intent.
- Adds per-rule documentation and deduplicates shared React lint URLs.
- Preserves standardized compiler diagnostics while reporting each finding under its Oxlint rule name.
Breaking change: configurations using `react/react-compiler` must migrate to the category-specific rules.
Written with Claude Code and Codex.
## Summary
- default `allowIndirect` to `false`, matching ESLint's `no-eval` behavior
- report bare global `eval` references and declared global-object member access by default
- avoid duplicate diagnostics for direct global calls while preserving `allowIndirect: true`
- add regression coverage, including an ESLint disable-next-line directive
Closes#25619.
## 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
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.
## 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>
## 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
The generated config reference only described the JSON schema's `string[]` form. Clarify that `oxlint.config.ts` accepts imported `OxlintConfig[]`, add an example and public JSDoc, and regenerate the derived artifacts.
Closes#20238.
Validated with the website generator suite, targeted TypeScript checks, and the relevant Oxlint tests. The full `just ready` run reached an unrelated parallel suppression-fixture cleanup race; the failing test passes in isolation.
AI-assisted.
Part of #22955. Follow-up to the resolved#23617.
## What
`eslint/no-restricted-globals` stayed in `NO_VERIFIED_VALID_SCHEMA`
after #23617 was resolved, because the derived schema described the
internal `NoRestrictedGlobalsConfig` struct (a `globals` hash map)
rather than the user-facing positional-array format the rule actually
parses.
This PR adds a hand-written `JsonSchema` following the existing
`no-restricted-imports` pattern, describing the three accepted
positional item forms:
1. `"event"` — a global name string
2. `{ "name": "event", "message": "…" }` — a name/message object
3. `{ "globals": [ … ], "checkGlobalObject": true, "globalObjects": [ …
] }` — the object form added in #23617
Generated TS declaration:
```ts
"no-restricted-globals"?:
RuleNoConfig | [AllowWarnDeny, NoRestrictedGlobalsConfigEnum, ...NoRestrictedGlobalsConfigEnum[]];
export type NoRestrictedGlobalsConfigEnum = string | RestrictedGlobal | NoRestrictedGlobalsObjectConfig;
```
Verified against the #22955 checklist: reflects all accepted user
configuration forms, denies unknown fields on object forms, and produces
no `[k: string]: unknown` in the TS declaration. `from_configuration`
and rule behavior are unchanged; rule tests pass.
Note: this branch removes only the `no-restricted-globals` entry from
`NO_VERIFIED_VALID_SCHEMA`; #24586 (separate PR) removes the
`filename-case` entry, so whichever merges second will have a trivial
conflict in that array.
## Disclosure
This contribution was developed with assistance from Claude Code
(Anthropic); I have reviewed and tested all changes.
---------
Signed-off-by: Alexander S. <sysix@sysix-coding.de>
Co-authored-by: Alexander S. <sysix@sysix-coding.de>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
## Summary
- Unskip `jest/prefer-lowercase-title` and
`vitest/prefer-lowercase-title` from `NO_VERIFIED_VALID_SCHEMA`.
- PreferLowercaseTitleConfig already derives `Deserialize` +
`JsonSchema` with `deny_unknown_fields` and docs for all public options,
so the generated schema/types can describe the real config.
- Regenerates `npm/oxlint/configuration_schema.json` and
`apps/oxlint/src-js/package/config.generated.ts`.
## Motivation
Part of #22955. These two plugin names shared a clean config struct
already used at runtime; they were still emit-as-`DummyRule` only
because of the broader #23186 split note (mainly about `valid-title`
option divergence). Leaving `valid-title` skipped.
Generated config now exposes:
- `allowedPrefixes: string[]` (default `[]`)
- `ignore: string[]` (default `[]`)
- `ignoreTopLevelDescribe: boolean` (default `false`)
- `lowercaseFirstCharacterOnly: boolean` (default `true`)
- `additionalProperties: false` / no `[k: string]: unknown`
## Verification
- `cargo test -p website_linter` — 8 passed
- `cargo test -p oxc_linter --features ruledocs
test_rules_with_custom_configuration_have_schema` — passed
- `cargo test -p oxc_linter prefer_lowercase_title --lib` — 2 passed
(jest + vitest)
- Inspected generated schema/TS: not DummyRule; no index signature
## AI disclosure
Assisted by AI (Hermes/Sera). I reviewed the existing
PreferLowercaseTitleConfig against the GFI checklist, regenerated
schema/types locally, and ran the tests above.
---
**Agent-Owner:** `sera` · **Platform:** hermes · **Claim:** `sera`
---
<!-- fleet-pr-claim: agent_id=sera platform=hermes -->
**Agent-Owner:** `sera` · **Platform:** hermes · **Claim-TTL:** 24h
---------
Co-authored-by: Bartok9 <259807879+Bartok9@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This implements
[`no-top-level-await`](https://github.com/eslint-community/eslint-plugin-n/blob/master/docs/rules/no-top-level-await.md)
from the Node ESLint plugin (#493).
AI Disclosure: Generated with Claude Code. Reviewed and tested by me.
I have an alternative implementation using a Program visitor but it made
no difference performance-wise on vscode or in benchmarking outside
extreme cases, so I don't think it's really worth the trouble vs the
simpler implementation here. It's still in the commit history if that
implementation is preferred.
There is one notable difference between this and the original
implementation, which is that the `convertPath` option is not
implemented, and the checking of `package.json`/`.npmignore` is not
implemented (it was used for checking if the given module was actually
exposed in the library) as there's no way to check against those in
oxlint. There's an argument to be made that this makes the rule not
worth implementing, and I'm open to that argument if we'd prefer to mark
this rule as unsupported instead.
All tests were ported from the original rule (excluding those reliant on
the mentioned config options/checks that were skipped). I've also had
Claude add a few additional test cases (see commit
40418f7e63) on top to cover behavior that
wasn't tested previously. I have confirmed that all of these tests are
identical to the behavior of the upstream rule, but I can remove them if
we don't want to have any divergence from the upstream test suite.
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Summary
- skip prefer-destructuring diagnostics for variable declarations with type annotations by default
- add enforceForDeclarationWithTypeAnnotation for typescript-eslint compatibility
- report without an autofix when annotated declarations are explicitly enforced, preserving the declared type
- cover object, computed-property, array, renamed-property, and reporter configuration cases
This matches the current `@typescript-eslint/prefer-`destructuring behavior.
Fixes#24615.
this PR moves `jest/padding-around-test-blocks` to the shared
jest_vitest rules, so it can be reused by both the jest and vitest
rules.
issue #4656
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
`is_ignored` in `vue/prop-name-casing` recompiled each slash-wrapped `ignoreProps` pattern with `Regex::new` for every prop it checked. This compiles the patterns once in `from_configuration` into an `Exact`/`Pattern(Regex)` matcher enum stored on the options (`serde`/`schemars`-skipped field), and matches against that.
Invalid regex patterns are dropped at compile time, which preserves the previous behavior (they could never match before either, and were not compared as literals).
### Benchmark
Interleaved paired-sample benchmark (N=40, alternating order, `--silent`), release binaries built from this branch and its merge-base.
Fixture: 220 Vue SFCs / 35,200 props / 36.5K lines, single-rule oxlintrc with `ignoreProps: ["ignored_prop", "/^legacy/", "/_deprecated$/", "/^(alpha|beta)_/", "/[/"]` (one exact pattern, three regexes, one invalid regex).
| | baseline | this branch |
|---|---|---|
| rule on | 66.87 ms | 16.69 ms |
| parse only | 8.47 ms | 8.41 ms |
Paired Δ of **+50.17 ms** (sd 2.18, t=146, faster in 40/40 pairs). The parse-only differential is null (+0.06 ms, t=0.2), so the saving is attributable to the rule and not to binary layout.
That works out to 4.0× on this fixture, but the multiplier is fixture-dependent — the work removed scales with `regex_pattern_count × prop_count`, so denser configs show a larger ratio. The ~50 ms saved across 35K props is the more transferable number.
### Correctness
Verified with `--format=json` (**without** `--silent`, which empties the JSON reporter's `diagnostics` array): both binaries emit the same 10,560 diagnostics, identical after sorting — the array order varies between runs because files are linted in parallel. The fixture includes canary props that are only ignored via the regex patterns, plus an invalid regex; the ignore semantics are unchanged.
### Disclosure
This change was implemented and benchmarked with AI assistance (Claude Code), and has been reviewed by the submitter.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
`match_argument_value_with_regex` recompiled every `allow` pattern with `Regex::new` for each `require()` call and `TSImportEqualsDeclaration` it checked. This compiles the patterns once in `from_configuration` into a `serde`/`schemars`-skipped `Vec<Regex>` on the config and matches against that. Same shape as #24412 and #24413.
### Benchmark
**Fixture:** a generated `requires.ts` with 30,000 one-line require calls of the form
```ts
const lib12345 = require('./lib12345');
```
None of the paths match an `allow` pattern, so every call pays the full allow-matching path and reports on both binaries (the common case for this rule: mostly-disallowed requires with a small allowlist). The allow/skip path itself was parity-checked separately with a canary mixing allowed string literals, an allowed template literal, an allowed `import ... = require(...)`, and reported requires.
**Config:** single-rule `.oxlintrc.json` so nothing else contributes to the timing:
```json
{
"plugins": ["typescript"],
"categories": { "correctness": "off" },
"rules": { "typescript/no-require-imports": ["warn", { "allow": ["/package\\.json$", "^some-package$", "\\.jsonc$"] }] }
}
```
**Method:** two release binaries (baseline from `main`, this branch), run interleaved in alternating order for 40 paired samples with warmup, timed with `time.monotonic_ns()`. A parse-only config on the same fixture showed no meaningful difference between the binaries (1.018×, t=1.7), so the delta is attributable to the rule rather than binary-layout noise.
| | mean |
|---|---|
| before | 410.80 ms |
| after | 32.26 ms |
**12.7× faster** (paired t=229, 40/40 wins). The magnitude scales with require-call count × number of `allow` patterns; configs that don't set `allow` are unaffected (the matching path is already guarded by `allow.is_empty()`). Diagnostics output is identical between the two binaries on the fixture (30,000 diagnostics) and the canary.
It is very unlikely that this will have much of an impact in most cases, as the option is rare and so are `require()` calls these days. But it's a simple enough improvement.
### Behavior note
An invalid `allow` pattern previously panicked (`.unwrap()`) at the first `require()` call in a linted file; it now panics when the configuration is loaded — same panic, strictly earlier.
### Disclosure
This change was implemented and benchmarked with AI assistance (Claude Code), and has been reviewed by the submitter.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
AI Disclosure: Generated with Claude Code, reviewed and tested by me. I don't think there's a particularly good reason to use a RwLock like this?
This can be split into separate PRs if preferred, as it also adds the type for this rule to the generated definitions and JSON Schema.
The rule kept compiled `checkTypesPattern` regexes in a global `OnceLock<RwLock<FxHashMap<String, Regex>>>`. Every `run()` on a JSDoc-documented function:
- cloned the pattern `String` to use as the map key,
- took the RwLock **write** lock even on cache hits, serializing all linter threads through a single lock, and
- held the guard across the entire parameter check.
The pattern is fixed at configuration time, so the cache is unnecessary: this PR deserializes the option directly into a `Regex` field on the config (same approach as #24412 / #24417) and deletes the cache entirely.
## Benchmark
Paired interleaved samples (N=40), release builds, fixture of 64 files × 400 fully-documented JSDoc functions (25,600 `run()` calls, all hitting the regex path, zero violations) with only `jsdoc/require-param` enabled:
| Run | Baseline (8de6fca) | This PR | Result |
|---|---|---|---|
| Rule enabled | 56.95 ms | 18.25 ms | **3.12×**, t=132.8, 40/0 wins |
| Parse-only null control (same fixture) | 11.05 ms | 10.75 ms | 1.03×, t=1.5 — noise |
Subtracting the ~11 ms parse floor, rule execution drops from ~46 ms to ~7 ms (~6.4×). The win is mostly the removed cross-thread lock contention, so it scales with file count on multi-core machines.
## Correctness
- Diagnostics are byte-identical between baseline and this PR on a mixed pass/fail canary, under both the default config and a custom `checkTypesPattern` config (which changes reporting, confirming the option deserializes and takes effect).
- `oxc_linter` lib tests (1,169), `oxlint` tests (396), and clippy pass; the generated website rule-doc page is byte-identical (`schemars(with = "String", default)` preserves the documented default).
## Invalid patterns are now a config error, not a panic
An invalid `checkTypesPattern` previously panicked lazily, on the first checked function. It now fails config loading with a proper diagnostic:
```
Failed to parse oxlint configuration file.
x Invalid configuration for rule `jsdoc/require-param`:
| regex parse error:
| ^(unclosed
| ^
| error: unclosed group
```
To get there, two things changed:
- The regex deserializer lives in `utils/config.rs` alongside the existing `deserialize_regex_option` / `deserialize_regex_vec` / `deserialize_required_regex_option` family, and builds via `RegexBuilder` with `D::Error::custom` like they all do.
- `from_configuration` propagates the serde error instead of dropping it with `.ok()`. The linter already has the plumbing for this — `config/rules.rs` turns an `Err` into `OverrideRulesError::RuleConfiguration` — the `.ok()` was just discarding it.
### Behavior change worth flagging
Now that `from_configuration` no longer swallows errors, this config's `deny_unknown_fields` is load-bearing for the first time. A config carrying an `eslint-plugin-jsdoc` option that oxc doesn't implement (e.g. `unnamedRootBase`) previously fell back to defaults silently; it now fails to load with an "unknown field" error. No lint *results* change, but a user porting an eslint-plugin-jsdoc config that oxc previously tolerated will now see a config error.
That surfaced in the ported test suite: eight cases configure `unnamedRootBase` (×5), `enableFixer` (×2), `enableRootFixer`, and `autoIncrementBase`, none of which this rule implements. They're commented out, and the snapshot is regenerated accordingly.
If maintainers would rather keep the lenient behavior, the alternative is to validate `checkTypesPattern` up front and keep the `.ok()` fallback for everything else — that removes the panic without touching any test or changing config tolerance. Happy to switch.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Adds a `namespaces` option to `eslint/no-inner-declarations`:
```json
["error", "both", { "namespaces": "allow" }]
```
With `namespaces: "allow"`, `function`/`var` declarations placed directly inside a TypeScript `namespace`/`module` body are no longer reported. Declarations nested inside blocks within a namespace (e.g. `namespace N { if (x) { function f() {} } }`) are still reported. The default (`disallow`) is unchanged.
Closes#21143
Fixes#24310
Root config's `ignorePatterns` are now resolved relative to the directory containing the config file, instead of CWD.
Also fixes a latent issue: a `--config <path>` containing `..` silently disabled all `ignorePatterns` (the unnormalized parent dir never prefix-matches lint target paths). Explicit config paths are now lexically normalized, same as Oxfmt.
### Behavior change
The new anchoring applies in all cases, including `--config` / LSP `configPath`. This intentionally differs from ESLint, which resolves alternate-config ignore patterns relative to CWD:
- `extends`, `overrides[].files`, and JS plugin specifiers are already config-file-relative, including via `--config`
- rooting only `ignorePatterns` at CWD would give one file two coordinate systems
- Wrappers like Vite+ pass `--config <workspace-root config>` as an implementation detail while CWD stays at the invocation directory, so "`--config` means CWD-relative" does not hold in practice
- #24276
Impact should be small: bare names (`dist`, `*.min.js`) and `**/`-prefixed patterns are unaffected by the anchor.
The updated `config_ignore_patterns/with_oxlintrc` snapshot shows the `--config` case.