## 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
```
Rejects initialized `let` and `const` declarations in `for...in` during parsing while preserving Annex B's non-strict `var` form.
Adds misc coverage for valid and invalid initializer forms.
Verified with `just ready` and parser conformance.
Closes#25149.
AI-assisted.
Quoted JSX attribute values do not use ECMAScript escape sequences. Skip strict-mode legacy escape validation for JSX attributes and cover the behavior in misc conformance.
AI-assisted by Codex.
## Summary
- parse ordinary class field initializers as `AssignmentExpression`
- reject unparenthesized comma expressions while preserving
parenthesized sequence expressions
- add paired misc conformance fixtures and update the generated
snapshots
## Root cause
Ordinary class field initializers used `parse_expr`, which accepts a
top-level comma and constructs a sequence expression. The ECMAScript
`Initializer` grammar requires an `AssignmentExpression`, so the
unparenthesized comma must remain for the class-element terminator check
to reject.
## Summary
- Align auto-accessor initializer parsing with class-field initializer grammar.
- Add regressions for `in` in a `for` initializer and disallowed inherited `await`/`yield` contexts.
## Root cause
The auto-accessor path only enabled `new.target`. It therefore inherited outer `~In`, `Await`, and `Yield` grammar contexts: `a in b` could not parse in a `for` initializer, while `await` and `yield` could incorrectly parse from enclosing async/generator functions. The fix applies the same `In | NewTarget` addition and `Yield | Await` removal already used for class fields, while retaining AssignmentExpression parsing.
## References
- [ECMAScript `FieldDefinition` grammar](https://tc39.es/ecma262/#prod-FieldDefinition)
- [ECMAScript `Initializer` grammar](https://tc39.es/ecma262/#prod-Initializer)
- [TC39 decorators proposal: class auto-accessors](https://github.com/tc39/proposal-decorators#introduction)
## Summary
Narrow `TSInterfaceHeritage` from a general JavaScript `Expression` to `TSTypeName`.
```rust
pub struct TSInterfaceHeritage<'a> {
pub type_name: TSTypeName<'a>,
pub type_arguments: Option<Box<'a, TSTypeParameterInstantiation<'a>>>,
}
```
## Breaking Change
The Rust AST field changes from:
```rust
expression: Expression<'a>
```
to:
```rust
type_name: TSTypeName<'a>
```
## Why?
The current AST can represent shapes such as:
```ts
interface A extends foo() {}
interface A extends A + B {}
interface A extends new Foo() {}
interface A extends true {}
```
Which is an overly wide type since all of the above variants are invalid.
This PR tightens up the AST, making these invalid variants irrepresentable.
## How to migrate?
This should be a trivial migration:
1. instead of accessing `expression` on `TSInterfaceHeritage`, now access `type_name`
2. change any pattern matching on the `type_name` field to use `TypeName` (this is a smaller subset so should allow deleting code!)
closes https://github.com/oxc-project/backlog/issues/215
Fixes#24804.
Recognize `!` as a type-start token so `?` after `satisfies` remains the conditional-expression operator instead of being consumed as a JSDoc nullable type.
Validated with `just ready`.
AI-assisted.
## Summary
- allow `eval` and `arguments` as direct bindings in ambient declarations
- continue reporting strict-mode errors for destructured ambient bindings
- add focused coverage for declared functions, classes, object patterns, and array patterns
## Why
The semantic checker previously identified allowed bindings by walking to a `TSDeclareFunction`. That missed other ambient declarations, including declared class constructors and methods, and produced diagnostics for TypeScript cases that require no runtime code generation.
The check now uses the existing ambient-context state and rejects only destructuring binding shapes.
## Summary
- Report operator-specific diagnostics when unary and `await` expressions are used as exponentiation left operands.
- Reject unparenthesized TypeScript type assertions in the same position while preserving explicitly parenthesized forms.
- Add regression fixtures and update the affected conformance snapshots.
Recognize identifiers nested within `declare` variable declarations and declared class properties as being in an ambient context.
This prevents valid TypeScript from incorrectly producing reserved-keyword diagnostics.
### Examples
Function types inside ambient variable declarations are now accepted:
```ts
declare let f: (package: number) => interface;
```
Type references inside declared class properties are also accepted:
```ts
class C {
declare field: package;
}
```
Previously, package and interface were incorrectly reported as reserved keywords.
## Summary
Keep transformer semantic data in sync when TypeScript-only syntax is removed.
This change:
- removes resolved and unresolved references belonging only to stripped TypeScript syntax
- removes bindings for erased type-only and unused imports
- preserves runtime bindings when a type import is merged with a value declaration
- promotes the surviving declaration’s symbol flags, span, and redeclaration metadata
- adds coverage for type imports merged with runtime declarations
- refreshes semantic and transformer conformance snapshots
## Motivation
We are preparing to change the AST shape, including adding and rearranging scopes.
Currently, transformer semantic snapshots contain thousands of lines of mismatches caused by stale bindings and references from TypeScript syntax that has already been removed from the AST. That creates a large amount of unrelated snapshot noise.
With that noise present, snapshot changes caused by the upcoming AST work would be difficult to review: a real scope or semantic regression could easily be hidden among mechanical churn.
This PR fixes the underlying semantic inconsistencies first, giving us a much cleaner baseline for reviewing future AST and scope changes. It is not intended to change emitted JavaScript.
## Summary
- Report TS2398 when a TypeScript constructor parameter property is named `constructor`.
- Add coverage for the upstream TypeScript fixture plus dedicated misc pass/fail cases for ordinary `constructor` parameters versus invalid parameter properties.
```
× TS(2398): 'constructor' cannot be used as a parameter property name.
╭─[misc/fail/oxc-ts-2398.ts:2:31]
1 │ class A {constructor(public constructor){}}
2 │ class B {constructor(readonly constructor){}}
· ───────────
╰────
```
Port of [microsoft/typescript-go#4192](https://github.com/microsoft/typescript-go/pull/4192), which fixes [microsoft/TypeScript#63527](https://github.com/microsoft/TypeScript/issues/63527).
## Problem
`as`/`satisfies` are supposed to be erasable without changing runtime semantics. But for an expression of the form `a ## b as T $$ c`, where `##` has *lower* precedence than `$$`, erasing the assertion silently changes the parse:
```ts
const x = 1 + 1 as number * 2;
```
This parses as `((1 + 1) as number) * 2` (= `4`), but textually erasing `as number` yields `1 + 1 * 2` (= `3`). TypeScript now rejects such constructs as a syntax error, forcing explicit parentheses.
## Change
In `parse_binary_expression_rest`, after parsing an `as`/`satisfies` type, stop parsing if the following operator binds tighter than the operator that produced the running left-hand operand. This leaves the higher-precedence operator dangling and surfaces as a parse error.
A chained `a as T as U` keeps referring back to the original operator's precedence (the tracked precedence is intentionally not updated while consuming `as`/`satisfies`), so `1 + 1 as any as number * 2` is rejected too.
## Behavior
| Expression | Result |
| --- | --- |
| `1 as number * 2` | ok |
| `1 * 1 as number + 2` | ok (`+` does not bind tighter than `*`) |
| `1 + 1 as number * 2` | **error** |
| `1 + 1 as any as number * 2` | **error** |
| `1 >> 1 as number + 2` | **error** |
| `(1 + 1 as number) * 2` | ok |
`satisfies` behaves identically to `as`.
## Tests
Added `misc` coverage fixtures mirroring the upstream test matrix: `pass/ts-erasable-as-satisfies.ts` for the erasable cases and `fail/ts-unerasable-{as,as-chained,satisfies}.ts` for the rejected ones. Full conformance (test262 / babel / typescript) shows zero regressions.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
In unambiguous (`.js` auto-detect) sources, `export var x = await + 1;` reported a spurious `Duplicated export 'x'` error. The parser first parsed the statement with `await` as an identifier, then re-parsed it under `Context::Await` to patch the AST — but the second pass re-invoked `visit_export_named_declaration`, recording the binding `x` a second time in the module record.
`export` is unambiguously module syntax per ECMA-262 §16.2.3 (`ExportDeclaration` is only a `ModuleItem`, never a Script production). So commit to the Module goal — enable `Context::Await` — as soon as the next top-level token is `Kind::Export`. The statement then parses correctly on the first attempt; no reparse and no duplicate record.
`Kind::Import` is intentionally **not** eager-switched. TypeScript's `import name = ns.path` is a script-compatible namespace alias (see `topLevelAwait.2.ts`), so treating `import` as a module starter would break that case.
The only TS snapshot churn is +16 lines of additional error messages for already-failing tests (`topLevelAwaitErrors.5.ts`, `topLevelAwaitErrors.6.ts` — `export ... await`). Summary counts unchanged.
Closes#22520Fixes#22158
Fixes parser recovery for class computed property names whose expression starts with an array literal, such as `class C { [[]]() {} }`.
The TypeScript index-signature lookahead previously treated a nested `[` after the opening computed-name bracket as an unambiguous index signature. That caused valid class computed keys containing array literals to be parsed through the wrong branch and rejected.
This changes the lookahead so only `...` remains an early unambiguous index-signature signal, allowing nested arrays and other assignment expressions to parse as computed property names.
fixes: #22157
## Summary
- Add `is_unambiguous_await()` to detect when `await x` is clearly an await expression
- Unambiguous top-level await upgrades file to ESM (like Babel's `sawUnambiguousESM`)
- Add `function_depth` tracking so await inside non-async functions errors even in ESM
- Treat `await of` and `await using` as ambiguous (for-await-of and await using declarations)
- Better error messages: "await is only allowed within async functions" instead of confusing "Expected semicolon" errors
Closes#15541Closes#18457🤖 Generated with [Claude Code](https://claude.ai/code)
## Summary
- In idempotency tests, the second parse now uses the source type derived from `program.source_type` after the first parse, not the original input source type
- This ensures consistent parsing when the source type is resolved (e.g., from unambiguous to module/script)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
> This PR fixes TypeScript parser errors 1266 and 1257 by properly handling the `optional` field of `TSNamedTupleMember` when validating tuple element ordering constraints.
Introduced in #18146 and #18145
## Summary
- Fix parsing of `await (...)` and other cases where `await` followed by
certain tokens was parsed as an identifier instead of an await
expression in unambiguous mode
- Commit 92e27b4 only handled `await /regex/` but missed other cases
## Changes
- Add `encountered_await_identifier` flag to `ParserState` to track when
await is parsed as identifier
- Set flag in `parse_identifier_reference` when parsing "await" as
identifier in non-await context
- Modify statement parsing to track checkpoints only for statements that
actually used await as identifier
- Once ESM detected, enable await context for remaining statements
## Test plan
- Added test cases in `tasks/coverage/misc/pass/`:
- `unambiguous-await-call.js` - Tests `await (async function () { })();`
- `unambiguous-await-in-declaration.js` - Tests `const x = await (async
function () { })();`
- All parser tests pass
- All conformance tests pass
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
## Summary
- Implements TypeScript-compatible await expression reparsing for unambiguous mode
- When `sourceType` is `unambiguous`, `await / 0 /u; export {}` now correctly parses as `await /0/u` (await expression with regex)
- Follows TypeScript's two-pass approach: initially parse `await` as identifier, then reparse with await context if ESM is detected
## Test plan
- Added `tasks/coverage/misc/pass/unambiguous-await-regex.js` test case
- Moved `tasks/coverage/misc/fail/babel-16776-s.js` to pass (now parses as division in script mode)
- All parser tests pass
- Conformance tests show improvements in parser_babel and semantic_babel
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
- Implements speculative/unambiguous parsing for `.js`, `.jsx`, `.ts`, and `.tsx` files
- Instead of assuming module or script upfront, parses with `ModuleKind::Unambiguous` and upgrades to module mode when ESM syntax is detected
- ESM indicators: `import`, `export`, `import.meta` (NOT top-level await alone)
- Defers top-level await errors until module type is resolved
- Vue loader upgrades unambiguous scripts to module mode
- Updates linter tests to use explicit ESM extensions (`.mjs`/`.mts`) where needed
## Test plan
- [x] All parser tests pass
- [x] All linter tests pass
- [x] All semantic tests pass
- [x] Coverage conformance tests updated
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
- Add check to error on `using` declarations at the top level of scripts
- `using` declarations require block scope semantics and are not allowed
at the top level of scripts
`using` declarations are allowed:
- At the top level of ES modules
- At the top level of CommonJS modules (files are wrapped in a function)
- Inside any block scope in scripts
But NOT at the top level of scripts.
Closes#11862
## Test plan
- [x] Added test case
`tasks/coverage/misc/fail/script-top-level-using.js` for invalid usage
- [x] Added test case
`tasks/coverage/misc/pass/script-using-in-block.js` for valid usage in
block
- [x] All existing tests pass
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
## Summary
- Add `ModuleKind::CommonJS` variant to support CommonJS module type in the parser
- Enable top-level `return` statements (CommonJS files are wrapped in a function)
- Enable top-level `new.target` (allowed in CommonJS function wrapper)
- Add proper errors for `import`/`export` statements in CommonJS
- Add proper errors for `import.meta` in CommonJS
The CommonJS source type can be set via:
- `SourceType::with_commonjs(true)` method
- Babel's `sourceType: "commonjs"` option
Closes#16200
## Test plan
- [x] Added test cases in `tasks/coverage/misc/pass/` for valid CommonJS features
- [x] Added test cases in `tasks/coverage/misc/fail/` for invalid CommonJS usage
- [x] Enabled Babel conformance tests for `sourceType: "commonjs"`
- [x] All existing tests pass
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Improved error message for `yield` as identifier usage.
**Before**
```
× Cannot use `yield` as an identifier in a generator context
╭─[test262/test/language/expressions/generators/yield-weak-binding.js:17:33]
16 │
17 │ var g = function*() { yield 3 + yield 4; };
· ─────
╰────
```
**After**
```
× Cannot use `yield` as an identifier in a generator context
╭─[test262/test/language/expressions/generators/yield-weak-binding.js:17:33]
16 │
17 │ var g = function*() { yield 3 + yield 4; };
· ─────
╰────
help: Wrap this in parentheses if you want to use a `yield` expression here
```
Fixes#16839.
Make parser parse `let?.x` successfully.
There's a failure in codegen idempotency tests, but that's an unrelated
and pre-existing bug, so am leaving that to another PR.
Co-authored-by: overlookmotel <theoverlookmotel@gmail.com>
closes#13284
Either TypeScript implemented the spec incorrectly or made it more
strict.
```js
class C {
foo() {
return {
bar() {
super.bar(); // syntax error in ts but not in js
},
};
}
}
```
fixes#10503
```ts
using
foo = bar()
await using
foo = bar()
```
should be parsed as
```ts
using;
foo = bar()
await using;
foo = bar()
```
not
```ts
using foo = bar()
await using foo = bar()
```