Commit Graph

14391 Commits

Author SHA1 Message Date
Dunqing 893a949a5d fix(transformer): skip async generators in async-to-generator
Async generator methods must return async iterators, but the method
visitor sent them through async-to-generator and changed their return
value to a Promise.

Match the other function paths and Babel by leaving these methods for
the async-generator-functions transform.
2026-09-04 09:08:37 +08:00
Dunqing ce757a5f8e fix(transformer): preserve this in lowered async methods
Async method bodies moved into generated generator functions lose their
receiver when arrow-function lowering is enabled at the same time.

Track the two async transforms separately so ordinary async methods and
async generator methods capture `this` only when their owning transform
actually moves the body.
2026-09-01 23:41:54 +08:00
camc314 4ba33c81d1 fix(linter/eslint/no-unused-vars): handle stored arrow references (#26225)
## Summary

- recognize references returned from arrow functions stored on properties
- treat arrow functions passed to calls and constructors as independently callable
- preserve self-use detection for immediately invoked arrow functions
- add regression coverage based on VSC-NeuroPilot/neuropilot
2026-09-01 15:02:56 +00:00
oxc-guard 0b4e2e67f4 release(apps): oxlint v1.81.0 && oxfmt v0.66.0 (#26199)
# 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)
2026-09-01 08:25:16 +00:00
oxc-guard 894c8f9cd8 release(crates): oxc v0.148.0 (#26198)
### 💥 BREAKING CHANGES

- a31567a allocator: [**BREAKING**] Make `Allocator::cursor_ptr` and `data_end_ptr` private (#26081) (overlookmotel)

### 🚀 Features

- 784e9fa minifier: Invert `!0` and `!1` in place for boolean context to `1` and `0` (#26050) (Armano)
- 1e902cc minifier: Expand fold leading assignments into the var decl (#26142) (Armano)
- 3ed4f6a minifier: Expand de morgan's optimization to allow move of `!` (#25930) (Armano)
- 5672585 parser: Attach all comments to nodes (#25944) (camc314)

### 🐛 Bug Fixes

- 4adfb4c semantic: Validate chained continue labels (#26157) (camc314)
- b874f48 ecmascript: `Math.round` only exact half ties (#26150) (camc314)
- a625378 minifier: Coerce omitted `indexOf` search argument (#26149) (camc314)
- dc7398b ecmascript: Trim trailing whitespace in string to number (#26148) (camc314)
- 243b685 transformer/object-rest: Lower multiple declarators correctly (#26147) (camc314)
- dc09a3a parser: Avoid panic on escaped string export names (#26146) (camc314)
- e412cf2 linter: Clamp invalid JS plugin locations (#26144) (camc314)
- c3dedc9 semantic: Skip function body bindings in parameters (#26099) (Dunqing)
- e74de61 transform-react: Match Babel diagnostic reporting (#26128) (Boshen)
- d5163d0 parser: Correctly classify unapplied pure annotations (#26084) (camc314)
- 8531b9b linter/plugins: Alter method for obtaining mutable `Program` when sending AST to JS plugins (#26077) (overlookmotel)
- 9b51658 regular_expression: Allow oversized decimal escape for Annex B (#26070) (leaysgur)
- c8de4df regular_expression: Reject oversized backreferences (#26055) (camc314)

### ⚡ Performance

- ac4785a diagnostics: Use fixed ANSI styles (#26130) (Boshen)
- 07a0793 packages/codegen: Flatten output in chunks (#26109) (overlookmotel)
- 487427a packages/codegen: Faster string flattening (#26108) (overlookmotel)
- 7785583 packages/codegen: Ensure indent strings are flattened (#26107) (overlookmotel)
- 0dd4db3 packages/codegen: Store mapping positions in an `Int32Array` (#26085) (overlookmotel)
2026-09-01 08:15:07 +00:00
leaysgur 9f81002229 fix(formatter): re-add suppressed statement terminators per options.semi (#26220)
```js
// input (semi: true)
// oxfmt-ignore
const a = x

// before
// oxfmt-ignore
const a = x

// after
// oxfmt-ignore
const a = x;
```

```js
// input (semi: false)
let a = 1;
// oxfmt-ignore
[b].sort();

// before
let a = 1
// oxfmt-ignore
[b].sort(); // <- ASI failure

// after
let a = 1
// oxfmt-ignore
;[b].sort() // <- OK
```
2026-09-01 07:25:43 +00:00
leaysgur 769ffd590d fix(formatter): print suppressed typecast parens (#26218)
```js
// input
foo(
  // oxfmt-ignore
  /** @type {A} */ (x),
  /** @type {B} */ (y),
);

// before
foo(
  // oxfmt-ignore
  /** @type {A} */ x, // <-
  /** @type {B} */ (y),
);

// after
foo(
  // oxfmt-ignore
  /** @type {A} */ (x), // <-
  /** @type {B} */ (y),
);
```
2026-09-01 07:25:42 +00:00
leaysgur 5ff57f83c0 fix(formatter/sort-imports): handle custom side effect groups (#26217)
Fixes #26165

- `side_effect` is predefined selector, it cannot be used as custom group name
- respect custom group which uses `side_effect` as side-effect-import correctly
- fix metadata detection bug
2026-09-01 03:56:36 +00:00
leaysgur 2f4d759717 fix(formatter): do not skip cast comment lookup (#26216)
Fixes #26202

---

The trigger for this issue is the presence of a suppressed typecast.

```js
// oxfmt-ignore
const cast = /** c */ (x)
```

Because a comment had already been printed in a subsequent typecast check without going through the casting mechanism, it failed to find its own cast comment.
2026-09-01 03:56:35 +00:00
leaysgur 1213e12c0e fix(formatter): preserve comment for statement terminators and binary casts (#26213)
Refine comment position preserving rules, for statements and binary casts. Fixes idempotency issues for several sites.

---

Trailing is the same-line run only.
A newline-preceded comment is never trailing. It defers to the next node's leading pass, staying own-line with its blank lines.

Comments around `as`/`satisfies` keep their source side and line-start side, within the grammar-defined slots (line terminator is not allowed between `as` and before).
2026-09-01 03:56:35 +00:00
Dunqing a3d33dda7c fix(semantic): skip body bindings in type parameters and this param (#26169)
#26099 resolves parameter and signature references before visiting the function body, so they cannot bind to declarations that only exist inside the body. That early pass only ran when the function had parameters or a return type. Type parameter constraints and a `this` parameter type are visited before that check, so a function whose signature has references only in those positions skipped the pass. Its references then resolved after the body was visited and bound to body-local types.

## Example

```ts
type U = number;
function f<T extends U>() {
  type U = string;
  return null! as T;
}
```

Before this change, `U` in the constraint resolved to the body-local `type U = string`. TypeScript scopes local types to the function body, so it must resolve to the outer alias. The same happened for `function f(this: U) { type U = string }` and for arrow functions with type parameters.

The early pass now runs for every function and arrow function. It returns immediately when the signature produced no references, so the `has_parameter() || return_type.is_some()` condition, which approximated that check, is no longer needed.

Also adds a regression test for the compaction in `resolve_references_for_current_scope`: a resolved reference followed by an unresolved one must neither drop nor duplicate entries, and no existing test covered that ordering.

Verified with the semantic and transformer unit tests, Clippy, `cargo coverage -- semantic`, and transform conformance; no snapshots changed.

AI assistance: Claude Code was used to investigate, implement, and verify this change. The contributor is responsible for the submitted change.
2026-08-31 09:23:18 +00:00
Dunqing a09c3e0220 refactor(semantic): simplify resolve_references_for_current_scope (#26167)
Follow-up to https://github.com/oxc-project/oxc/pull/26099: make it readable and easy to understand.
2026-08-31 09:23:17 +00:00
Armano 115955d048 feat(minifier): drop cases whose condition is statically false (#26172)
Add logic to drop switch cases whose test is never reached

fixes #26141
2026-08-31 17:16:40 +08:00
leaysgur 1fb37b6e47 feat(formatter/css): format declaration-shaped raw-prelude rules (postcss nested config blocks) (#26194)
Fixes #26158

---

> Otherwise, [restore a mark](https://drafts.csswg.org/css-syntax-3/#token-stream-restore-a-mark) from input, then [consume a qualified rule](https://drafts.csswg.org/css-syntax-3/#consume-a-qualified-rule) from input, with nested set to true, and [<semicolon-token>](https://drafts.csswg.org/css-syntax-3/#typedef-semicolon-token) as the stop token.
> https://drafts.csswg.org/css-syntax-3/#consume-block-contents

When fallback happens: format block, keep prelude verbatim.
2026-08-31 04:42:06 +00:00
Alexander S. 409b4e27f3 perf(lsp): increase concurrency level by available threads (#25153)
> Adjusts the Oxc language server startup to scale Tower LSP request
handling concurrency based on the machine’s available parallelism,
aiming to improve throughput on higher-core systems without fully
saturating the host.

The saturation is from personal feeling and did not get benchmarked.

---------

Signed-off-by: Alexander S. <sysix@sysix-coding.de>
Signed-off-by: Yuji Sugiura <6259812+leaysgur@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Yuji Sugiura <6259812+leaysgur@users.noreply.github.com>
2026-08-31 00:27:18 +00:00
connorshea 464ddd1806 docs(linter): support a shared short description for jest/vitest rules (#26186)
AI Disclosure: Generated with Claude Code, Fable 5. Reviewed by me. This sets up the short_description to be added to the various rules shared between jest and vitest.

`declare_oxc_lint!` now accepts a path to a shared constant for `short_description`, mirroring how `docs = SHARED_DOCUMENTATION` works. Like `documentation`, the handling is gated behind the `ruledocs` feature.

A shared short description is added to `expect-expect`, `no-disabled-tests`, and `valid-expect`.

Rules where the wording legitimately differs per framework (e.g. `no-alias-methods`) can keep per-plugin string literals, which remain supported. Or we can opt to add the raw strings on every one of these rules and drop the shared short desc idea, I don't have a strong preference either way.

Once we decide and merge this, we can add the short descriptions for all the other remaining shared rules. We'll also need to split up the two remaining rules that are problematic (https://github.com/oxc-project/oxc/issues/23186), then we can expose the `short_description` field in the JSON rules formatter for use on the website's rules list view.
2026-08-30 20:40:00 +00:00
connorshea 9db5ad39b5 docs(linter): add short description to vue/no-dupe-keys (#26183)
This rule was the only Vue rule missing a short description, so this fixes that.
2026-08-30 19:49:05 +00:00
billychannnnnn db66f5821d docs(linter): correct export/import mismatch in bar and foo example (#25927)
The example incorrectly used a named import for a default export.
Changed `export default function bar()` to `export function bar()` to
align with the `import { bar }` statement.

Signed-off-by: billychannnnnn <billychannnnnn@foxmail.com>
2026-08-29 19:59:18 +02:00
Adrian Schaedle 33ac4b0915 fix(linter/lsp): prevent tsgolint from holding onto processes (#25570)
Attempts to address:
- oxc-project/oxc#17070
- oxc-project/oxc#21402,
- oxc-project/oxc-vscode#264

I recently started enabling the type-aware rules as part of my editor's
linter (zed). I quickly started hitting resource exhaustion limits on
macOS. Listing processes showed thousands of zombie tsgolint entries
with oxlint as the parent.

Doing a little digging, I found the above issues listing similar
resource exhaustion. oxc-project/oxc#24670 attempted to solve this issue
by calling `child.kill` on the tsgolint process, but this is not enough
on macOS. From [the `Child`
docs](https://doc.rust-lang.org/std/process/struct.Child.html):

> On some systems, calling wait or similar is necessary for the OS to
release resources. A process that terminated but has not been waited on
is still around as a “zombie”. Leaving too many zombies around may
exhaust global resources (for example process IDs).
>
> The standard library does not automatically wait on child processes
(not even if the Child is dropped), it is up to the application
developer to do so. As a consequence, dropping Child handles without
waiting on them first is not recommended in long-running applications.

This change follows this advice and adds a `wait` after the existing
`kill`.
2026-08-29 15:12:42 +02:00
Armano 784e9faad2 feat(minifier): invert !0 and !1 in place for boolean context to 1 and 0 (#26050)
improve negation of 1 and 0 to 0 and 1 in boolean context

previously only `!!0` and `!!1` could be inlined to `1` and `0` and now
`!0` and `!1` will also be inlined,

this change allows us to flip numeric values in-place instead of having
to first to create unary and remove it afterwards

```
!0 was converted before to 1 in some cases:
1. negate 1
2. !1 - add unary
3. 0 - remove unary

now:
1. negate 1
2. 0
```
2026-08-29 15:36:17 +08:00
Armano 1e902cc1ad feat(minifier): expand fold leading assignments into the var decl (#26142)
expands leading assignment inlining into variable declarations for
`return`, `switch`, `if`, `throw`, `for`, `for in`, `for of`
```js
// return
var a; return a = b(), c;
var a = b(); return c;
// throw
var a; throw a = b(), c;
var a = b(); throw c;
// switch
var a; switch (a = b(), c) {}
var a = b(); switch (c) {}
// for
var a; for (a = b(), c; ;) d;
var a = b(); for (c; ;) d;
// if
var a; if (a = b(), c) d;
var a = b(); if (c) d;
```

fixes #25949
2026-08-29 04:27:01 +08:00
camc314 4adfb4c949 fix(semantic): validate chained continue labels (#26157)
## Summary

- follow chained labels to their terminal statement when validating labeled `continue`
- reject label chains that terminate in a non-iteration statement
- add a focused negative coverage fixture and update the parser coverage snapshot
2026-08-28 18:45:13 +00:00
Armano 3ed4f6ad90 feat(minifier): expand de morgan's optimization to allow move of ! (#25930)
Expand negation to include move of `!` operator to inner children

```js
!(a == b && c == 3 && a)
a != b || c != 3 | !a
```

delta calculation is dependent on boolean context
- if we expect truthly/falsly value negation of `!a` will be converted
to `a` (-1 delta)
- in ambiguous context `!a` will be converted to `!!a` (+1 delta)

```js
a = !!(!b || !c);
//   ^ ^     ^ -3
a = !(b || c)
//  ^ ^    ^ +1 - if we could detect if parens can be removed it would be -1
//  ^^^    ^^ -1 - if we would know that we can remove parens
```
2026-08-29 02:08:57 +08:00
camc314 baf4b1e00a fix(linter/import/no-empty-named-blocks): make empty value import removal a suggestion (#26155)
## Summary

- classify removal of empty value imports as a suggestion because deleting them can drop module evaluation side effects
- keep removal of empty type-only imports as an automatic fix
- preserve the rule’s existing deletion behavior
2026-08-28 16:29:00 +00:00
camc314 77cfaec3f3 fix(linter/eslint/object-shorthand): preserve __proto__ semantics (#26154)
## Summary

- exclude non-computed `__proto__` properties from shorthand and longform conversions
- preserve computed `__proto__` properties as safely fixable
- add regressions for methods, arrows, property shorthand, quoted keys, and `never` mode
2026-08-28 15:40:47 +00:00
camc314 fa3c0825e2 fix(linter/unicorn/prefer-set-size): ignore shadowed Set constructors (#26153)
## Summary

- verify that new Set constructors resolve to the intrinsic global before reporting or fixing
- preserve detection for direct constructions and const-bound Set instances
- add regression coverage for a locally shadowed constructor that returns an array
2026-08-28 15:30:27 +00:00
camc314 b874f480c9 fix(ecmascript): Math.round only exact half ties (#26150)
[ECMA-262 §21.3.2.29, `Math.round`](https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-math.round).

- If `0 < n < 0.5`, return `+0`.
- If `-0.5 ≤ n < -0`, return `-0`.
- Otherwise choose the closest integer, preferring `+∞` only for an actual tie.
2026-08-28 14:26:10 +00:00
camc314 a625378066 fix(minifier): coerce omitted indexOf search argument (#26149)
## Summary

- Apply `ToString(undefined)` when `String.prototype.indexOf` or `lastIndexOf` is called without a search argument.
- Keep folding strings without the resulting `"undefined"` substring to `-1`.
- Add focused helper and minifier regression coverage.

```js
"undefined".indexOf();     // 0
"undefined".lastIndexOf(); // 0
"abcdef".indexOf();        // -1
"abcdef".lastIndexOf();    // -1
```
2026-08-28 14:18:01 +00:00
camc314 dc7398beae fix(ecmascript): trim trailing whitespace in string to number (#26148)
## Summary

`StringToNumber` previously removed ECMAScript whitespace only from the beginning of a string. Legal trailing whitespace therefore remained in the value passed to Rust’s numeric parsers, causing valid JavaScript numeric strings to produce `NaN`.

For example:

```js
"1 " * 2       // incorrectly folded to NaN
"0x10 " - 0    // incorrectly folded to NaN
```

This changes `trim_start_matches` to `trim_matches`, applying the existing ECMAScript whitespace predicate to both ends of the string.

After the change:

```js
"1 " * 2       // folds to 2
"0x10 " - 0    // folds to 16
```

The custom predicate remains important because ECMAScript and Rust define whitespace differently. Tests cover every ECMAScript whitespace character and verify that non-ECMAScript whitespace such as U+0085 is not accepted.
2026-08-28 14:07:56 +00:00
camc314 243b685c3d fix(transformer/object-rest): lower multiple declarators correctly (#26147)
## Summary

Fix ES2018 object-rest lowering when one variable declaration contains multiple object-rest declarators.

### Before

Given:

```js
let { a, ...r } = x, { b, ...s } = y;
```

Oxc produced:

```js
let { a } = x, { b } = y,
  s = babelHelpers.objectWithoutProperties(y, ["b"]),
  {} = null;
```

The `r` binding was lost.

Each replacement was recorded using its original declarator index. Replacing the first declarator expanded it into multiple entries, shifting the second declarator. The subsequent replacement still used the old index and overwrote part of the first expansion.

### After

Oxc now produces:

```js
let { a } = x,
  r = babelHelpers.objectWithoutProperties(x, ["a"]),
  { b } = y,
  s = babelHelpers.objectWithoutProperties(y, ["b"]);
```

Queued replacements are applied from right to left. Replacing a later declarator cannot change the index of an earlier one, so every recorded index remains valid.

Regression coverage includes multiple `let`, `const`, and `var` declarators.
2026-08-28 14:02:19 +00:00
camc314 dc09a3aa9d fix(parser): avoid panic on escaped string export names (#26146)
## Summary

Fix a parser panic when a string-named export decodes to a literal `\u` sequence.

Lone-surrogate validation now uses the metadata captured by the lexer instead of rescanning decoded string contents. This also prevents false diagnostics for names such as `"\\uD800"`.

## Before:

```

thread 'main' (10990283) panicked at crates/oxc_ast/src/ast_impl/literal.rs:89:42:
end byte index 4 is out of bounds for string of length 0
stack backtrace:
   0: __rustc::rust_begin_unwind
   1: core::panicking::panic_fmt
   2: core::str::slice_error_fail_rt
   3: core::str::slice_error_fail
   4: <core::ops::range::RangeTo<usize> as core::slice::index::SliceIndex<str>>::index
   5: <str as core::ops::index::Index<core::ops::range::RangeTo<usize>>>::index
   6: <oxc_ast::ast::literal::StringLiteral>::is_string_well_formed_unicode
   7: <oxc_parser::ParserImpl<oxc_parser::config::NoTokensParserConfig>>::parse_module_export_name
```
2026-08-28 13:37:48 +00:00
camc314 e412cf2ce3 fix(linter): clamp invalid JS plugin locations (#26144)
Follow-up to #26138, closes #25867.

External plugins can report a node range past the source text. The default formatter rejects that invalid span and previously panicked. Clamp external diagnostic offsets to the source's UTF-16 length before normalizing reversed ranges.

The end-to-end fixture now covers:
 - reversed locations
 - negative loc values
 - negative node ranges
 - an out-of-range node range in Unicode source text
2026-08-28 13:33:32 +00:00
Dunqing c3dedc9b0c fix(semantic): skip function body bindings in parameters (#26099)
Function parameters, TypeScript signatures, and function bodies currently share one Oxc semantic scope. A reference in a parameter can therefore bind to a declaration inside the body, even though JavaScript does not make body declarations visible there. Rolldown may then treat a global as local, skip a configured define, or remove live code.

## Example

```js
export function load(value = typeof window !== "undefined") {
  var window;
  return value;
}
```

The body `var window` is not visible to the default value. Before this change, Oxc resolved `window` in the default value to that body declaration. It should remain a global reference.

The workaround resolves parameter and signature references before visiting the body, while only parameter bindings are present. If a reference is still unresolved, its `lookup_scope_id` advances to the function's parent. Final resolution resumes there, so declarations added while visiting the body are skipped. References created in the body still begin at the function scope and resolve normally.

```text
Before: parameter reference -> completed function scope -> body binding (wrong)

After:  parameter reference -> parameter bindings -> parent scopes
        body reference      -> completed function scope -> parent scopes
```

Parameter decorators already begin in the enclosing class scope, so they are left for normal final resolution. This emulates separate parameter and body scopes until https://github.com/oxc-project/backlog/issues/176 is implemented.

The corrected semantic data also exposes the transformer case covered by #26105.

Verified with semantic and transformer-plugin tests, Clippy, coverage, allocation snapshots, and diff checks. `just ready` completed workspace checks but stopped at a codegen snapshot recorded with Node.js v26.5.0; the local version is v25.8.1.

Closes #20427
Closes #22783

Downstream reports:

- https://github.com/rolldown/rolldown/issues/10722
- https://github.com/rolldown/rolldown/issues/10779

AI assistance: OpenAI Codex was used to investigate, implement, and test this change. The contributor is responsible for the submitted change.
2026-08-27 17:23:18 +00:00
camc314 d86c1137c4 fix(linter): normalize reversed JS plugin locations (#26138)
## Summary
- normalize reversed JS plugin diagnostic locations to empty spans at their stated start
- add an end-to-end regression fixture for reversed `loc` positions

https://github.com/oxc-project/oxc/issues/25867
2026-08-27 11:11:26 +00:00
leaysgur 57e8e22483 fix(formatter_css): space a folded sign after a call in Less operations (#26134)
Follow up on #26132.

By that change, Less is also possible to format binary operation like SCSS.
2026-08-27 07:49:30 +00:00
leaysgur 0e734cc7ae test(formatter_css): pin signed-value parser fixes from oxc-css-parser 0.0.12 (#26132)
Bump parser and pin fixed by https://github.com/oxc-project/oxc-css-parser/pull/158
2026-08-27 07:49:30 +00:00
leaysgur b8796080d5 docs(formatter,formatter_graphql,formatter_yaml): annotate own-line comment inlining as known policy violation (#26131) 2026-08-27 06:29:50 +00:00
leaysgur f94b22296c test(formatter,formatter_css,formatter_json,formatter_yaml): restore coverage lost in fixture consolidation (#26129)
- Restore wrongly consolidated fixtures
- State new fixtures policy and apply
- Check `endOfLine` option and output at test harness level
2026-08-27 06:12:52 +00:00
leaysgur 2dba883bf2 test(formatter): consolidate redundant JS fixtures (#26126)
Consolidate redundant fixtures.
2026-08-27 05:34:00 +00:00
leaysgur 2d57487a30 test(formatter): consolidate redundant TS fixtures (#26125)
Consolidate redundant fixtures.
2026-08-27 05:34:00 +00:00
leaysgur 3e5adf9e87 test(formatter_css): consolidate redundant fixtures (#26124)
Remove redundant fixtures.
2026-08-27 05:33:59 +00:00
leaysgur 69b9a0ed81 test(formatter_graphql, formatter_yaml): consolidate fixtures and fix crlf coverage gap (#26123)
GQL: Consolidate redundant fixtures
YAML: Just add notes
2026-08-27 05:33:59 +00:00
leaysgur 9a2e378d25 test(formatter_json): consolidate redundant fixtures (#26122)
Mainly remove redundant fixtures.
2026-08-27 05:33:58 +00:00
leaysgur 181953b92d docs(oxfmt,formatter_core,formatter,formatter_yaml,formatter_css,formatter_graphql): extract DIVERGENCES.md out from AGENTS.md (#26121)
- Extract "known divergences" section from `AGENTS.md` to explicit `DIVERGENCES.md` with code example
- Update all anchors
- Add missing pinned fixtures
2026-08-27 05:33:58 +00:00
Boshen e74de61886 fix(transform-react): match Babel diagnostic reporting (#26128)
Match Babel’s default React Compiler diagnostic reporting and severity.

AI-assisted.
2026-08-27 05:27:21 +00:00
Boshen ac4785a139 perf(diagnostics): use fixed ANSI styles (#26130)
Replace dynamic diagnostic styles with fixed ANSI prefixes, reducing `oxfmt` and `oxlint` release text size.

AI assistance: Codex was used. The contributor remains responsible for this change.
2026-08-27 05:19:35 +00:00
camc314 73c09b212e fix(linter/eslint/no-use-before-define): run on JS, JSX files (#26114)
Fixes #26113.

The rule was moved from the TypeScript plugin to the ESLint plugin in 79fc6d7e9f, but its TypeScript-only execution gate was retained. As a result, eslint/no-use-before-define never ran for JavaScript or JSX files.Remove the gate and add a JavaScript regression test for a temporal-dead-zone reference.
2026-08-26 14:55:36 +00:00
Boshen a565a37d1d fix(react_compiler): bail out on missing identifier nodes (#26112)
Match upstream's catchable missing-identifier invariant in `PruneNonEscapingScopes`, preventing a later misleading `PreserveManualMemo` diagnostic. Adds the original-shaped named function expression regression.

AI-assisted and reviewed by the contributor.
2026-08-26 14:47:42 +00:00
camc314 d5163d0faa fix(parser): correctly classify unapplied pure annotations (#26084)
Mark all `#__PURE__` annotations not directly applied to a `NewExpression` or CallExpression` as `PureNotApplied`.

This changes the approach by letting pure annotations start of their life as `CommentContent::PureNotApplied`, and only changing to `CommentContent::Pure` once they have successfully been applied to a node.

This aligns the behaviour with Rollup.

Rollup Playground:

https://rollupjs.org/repl/?version=4.63.0&shareable=eyJleGFtcGxlIjpudWxsLCJtb2R1bGVzIjpbeyJjb2RlIjoidmFyIGZvbyAvKiAjX19QVVJFX18gKi8gPSBwdXJlT3BlcmF0aW9uKCk7XG5mb28gLyogI19fUFVSRV9fICovID0gcHVyZU9wZXJhdGlvbigpO1xuZm9vIC8qICNfX1BVUkVfXyAqLyArIHB1cmVPcGVyYXRpb24oKTtcbmZvbyAvKiAjX19QVVJFX18gKi8gJiYgcHVyZU9wZXJhdGlvbigpOyIsImlzRW50cnkiOnRydWUsIm5hbWUiOiJtYWluLmpzIn1dLCJvcHRpb25zIjp7fX0=

Rolldown Playground: (only the 1st pure comment is marked as not applied).

https://repl.rolldown.rs/#eNqlkU1LxDAQhv/KEGG/LO294kk8K4K3QEnbyW60nYR0uu5S+t9NUlwRPQgLgczHOy/zMJPQopyEoRZP+dsQYxLld56JJqRH5UFbC8UObqrq+fXlsapgV8A9uNHjk0Ov2FjabO+kl3Sd8vbfytXqlzTsi6JkP+KcCW+7rrUflDeWtNnnfMH7o7OAmt5ZzzBBi9oQPqQ2zKC97WH9NbaWJAlPSRqEauzSfxnYTJIADLmRS1gs8x5Z5amUQVEAHxC06XCAATtsGFuoz6laj8yWIDxUzQFY1dEsjFgXIYeY2ZGT9wS9IaPPJURkmCXNW0kisDvVvKs9hhPaALxQ/6gtvGlRKVp0GC5OjcFBiuAbnaJRcDoGWacYBxbzJ8uvunY=

fixes https://github.com/oxc-project/oxc/issues/23669
closes https://github.com/oxc-project/oxc/pull/24161
2026-08-26 10:33:48 +00:00
Aadharsh Pannirselvam 03ef0f27ba fix(linter/unicorn/no-useless-spread): treat typed arrays as a distinct value hint (#26067)
Closes #25868.

## What

`unicorn/no-useless-spread` inferred "returns a plain array" from the
method name
alone, so `[...new Uint8Array(buf).slice(0, 12)]` was reported and
`--fix` removed
the spread. That spread is the conversion to `number[]`, so the
following `.map()`
kept running as `TypedArray.prototype.map` and coerced every callback
result back
into the element type. #25868 has the measurements and the seven
affected methods.

## Approach

Rather than guard the one call site, this adds a
`ValueHint::NewTypedArray` variant
beside the existing `NewArray` / `NewObject` / `NewIterable`.

The reason is chains. A one-off receiver check handles
`new Uint8Array(buf).slice(0)` and misses `new
Uint8Array(buf).slice(0).map(f)`,
where the receiver is itself a call. Carrying the typed-array fact
through
`const_eval` means the existing recursion does that work, and
`[...new Uint8Array(buf).slice(0, 12).map(f)]` passes with no extra
code.

`is_array()` stays false for the new variant, so nothing is reported.
Three places
feed it:

- `NewExpression::const_eval`, via the existing `is_new_typed_array`
- `is_typed_array_from`, for `Uint8Array.from(x)`
- `is_typed_array_method`, for a clone method whose receiver already
evaluates to
  `NewTypedArray`

## One deviation from the fix sketched in the issue

The issue proposed splitting the typed-array names out of
`is_array_from`. That
would regress an existing `fail` vector, because `is_array_from` has a
second
consumer doing a different job.

`mod.rs:362` uses it to decide whether a spread passed *into* `from` is
useless,
which it is for every constructor in that list, since they all accept an
iterable.
`BigUint64Array.from([...iterable])` is in the `fail` vectors today and
should stay
there. Only the *result*-type inference in `const_eval` was wrong.

So `is_array_from` keeps its full list and gains a doc comment saying
which of the
two questions it answers, and `const_eval` drops its call to it.
`Array.from(x)`
keeps evaluating to `NewArray` through `is_array_factory`, which already
matches
`Array.{from,of}` with any argument count.

## Behaviour

| expression | before | after |
|---|---|---|
| `[...new Uint8Array(b).slice(0, 12)]` | reported, fixed | passes |
| `[...new Uint8Array(b).map(f)]` | reported, fixed | passes |
| `[...new Uint8Array(b).filter(f)]` | reported, fixed | passes |
| `[...new Uint8Array(b).toReversed()]` | reported, fixed | passes |
| `[...new Uint8Array(b).toSorted()]` | reported, fixed | passes |
| `[...new Uint8Array(b).with(0, 1)]` | reported, fixed | passes |
| `[...Uint8Array.from([1, 2, 3])]` | reported, fixed | passes |
| `[...new Uint8Array(b).slice(0).map(f)]` | reported, fixed | passes |
| `[...[1, 2, 3].slice(0, 2)]` | reported, fixed | unchanged |
| `[...Array.from(foo)]` | reported, fixed | unchanged |
| `BigUint64Array.from([...iterable])` | reported, fixed | unchanged |
| `[...new Uint8Array([1, 2, 3])]` (#7936) | passes | unchanged |

## Tests

19 `pass` vectors added under a `#25868` comment next to the existing
`#7936` pair:
the seven methods from the issue, a chained case, and all 11 typed array
constructors. The `fail` vectors are untouched, which is the regression
check that
plain arrays and `Array.from` still report.

## Known limits, both deliberate

**Variable receivers still report.** `[...view.slice(0, 12)]` where
`view` is a
`Uint8Array` needs type information. #24107 asked for that general case
and was
closed on the grounds that upstream's `isArray` is type-aware and this
rule is not
moving to tsgolint. This PR stays inside the syntactic subset, where the
receiver is
literally `new <TypedArray>(...)` or `<TypedArray>.from(...)`.

**A shadowed constructor is a false negative.** With `class Uint8Array`
in scope,
`[...new Uint8Array().slice(0)]` is a genuine useless spread and is no
longer
reported. This matches how `is_new_typed_array` and every other name
matcher in the
file already behave, so it introduces no new inconsistency. Happy to add
a
global-reference check if you'd rather have it here.

## Verification

```
cargo check -p oxc_linter                 clean
cargo test -p oxc_linter no_useless_spread  rules::unicorn::no_useless_spread::test ... ok
```

The snapshot is unchanged, so no existing `fail` case flipped.

Control, to show the tests have teeth: reverting `const_eval.rs` to its
previous
state while keeping the new vectors fails the test with 19 diagnostics,
one per new
vector.

## AI usage disclosure

Per the AI usage policy: this patch was drafted with Claude Code,
including the
`ValueHint::NewTypedArray` approach and the test vectors. Everything in
the
verification section was run locally against this branch rather than
asserted, and
the control run is there because a test that passes with and without the
fix would
prove nothing. Happy to take the change in a different direction if
you'd prefer the
narrower receiver guard described in #25868.

---------

Co-authored-by: Cameron <cameron.clark@hey.com>
2026-08-26 08:47:24 +00:00