Allow escaped value names such as `import { t\u0079pe as x } from "m"` and the equivalent named exports. Reject escapes only after resolving `type` as a type-only modifier.
Preserve the decoded identifier name in the ambiguous `type as as` form so its AST name remains `type`.
`class C { async x; }` was accepted in JavaScript and TypeScript, silently discarding `async` from the resulting field. Reject the modifier after parsing a class field, once fields have been distinguished from methods.
Async methods, fields named `async`, and newline-separated fields remain valid.
Return early for calls whose last argument is not `undefined`, avoiding unnecessary callee and `bind` checks. Collect trailing undefined spans with pushes followed by one reversal instead of repeated front insertions, preserving diagnostic and fix order.
Require a comma after a TypeScript `this` parameter when the parameter list continues. Previously, malformed syntax such as `function f(this: T x: T) {}` parsed without a diagnostic.
Pure refactor.
Add `bm_clear` function that clears a bit in a bitmap at specified index. This is the converse of `bm_set`, and single-bit version of `bm_clear_range`.
This operation is performed in various places across `classify`, `carve`, and `coalesce` stages. Replace the duplicated code with `bm_clear` calls. This makes the logic easier to read.
`bm_clear` is `#[inline(always)]` so this change makes zero difference to codegen. The changes in `carve_jsx` look more substantive, but compiling to ASM and diffing it before/after this PR shows 0 difference. The compiler is able to identify the repeated terms across the 4 calls - there's no need to perform that optimization manually.
Code to read the nth bit of a bitmap was duplicated in several places across pipeline code:
- `wordbit` in `carve`
- `bit_at` in `regex_div`
- Various places inline in `carve`, `classify`, and `coalesce`
Add a function `bm_get` for this purpose to `bitmap` module (which feels like its natural home) and replace all usages with calls to this function.
This reduces repetition, and makes the call sites easier to read.
`bm_get` is marked `#[inline(always)]`, so extracting it into a function should have no effect on perf.
Pure refactor. No code changes, just moving code around.
Re-order the functions in `bitmap` module, moving `bm_next0` up to the top with the other getters.
Add line breaks between all the functions.
Pure refactor. No code changes, just moving code around.
After #26443, main exported logic for `compress` stage is in `compress/mod.rs`.
`write_sentinels` is also exported from the module, so move it out of `common.rs` and into `mod.rs`, alongside `compress`. `common.rs` not only contains functions internal to the `compress` stage, shared between AVX2 and generic implementations.
Pure refactor. No code changes, just moving code around.
`compress` stage of pipeline involves several separate steps. Previously this compress-specific logic was in `lex_raw`, mixed with the logic for other stages.
This PR moves it into the `compress` module, so all that remains in `lex_raw` is a single call to `compress`.
The function that was previously called `compress` is renamed to `compress_blocks` to avoid duplicated names.
Pure refactor. No code changes, just moving code around.
Split `compress` pipeline stage into multiple files.
- `avx2.rs` / `generic.rs` - SIMD and generic impls.
- `common.rs` - Code shared between both impls.
- `mod.rs` - Minimal entry point, chooses which impl to load dependent on target.
Additionally, apply the same kinds of stylistic changes as #26390.
Pure refactor. No code changes, just moving code around.
Move all code for `coalesce` pipeline stage into a directory together.
`coalesce/mod.rs` contains same code as `coalesce.rs` did previously. `keyword.rs` moves into the same directory, since `kw_verify_batch` is only used in `coalesce` stage. `kw_flush` moves into `keyword.rs` as it's keyword-related.
Additionally, apply the same kinds of stylistic changes as #26390.
Pure refactor.
`carve` has 2 different implementations for JS and JSX. Move selecting which to use to within the `carve` module, to make `lex_raw` clearer to read.
`carve` function is marked `#[inline]` so this should make no difference whatsoever to codegen.
Pure refactor. No code changes, just moving code around.
Split `carve` pipeline stage into multiple files.
Unlike #26390, here there's little platform-specific code to split up. Aim is just to separate out code which is specific to JS / JSX, and split JSX code up into separate sub-systems.
Additionally, apply the same kinds of stylistic changes as #26390.
Pure refactor. No code changes, just moving code around.
Split `classify` pipeline stage into multiple files.
- `avx2.rs` / `generic.rs` - SIMD and generic impls.
- `common.rs` - Code shared between both impls.
- `mod.rs` - Minimal entry point, chooses which impl to load dependent on target.
Additionally, a few stylistic changes in Oxc "house style":
- Re-order code so it reads top-to-bottom - imports and consts first, then entry points, private fns/helpers lower down.
- Combine imports into a single `use` statements.
- Line breaks between functions.
The split of SIMD/generic into separate files is the main point. This is a precursor to switching over to runtime feature detection, instead of compile-time.
Allow inversion of binary operation when comparing `'u'` string with
`typeof
`!(typeof a < "u")` => `typeof a > "u"`
`!(typeof a > "u")` => `typeof a < "u"`
this is needed to support negation of short version of `typeof x ===
"undefined"` -> `typeof a > "u"` generated by
`substitute_typeof_undefined`
fixes#25294
related #26460
Keep the precedence and source-map availability checks in an inline wrapper, and move the remaining postfix mapping work into an `#[inline(never)]` helper. This keeps the call sites unchanged while separating the mapping work from the inline path.
Skip the scope-ancestor walk in `is_in_declare_global` when the file contains no `TSGlobalDeclaration` nodes. Files containing global declarations retain the existing scope checks, using `nodes().kind()` directly when inspecting ambient module scopes.
Check configured globals once per unresolved name instead of once per reference. Names with only type references skip the global lookup, while undefined value references retain their individual `typeof` and function-scope `arguments` checks.
Skip the rule when neither paths nor patterns are configured. For side-effect import detection, build a set of import statement spans once instead of scanning every import entry for each request, and return early when the file has no requested modules.
Check component parameter validity before scanning for hooks or JSX. Invalid parameter lists now short-circuit the body scan without changing component classification.
Skip exported symbols before collecting their operations and assigning liveness bitset indices. These symbols were already excluded from diagnostics, so tracking them added reference scans and dataflow work without producing reports. Local symbols referenced inside exported declarations and assignments continue to be analyzed independently.
Compare configured function paths directly through their split iterators instead of collecting a temporary vector for each candidate call. The shared matcher accepts iterators while preserving exact segment and length matching; its other caller, `no-array-method-this-argument`, is adapted to the new signature.
Check the terminal callee name's capitalization before constructing its full property path, so ordinary calls and constructors return early. Borrow terminal names directly from the AST to avoid copying identifiers and computed property names; full paths are still constructed when exception matching requires them.
Format non-negative integers below 1000 directly with `itoa`, avoiding Dragonbox formatting and the intermediate `InlineString` copy. Larger numbers and fractions retain the existing shortest-literal logic.
Use `HashMap::entry` to reuse the lookup when inserting a new source-map name, avoiding the second hash and table search from `get` followed by `insert`. Existing name IDs and insertion order are preserved.
Preserve parentheses around TypeScript instantiation expressions in postfix contexts. Previously, `(f<T>).x` and `(f<T>)[x]` were emitted as `f<T>.x` and `f<T>[x]`, producing invalid syntax or changing how the expression is parsed.
The printer now respects the surrounding precedence while retaining grouping for lower-precedence operands.
Class static blocks inherit the disabled `in` context of a surrounding `for` initializer, causing valid code such as `for (class { static { a in b; } };;);` to report a missing semicolon at `in`. Enable `Context::In` while parsing the static block, with the existing context helper restoring the surrounding flags afterward.
`packages/codegen` drops required parentheses around the right operand of a private-in expression when that operand is another relational expression. This changes which value the private-field check receives and can change observable behavior.
For example, this input throws a `TypeError`:
```js
class C {
#x;
test(a, b) {
return #x in (a instanceof b);
}
}
new C().test({}, Object);
```
`a instanceof b` evaluates to `true`, but a private-field check requires an object on its right-hand side.
The JavaScript printer previously emitted:
```js
return #x in a instanceof b;
```
Relational operators associate to the left, so that output is parsed as `(#x in a) instanceof b`. The private-field check on `{}` produces `false`, and `false instanceof Object` returns `false` instead of throwing.
The printer now preserves the original grouping:
```js
return #x in (a instanceof b);
```
`printPrivateInExpression` now prints its right operand with `PREC_COMPARE` instead of `PREC_EQUALS`. The expression printers wrap operands whose precedence is equal to or lower than the requested precedence, so the comparison threshold retains parentheses around `<`, `<=`, `>`, `>=`, `instanceof`, and nested private-in expressions. The now-unused `PREC_EQUALS` import is removed.
Equality and lower-precedence operands continue to retain their required grouping. Shift, arithmetic, and exponentiation operands can still omit unnecessary parentheses. The existing `CTX_FORBID_IN` handling remains in place.
This applies to both ordinary and source-map-enabled printer builds and brings the JavaScript implementation in line with the Rust fix in #26411. It addresses grouping of the private-in right operand, separately from the left-operand correction in #26403.
`packages/codegen` can turn valid JavaScript into unparseable output when a `yield` expression appears in a classic `for` loop initializer and its argument contains an `in` operator.
For example, this input is valid:
```js
function* g(o) {
for (yield (1 in o); false;);
}
```
The JavaScript printer previously dropped the required grouping:
```js
function* g(o) {
for (yield 1 in o; false;);
}
```
An unparenthesized `in` is not allowed at this position in a classic `for` initializer. The same problem affects `yield*`, nested yields, and assignments inside the yield argument.
The printer now preserves the parentheses:
```js
function* g(o) {
for (yield (1 in o); false;);
}
```
The `for` printer already marks its initializer with `CTX_FORBID_IN`, but `printYieldExpression` discarded that context and printed its argument with `CTX_NONE`. The yield dispatch now passes its incoming context to `printYieldExpression`, which forwards only `CTX_FORBID_IN` to the argument when the yield expression is unwrapped. The argument retains its existing `PREC_YIELD` precedence.
When precedence requires parentheses around the entire yield expression, those parentheses already permit `in` inside. The argument context is cleared in that case, avoiding redundant inner parentheses:
```js
// Input
function* g(o) {
for ((yield (1 in o)) + 1; false;);
}
// Output
function* g(o) {
for ((yield 1 in o) + 1; false;);
}
```
Both `yield` and `yield*` use this path. Outside a restricted initializer, ordinary yields continue to omit unnecessary grouping: `yield (1 in o)` prints as `yield 1 in o`.
The correction applies to both ordinary and source-map-enabled builds and brings the JavaScript printer in line with the Rust fix in #26413.
## Problem
Named tuple rest elements bypass the parser's existing checks for optional elements after an array rest and for multiple array rests. For example, both of these declarations currently parse successfully even though TypeScript rejects them:
```ts
type OptionalAfterRest = [...a: string[], b?: number];
type RestAfterRest = [...a: string[], ...b: number[]];
```
The equivalent unnamed forms already produce TS1266 and TS1265, respectively. Mixed named and unnamed array rests have the same gap when either rest is named.
## Cause and change
`parse_tuple_type` inspects `TSRestType.type_annotation` to decide whether an element is an array rest. For a named element, that annotation is a `TSNamedTupleMember`, and the actual type is stored in its `element_type`. Matching directly on the outer annotation therefore skips the array check and fails to track the rest element.
Unwrap the named member with `as_ts_type()` before applying the existing classification. Named and unnamed elements then share the same validation and existing diagnostics:
- An optional element after an array rest reports TS1266.
- A second array rest reports TS1265, including mixed named and unnamed forms.
The diagnostic spans continue to use the complete tuple elements, including their labels. The change borrows the underlying type without changing the AST representation or introducing allocations.
## Preserved behavior
A rest marker alone does not make a spread an unbounded array. Fixed-tuple and generic variadic spreads continue to be accepted, including:
```ts
type FixedBeforeOptional = [...a: [string], b?: number];
type RestBeforeFixed = [...a: string[], ...b: [number]];
type VariadicBeforeOptional<T extends unknown[]> = [...a: T, b?: number];
type RestBeforeVariadic<T extends unknown[]> = [...a: string[], ...b: T];
type MultipleVariadic<T extends unknown[], U extends unknown[]> = [...a: T, ...b: U];
```
This change preserves the existing type-reference classification; it does not add type resolution or change how shadowed `Array` references are handled.