Commit Graph

1582 Commits

Author SHA1 Message Date
camc314 3048594401 fix(parser): use correct diagnostic for await using in bare switch case (#24798)
This improve the error diagnostic for await using in bar switch case clauses, as well as aligning more closely with  the behaviour for using/await using in ambient contexts:

https://github.com/oxc-project/oxc/blob/981a9522f5fb658943e89501b35543ff3283eea5/crates/oxc_parser/src/js/declaration.rs#L197-L204
2026-07-22 09:04:49 +00:00
Boshen baf022d74d refactor(ast)!: remove old AstBuilder methods (#24563)
Closes the migration tracked in #23043.

The new builder API (methods on the AST types themselves) has been in place for a while, all Oxc crates are migrated, and every crate which uses `AstBuilder` already enables `disable_old_builder` in its tests. The module docs said "after a few weeks, we will remove `AstBuilder`'s own methods entirely" — this does that.

## What's removed

- `crates/oxc_ast/src/generated/ast_builder.rs` and `builder/methods.rs` — `AstBuilder`'s own node and primitive constructors.
- `AstBuilderGenerator`, which produced the former.
- The `disable_old_builder` Cargo feature, plus the dev-dependency hacks it required across 33 manifests. Eight crates depended on `oxc_ast` *purely* to turn the feature on; those deps and their `cargo-shear` ignore entries are gone too.

## One thing worth reviewing

`AstBuilderGenerator` owned the `#[builder(default)]` / `#[builder(skip)]` attr registration that `BuilderMethodsGenerator` only *reads* — its doc comment said as much. Deleting it naively would have silently dropped `skip`/`default` handling for the 12 AST types using those attrs, so `attrs()` and `parse_attr()` move to `BuilderMethodsGenerator`.

The evidence this was faithful: after regenerating, `builder_methods.rs` and every other generated file are **byte-identical**. The only generated change in the diff is the deletion.

## Breaking changes

- `AstBuilder`'s own methods are gone. Use the AST type methods: `Statement::new_expression_statement(span, expr, &builder)` instead of `builder.statement_expression(span, expr)`.
- `AstBuilder` is no longer `Copy`/`Clone`, and its `allocator` field is private — use the `allocator` method from `GetAllocator`.
- `AstBuilder` and `NONE` are no longer re-exported from the crate root; import them from `oxc_ast::builder`. (The `disable_old_builder` feature already gated these off, so nothing in-tree used the root path.)
- The `disable_old_builder` feature no longer exists — remove it from any manifest that sets it.

A migration note covering all of the above is in `crates/oxc_ast/src/builder/mod.rs`.

---

Implemented with AI assistance (Claude Code); design, review, and verification driven by the author per the repo AI-usage policy.
2026-07-21 15:22:46 +00:00
camc314 47ddedf011 fix(semantic): allow arguments in ambient declarations (#24758)
## 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.
2026-07-21 12:43:21 +00:00
camc314 ddacf617f1 feat(semantic): add context notes for strict assignments (#24728)
## Summary

Adds context notes to `Cannot assign to '{x0}' in strict mode` diagnostics, explaining whether strict mode comes from an explicit directive, class body, or module.
2026-07-20 17:17:30 +00:00
camc314 76ec104498 fix(semantic): resolve import-equals namespaces (#22696)
Fixes `import =` semantic reference resolution so internal module references are resolved as namespace lookups instead of ordinary value reads.

TypeScript treats the RHS of an internal `import =` specially. In the checker, `getTargetOfImportEqualsDeclaration` delegates internal module references to `getSymbolOfPartOfRightHandSideOfImportEquals`, which resolves bare RHS names and intermediate qualified names with `SymbolFlags.Namespace` rather than value meaning:

- `getTargetOfImportEqualsDeclaration`: https://github.com/microsoft/TypeScript/blob/f350b52331494b68c90ab02e2b6d0828d2a22a74/src/compiler/checker.ts#L3708-L3733
- `getSymbolOfPartOfRightHandSideOfImportEquals`: https://github.com/microsoft/TypeScript/blob/f350b52331494b68c90ab02e2b6d0828d2a22a74/src/compiler/checker.ts#L4480-L4499
- `getSymbolOfNameOrPropertyAccessExpression` also routes names on the RHS of import/export assignments through that same helper: https://github.com/microsoft/TypeScript/blob/f350b52331494b68c90ab02e2b6d0828d2a22a74/src/compiler/checker.ts#L50014-L50019

Before this change, Oxc could count plain values as references from `import =`:

```ts
const x = 1;
import foo = x;
```

Before:

```text
x references: 1
```

After:

```text
x references: 0
```

That matches TypeScript’s behavior because `x` is only a value symbol, not a namespace-capable symbol.

The same applies to qualified names:

```ts
const x = { y: 1 };
import foo = x.y;
```

Before:

```text
x references: 1
```

After:

```text
x references: 0
```

But namespace-capable declarations still resolve:

```ts
namespace x {}
import foo = x;
```

After:

```text
x references: 1
```

and:

```ts
namespace x {
  export namespace y {}
}

import foo = x.y;
```

After:

```text
x references: 1
```

This updates the semantic snapshots to reflect the corrected reference/declaration matching.
2026-07-20 13:10:54 +00:00
camc314 cc3d17f063 feat(semantic): add context notes for reserved keyword diagnostic (#24715)
## Summary

Reserved-keyword diagnostics now explain the language context that makes an identifier invalid, rather than only reporting that the keyword is reserved.

## Details

- Add context-aware notes for strict mode, classes, and modules.
- Add a dedicated note for `await` in module code.
- Update parser-conformance snapshots for the expanded diagnostics.

Before:

```text
× The keyword 'package' is reserved
```

After, for strict-mode code:

```text
× The keyword 'package' is reserved
note: This identifier is reserved in strict mode code
```

After, for class code:

```js
class Example {
  method() {
    const static = 1;
  }
}
```

```text
× The keyword 'static' is reserved
note: Classes are always strict mode code
```

After, for module code:

```js
export const await = 1;
```

```text
× The keyword 'await' is reserved
note: The identifier `await` is reserved in module code
2026-07-20 10:59:00 +00:00
Dunqing 64c224117c fix(minifier): align class heritage removal with assumptions (#24533)
#24349 made unused-class removal conservatively keep every class whose heritage resolves to a class, lexical, or `var` binding. That preserves class-evaluation errors which the minifier assumptions explicitly allow optimizations to ignore, and it leaves `(class extends Base {});` residue in Rolldown chunks after tree-shaking ([rolldown#10274](https://github.com/rolldown/rolldown/issues/10274)).

The minifier already documents both `No TDZ Violation` and `No side effects from extending a class`, and `oxc_ecmascript` explicitly ignores invalid-superclass errors so removable derived classes are not broadly deoptimized. Treat resolved identifier heritage like other pure reads while retaining the pre-existing literal-arrow exception, including its paren/sequence unwrap. Effects from evaluating the heritage expression, decorators, and effectful class elements remain observable.

The runtime harness already has minifier-only exclusions for unsupported inputs. Six Test262 fixtures covered by these assumptions are skipped only before the minifier variant, with the reason documented beside the list; codegen and transformer still execute, and `runtime.snap` remains unchanged.

## Example

Input:

```js
export var Base = class {};
export var Keep = class extends Base {};
var REMOVE = class extends Base {};
```

Before:

```js
var Base = class {}, Keep = class extends Base {};
(class extends Base {});
export { Base, Keep };
```

After:

```js
var Base = class {}, Keep = class extends Base {};
export { Base, Keep };
```

Verified with `cargo test -p oxc_minifier`, `cargo coverage runtime`, Clippy with warnings denied for `oxc_minifier` and `oxc_coverage`, `just minsize`, `just allocs`, formatting, and `just ready`. Minsize and `runtime.snap` are unchanged; the allocation snapshot records fewer allocations for `kitchen-sink.tsx`.

Implemented with AI assistance (Claude Code and OpenAI Codex). The contributor remains responsible for reviewing, understanding, and submitting the changes under the repository AI usage policy.
2026-07-20 09:48:52 +00:00
camc314 48b59f450d fix(parser): span ambient generator diagnostics (#24711)
## Summary

Make TS1221 underline the generator declaration consistently from the `*` token.

## Why

The previous diagnostic used the generic function span, but that span has different start points depending on how the function is parsed:

- A class method enters function parsing after its name, so `declare class C { *generator(): any; }` highlighted only `(): any;` (starting at column 15), omitting both the generator marker and its name.
- A function declaration starts its span at the `function` keyword, so `declare namespace M { function *generator(): any; }` highlighted the whole declaration (starting at column 5), including text that is not the invalid generator construct.

For example, the prior output treated these equivalent generator markers differently:

```ts
declare class C {
    *generator(): any;
//            ^^^^^^^^
}

declare namespace M {
    function *generator(): any;
//  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
```

The parser now carries the `*` token location as `Option<u32>` while parsing a function. TS1221 uses that location through the declaration end, so both cases consistently highlight the relevant generator declaration:

```ts
*generator(): any;
^^^^^^^^^^^^^^^^^^
```

The AST continues to store `generator` as a boolean; the location exists only while parsing diagnostics.
2026-07-20 09:44:55 +00:00
sapphi-red 4c71560a72 feat(parser): more friendly error for spread element in dynamic imports (#24705)
This PR makes parse error message for spread element in dynamic imports more friendly.

**Before**
```
  × Unexpected token
   ╭─[babel/packages/babel-parser/test/fixtures/es2020/dynamic-import/invalid-arguments-spread/input.js:1:8]
 1 │ import(...[1])
   ·        ───
   ╰────
```
**After**
```
  × TS(1325): Argument of dynamic import cannot be a spread element.
   ╭─[babel/packages/babel-parser/test/fixtures/es2020/dynamic-import/invalid-arguments-spread/input.js:1:8]
 1 │ import(...[1])
   ·        ───
   ╰────
```
2026-07-20 08:23:46 +00:00
camc314 b14d52e647 refactor(parser): move require after optional param check to parser (#24600)
## Summary
- report TS1016 while parsing formal parameter lists
- preserve initialized-parameter and rest-parameter behavior
- remove the equivalent semantic check and diagnostic
- update parser and semantic coverage snapshots

Follows #24596, which has now merged.
2026-07-16 15:50:50 +00:00
camc314 7cd106daab refactor(parser): move abstract constructor check to the parser (#24595)
## Summary
- report TS1242 for abstract constructors in the parser
- remove the equivalent semantic diagnostic
- update TypeScript parser coverage snapshots

## Why?

This check needs to be moved to the parser, as the data is not retained after we change the Constructor ast type.
2026-07-16 14:35:42 +00:00
camc314 129b759131 feat(parser): improve diagnostics for unparenthesized LHS on exponential expr (#24569)
## 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.
2026-07-15 18:38:30 +00:00
camc314 7b4baff16c fix(parser): reject new import member access (#23459)
Reject `new import(...).prop`, `new import.source(...).prop`, and `new import.defer(...).prop` by treating member access on an unparenthesized import expression as invalid after `new`.

Fixes #23458
2026-07-15 10:38:34 +00:00
Boshen cef9143aed refactor(transformer,minifier,react_compiler): switch JS-only visitors from Visit to VisitJs (#24532)
Migrate the transform-pipeline `Visit` implementors to `VisitJs` (#24499): `oxc_transformer` (3), `oxc_minifier` (4), `oxc_react_compiler` (1), plus the parser regex example and the coverage driver. Part of #24317; linter half in #24530. Behavior is unchanged.

Together with #24530: `oxlint` −129.4 KiB (−0.94%) stripped, `oxc_transform` napi −16.2 KiB (−0.46%).

## Why each visitor can switch

A visitor is safe on `VisitJs` when its hooks cannot observe anything inside the pruned type grammar — either the hooked node kinds are value-space-only, or the AST it walks cannot contain type nodes at that pipeline stage.

| Visitor | File | Why equivalent |
|---|---|---|
| `PrivateInExpressionDetector` | `crates/oxc_transformer/src/decorator/legacy/mod.rs` | Hooks `visit_private_in_expression` (+`visit_decorators`); `#x in y` is runtime-only and cannot occur in type grammar, even inside decorator expressions carrying casts. |
| `BindingMover` | `crates/oxc_transformer/src/es2017/async_to_generator.rs` | Its formal-parameter overrides visit only pattern + initializer (`BindingPattern` carries no type field — annotations are sibling fields it never touches); runs in the exit phase after TS strip. |
| `UsedInJSXBindingsCollector` | `crates/oxc_transformer/src/jsx/refresh.rs` | Runs on un-stripped TSX, but its hooks (JSX-shaped calls, `visit_jsx_opening_element`, declarations/imports) cannot fire inside type grammar; its hand-written `visit_ts_type_annotation` skip-stub is deleted — `VisitJs` prunes that natively. |
| `Finder` | `crates/oxc_react_compiler/src/react_compiler/entrypoint/program.rs` | Matches functions by `scope_id`; real JS function scopes never live in pure type grammar, and `VisitJs` still walks the places one could hide (enum initializers, namespace bodies, cast inner expressions). |
| `KeepVar` | `crates/oxc_minifier/src/keep_var.rs` | Hooks `visit_statement`/`visit_variable_declaration`; statements and `var` declarations don't exist in type space, and namespace/enum bodies (which can contain them) are still walked by `VisitJs`. |
| `DirectEvalFlagCheck` | `crates/oxc_minifier/src/peephole/mod.rs` | Debug-only; hooks `visit_call_expression` only — call expressions cannot occur in valid type grammar. |
| `LiveDirectEvalCollector` | `crates/oxc_minifier/src/peephole/mod.rs` | Same single call-expression hook; type-space-immune regardless of input. |
| `TestVisitor` | `crates/oxc_minifier/tests/ecmascript/prop_name.rs` | Test helper parsing `SourceType::default()` (plain JS); single non-recursing `visit_object_expression` hook. |
| `RegularExpressionVisitor` | `crates/oxc_parser/examples/regular_expression.rs` | Finds `RegExpLiteral` / `new RegExp(...)`; neither node kind can occur in type grammar. |
| `CheckASTNodes` | `tasks/coverage/src/driver.rs` | Its only active override is `visit_reg_exp_literal` (regex print idempotency); `RegExpLiteral` cannot occur in type space. (The commented-out `visit_span` full-AST check would need `Visit` if ever revived.) |

Left on `Visit`: the minifier's incremental-scoping bookkeeping (`DropDiff`, `OverPruneCheck`, `LiveRefCollector`) — dropping `let x: Foo = …` must unmark the type-space `Foo` reference, which the `peephole::remove_unused_declaration` tests verify (they fail under `VisitJs`; confirmed and reverted during this work). `ChildScopeCollector` also stays: TS type nodes (mapped/conditional/function types) carry real `scope_id`s it must collect.

---

🤖 This PR was written with the assistance of Claude Code (Claude Fable 5).
2026-07-15 08:08:18 +00:00
Dunqing 4279ecaa7c chore(coverage): update stale test262 runtime snapshot (#24528)
#24463 moved the test262 pin from `de8e621c` to `d1d583db` but did not regenerate `tasks/coverage/snapshots/runtime.snap`, which still records the old sha. The runtime suite doesn't run in repo CI, so nothing caught it; monitor-oxc's Test262 job has been aborting on the snapshot sha guard ("Repository … is outdated for runtime.snap. Please run `just submodules`") on every run since 2026-07-13.

Two changes:

1. Regenerated the snapshot with `UPDATE_SNAPSHOT=1 cargo coverage runtime` against the pinned checkout: 17306/18277 (94.69%) passing, matching what monitor-oxc measures on main. The list changes are upstream test262 churn — two new `eval-code` global-function-init failures, and the async-arrow `forbidden-ext` block that no longer exists upstream.

2. Fixed the root cause of the staleness: the `update_submodules` workflow runs `just coverage`, whose default task skips the runtime suite, so `runtime.snap` was never regenerated on automated pin bumps. The workflow now runs `cargo coverage runtime` explicitly (it already sets up Node).

This PR was assisted by Claude.
2026-07-15 01:43:09 +00:00
camc314 c517aa08a8 fix(parser): reject invalid accessor assertions (#24504)
## Summary

- Align auto-accessor definite assignment assertions with TypeScript.
- Report TS1263 when an accessor has both `!` and an initializer.
- Report TS1264 when an accessor has `!` but no type annotation.
- Report TS1255 for typed definite assertions in static, abstract, and ambient contexts.
- Highlight only the `!` token, matching TypeScript.

fixes #24503.

## TypeScript behavior

Given:

```ts
class A {
    accessor missingType!;
    // ^: TS1264: Declarations with definite assignment assertions must also have type annotations.
    accessor initialized! = 1;
    // ^: TS1263: Declarations with initializers cannot also have definite assignment assertions.
    accessor typed!: number;
    // ^: valid
    static accessor staticTyped!: number;
    // ^: TS1255: A definite assignment assertion '!' is not permitted in this context.
}
```

TypeScript treats auto-accessors as property declarations and applies the following grammar check:

https://github.com/microsoft/TypeScript/blob/637d5746b70257028fb95aad32ddec6b26ab0a14/src/compiler/checker.ts#L53443-L53452

This establishes the diagnostic precedence:

1. An initializer produces TS1263.
2. Otherwise, a missing type annotation produces TS1264.
3. Otherwise, an invalid context produces TS1255.
2026-07-14 10:16:51 +00:00
oxc-guard[bot] 17cb5c13c5 chore(submodules): update submodule SHAs to latest commits (#24463)
Updates submodule dependencies to their latest commits.

## Changes

- test262: `de8e621` → `d1d583d`
- babel: `1fb0b77` → `c86e9e4`
- TypeScript: `7964e22` → `637d574`
- estree-conformance: `6514ad7` → `e8fd120`


This PR is automatically generated by the [update_submodules
workflow](https://github.com/oxc-project/oxc/blob/main/.github/workflows/update_submodules.yml).

Co-authored-by: oxc-guard[bot] <276638029+oxc-guard[bot]@users.noreply.github.com>
2026-07-13 14:24:36 +01:00
Dunqing 7d3336365d fix(minifier): preserve guaranteed throws from class heritage evaluation (#24349)
Evaluating a class declaration can throw before any of its members matter. `class C extends C {}` reads its own name while it is still in the TDZ and always throws a ReferenceError. A heritage that is a `var`, or a lexical binding declared later, can be undefined or uninitialized at evaluation time and throws a TypeError. The minifier only checked for a literal arrow function as heritage, so removing an unused class could silently delete one of these guaranteed throws.

The removal check now unwraps parens and sequence wrappers before looking at the heritage, and keeps any class whose heritage identifier resolves to a class, `let`/`const`, or `var` binding. Declaration order cannot be proven in the middle of minification (transforms copy and move spans), so the rule is conservative on purpose. Function declarations, imports, and globals are initialized before any class can evaluate, so classes extending them can still be removed.

## Example

```js
var f = () => {};
class C extends f {}
```

Running this throws `TypeError: Class extends value ... is not a constructor`.

Before, the unused class was removed and the whole program minified to nothing, so the TypeError was gone. After, the output is unchanged and the throw is preserved:

```js
var f = () => {};
class C extends f {}
```

This fixes six test262 runtime failures that exist on main today (17279 -> 17285 positive passes): `in-extends-expression-grouped`, `in-extends-expression-assigned`, `superclass-arrow-function`, `prototype-getter`, `prototype-setter`, and `constructable-but-no-prototype`. The runtime suite executes the minified tests in node; the results were verified through monitor-oxc. Minified sizes are unchanged on every fixture.

Implemented with AI assistance (Claude Code); design, review, and verification driven by the author per the repo AI-usage policy.
2026-07-11 14:43:07 +00:00
camc314 058a62f8a3 fix(semantic): track ambient contexts in SemanticBuilder (#24327)
## Summary

- track TypeScript ambient contexts using a nesting depth in `SemanticBuilder`
- enter ambient context for declaration files and `declare` declarations, including declarations without their own scope
- replace namespace-based and ancestry-based ambient detection
- use the ambient context for reserved keywords, global augmentations, class heritage, computed class members, and bodyless accessors
- extend conformance coverage for ambient variables, properties, functions, and classes

This approach was discussed with overlookmotel yesterday after some brainstorming!
2026-07-11 11:00:02 +00:00
camc314 721eb0ba2b fix(transformer/decorator): scope accessor class binding (#24330) 2026-07-09 13:53:23 +00:00
camc314 1ebdce31b6 fix(semantic): allow reserved keywords in ambient declaration types (#24325)
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.
2026-07-09 10:40:33 +00:00
Shanon Jackson 6ab439a902 feat(lexer): add oxc_lexer, a unfused SIMD lexer for JS/TS/TSX (#24172)
Adds the x86_64 version of my Research `SIMD For Context Sensitive
Languages`.
(CPB = Cycles per byte)
- Adds new create crates/oxc_lexer; Which eventually lead into an
unfused parser design inside oxc_parser
- Fully test262 compliant JS standalone Lexer; SIMD used has
counterparts on every platform.
- Performs at 2.5CPB on checker.js on my ZEN 3 CPU; or around 1.5-1.75
gbs (3.8GHz).
- Across aarch64, + other platforms performance will hold which I've
seen in my POCs but those targets will come later.
- Supports JSX/TS options, Which don't have much impact on overall perf
results.

------

The expected results for seeing this work through [including on parser
side on oxc_parser]
1. P95 improvements of 80-100% over current `oxc_parser`; 12-18% of this
will come from the unfused contract where JS grammar specifically loves
being able to see 'ahead' into `kinds` in various places. The rest comes
from the perf improvements to the lexer itself and some wins that will
come inside the parser from work now done in the lexer.
2026-07-08 18:07:33 +01:00
camc314 af4922be6d fix(transformer): clear lowered namespace redeclarations (#24300) 2026-07-08 13:56:43 +00:00
camc314 ffd2765ffc fix(semantic): mark declared computed MethodDefinitions as type references (#24296)
## Summary

- mark computed method keys in ambient and abstract classes as type references
- preserve runtime read flags for concrete computed methods
- bound declare-class ancestry checks to the containing class
- add semantic snapshot coverage and update the TypeScript conformance snapshot

Follows the work done in 588d9971ac,  9b95632179
2026-07-08 11:42:29 +00:00
camc314 6371fed556 fix(transformer): remove stale enum member bindings (#24272)
## Summary

Remove TypeScript enum-member bindings after transformation.

Enum members are represented as bindings during semantic analysis so the transformer can resolve member values, fold references, and handle merged enums. Once TypeScript transformation finishes, those bindings no longer correspond to emitted JavaScript declarations.

Include `EnumMember` in the existing final TypeScript binding cleanup instead of removing bindings during enum lowering, where later references may still need them.

This fixes `discriminatedUnionTypes4.ts` and removes the same stale binding mismatch from other enum cases.
2026-07-07 18:29:57 +00:00
Dunqing f05dfabe5c fix(transformer): correct symbol flags for lowered namespaces (#24271)
Closes #24224 — the first commit is @camc314's fix from there.

Lowered namespaces kept their `ValueModule`/`NameSpaceModule` symbol flags, so the flags no longer matched the emitted JavaScript:

- Namespaces lowered to a declaration become `let` → `BlockScopedVariable`.
- Namespaces lowered to an assignment only lose their module bits.

This removes over 2,000 stale symbol-flag mismatches from the snapshots.

Unlike #24224 there is no pending state: the type-only check for merged namespaces now reads per-declaration flags from the redeclaration list instead of the symbol's live flags, so each declaration can update the flags right when it is lowered.
2026-07-07 16:48:19 +00:00
Dunqing 84eeb5570b fix(transformer): correct symbol flags for lowered enums (#24269)
Closes #24226 — the first commit is @camc314's fix from there.

Lowered enums kept their `RegularEnum`/`ConstEnum` symbol flags, so the flags no longer matched the emitted JavaScript:

- Top-level enums become `var` → `FunctionScopedVariable`.
- Exported and nested enums become `let` → `BlockScopedVariable`.
- Merged enums lowered to an assignment only lose their enum bits.

This removes over 1,000 stale symbol-flag mismatches from the snapshots.

Unlike #24226 there is no pending state: enum member inlining now identifies enums through `EnumData` (#24268) instead of `SymbolFlags`, so the flags can be updated right when the enum is lowered.
2026-07-07 16:48:19 +00:00
leaysgur 4f86e8c6e0 fix(formatter): print ; before trailing comments (#24244)
Fixes #23110, also follows Prettier 3.9.

- Move same-line trailing comments after the statement semicolon
- Keep dangling comments after trailing array holes inside the brackets
- Guard suppression comments and ASI sources
2026-07-07 08:53:08 +00:00
camc314 c3057dac59 fix(transformer): preserve generated class binding spans (#24220)
## Summary

- preserve outer and inner class binding spans during legacy decorator lowering
- add a span-aware traversal binding generator for transformed source-backed bindings
- update semantic coverage snapshots, removing stale `Span { start: 0, end: 0 }` mismatches
2026-07-07 06:53:38 +00:00
camc314 8260096253 fix(transformer): correct span for lowered namespace symbol (#24222)
## Summary

- preserve source spans when TypeScript namespace declarations are lowered to variable bindings
- update semantic coverage snapshots, removing stale `Span { start: 0, end: 0 }` mismatches
2026-07-07 02:27:08 +00:00
camc314 42d00d383e fix(semantic): mark declared class heritage as type references (#24237)
## Summary

- resolve declared class heritage expressions through ValueAsType so their final references are Type
- allow type-only namespace imports in declared heritage while preserving Read for runtime class heritage
- add regression coverage for type-only namespace imports, value namespace imports, local bases, and a runtime control
- update semantic conformance snapshots, yielding two additional TypeScript passes
2026-07-06 21:58:56 +00:00
camc314 588d9971ac fix(semantic): mark TS PropertyDefinitions computed fields as type references (#24233)
## Summary

- resolve computed declare class-field keys through ValueAsType so their final references are Type
- allow declared keys to resolve type-only import bindings while preserving Read for ordinary runtime class fields
- add a red/green semantic snapshot and update conformance snapshots, yielding one additional TypeScript semantic pass and one additional transform-conformance pass
2026-07-06 16:28:50 +00:00
camc314 9b95632179 fix(semantic): mark computed method keys in TSMethodSignatures as type references (#24232)
## Summary

- resolve computed TypeScript method, getter, and setter keys through ValueAsType so their final references are Type
- allow those keys to resolve value bindings and type-only import bindings consistently with computed property signatures and type queries
- add regression coverage and update semantic conformance snapshots, yielding one additional Babel pass and six additional TypeScript passes

Handled for TSPropertySignature via https://github.com/oxc-project/oxc/commit/d8b9909bd8df193306de7ff6f1204f3ac0963076
2026-07-06 16:10:05 +00:00
camc314 df62046da9 fix(transformer): preserve decorated class read bindings (#24231)
## Summary

Fix semantic reference tracking when class-properties processes a named class rewritten by legacy decorators.

## Problem

Legacy decorators split a named class into two bindings:

- the outer variable binding;
- the inner class-expression binding.

Class-properties previously created `_Class = Class` using the rewritten `class.id`, which points to the inner binding. Since the assignment executes outside the class body, it must reference the outer binding captured when entering the class.

Originally anonymous classes are different: another transform may assign their final name later, so they must continue using the current `class.id`.

```mermaid
flowchart TD
    A["Create read for `_Class = Class`"] --> B{"Captured class name is the temp binding?"}
    B -- "No" --> C["Named class: read captured outer binding"]
    B -- "Yes" --> D["Originally anonymous class: read current class ID"]
```

## Solution

Use the class binding captured on entry for named declarations, while retaining the current class ID for originally anonymous declarations.

This aligns transformed reference IDs with semantics rebuilt from the generated output without regressing anonymous decorated classes.
2026-07-06 15:16:21 +00:00
camc314 09bd6389c8 fix(transformer): scope anonymous decorated class bindings correctly (#24229)
## Summary

Generate bindings for anonymous decorated classes in the class’s enclosing scope.

## Problem

When an anonymous class element has a decorator, the transformer creates a
temporary `_default` binding while traversing the class body.

Previously, the binding was registered in the current class scope even though
the transformed declaration is emitted outside that class.

```text
Semantic data before fix          Transformed AST

Program                           Program
└─ Class scope                    └─ class/variable _default
   └─ binding: _default               ↑ emitted here
       ↑ recorded here
```

This caused the retained semantic data to disagree with semantics rebuilt from
the transformed AST:

```text
after transform: _default → class scope
rebuilt:         _default → enclosing scope
```

## Solution

Derive the class’s enclosing scope from its semantic scope and generate the
temporary binding there.

```text
Class scope
    │
    └── parent scope ── generate `_default` binding here
                            │
                            └── matches emitted declaration
```

This corrects binding ownership for anonymous default-export classes with
decorated members.
2026-07-06 14:44:59 +00:00
camc314 4b7fa9ca35 fix(transformer): preserve namespace strict mode flags (#24227)
## Summary

Preserve strict-mode metadata when lowering TypeScript namespaces into IIFE-style functions.

Previously, namespace transformation always replaced the original scope flags with `Function | StrictMode`, causing semantic mismatches for namespaces that were not strict. The transform now retains strictness only when present on the original namespace or enclosing scope.

Updated semantic and transform-conformance snapshots to remove the resolved scope-flag mismatches.
2026-07-06 14:00:03 +00:00
camc314 d8ead846c8 fix(transformer): correct scoping flags for lowered enums (#24225)
## Summary

TypeScript enum lowering reuses the enum body’s scope for the generated function expression. Update that scope with `ScopeFlags::Function` so transformed semantic data matches a freshly rebuilt AST.
2026-07-06 13:34:00 +00:00
leaysgur 1fe65465d4 fix(formatter): omit unneeded ; for type members with no-semi (#24212)
Also checked with `tsc`, this can be omitted.

```ts
interface H1 {
  foo: X /* ; */
  <T>(): T
}
```
2026-07-06 09:26:54 +00:00
camc314 e8b50ee716 fix(transformer): clean up semantics for stripped TypeScript syntax (#24180)
## 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.
2026-07-06 08:11:46 +00:00
leaysgur 3abbed59d2 fix(formatter): print ; before jsdoc type-cast parens with no-semi (#24208)
Follows https://github.com/prettier/prettier/blob/79f6cdfd9873a91be9b25c9c6a41d26dcd9a6656/changelog_unreleased/javascript/18751.md

```js
;/** @type {string[]} */ (["foo", "bar"]).forEach(doStuff)
```

With `no-semi`, this `;` should stay the same position.

Also fixes minor bugs and idempotency issues.
2026-07-06 06:01:18 +00:00
camc314 4b16e1a342 fix(transformer/async-to-generator): preserve direct eval scope flags (#24136)
## Summary

- propagate `DirectEval` when async-to-generator lowering inserts wrapper scopes
- update the Test262 semantic snapshot for the newly passing cases

## Known edge case

A direct eval nested in a function-valued default parameter of an async method can still leave a stale flag when that parameter scope is reparented. This should be addressed by the new function body scope logic
2026-07-03 17:11:56 +00:00
camc314 018c0e57ec fix(transformer): hoist lowered async declarations (#22770)
Fixes semantic scope mismatches when async function declarations are lowered inside sloppy block scopes.

Before this change, `async_to_generator` kept the original async function binding, and the generated helper binding, in the current block scope. After transform those declarations are no longer async:

```js
with (obj) {
  async function ref() {}
}
```

becomes roughly:

```js
with (obj) {
  function ref() {
    return _ref.apply(this, arguments);
  }
  function _ref() {
    _ref = babelHelpers.asyncToGenerator(function* () {});
    return _ref.apply(this, arguments);
  }
}
```

A fresh semantic rebuild treats those lowered plain function declarations with Annex B hoisting rules, so in sloppy block scopes their bindings can belong to the enclosing var scope instead of the block scope. The transformed semantic tree was still using the pre-lowered block placement, which caused rebuild mismatches in Test262 coverage.

This PR makes `async_to_generator` choose the same binding scope that a rebuilt semantic tree would use for the emitted plain function declarations, while preserving the existing behavior for TypeScript, strict mode, var scopes, and cases where the hoist scope already has a binding.
2026-07-02 19:47:32 +00:00
Dunqing 53f0b2ee3e fix(coverage): use ephemeral ports for runtime servers (#24053)
## Summary

Self-review follow-up to #24034 (stacked on #24052), hardening the runtime suite's server transport:

- **Ephemeral ports + stdout handshake**: the fixed 32055..N port range let an orphaned server from a killed run pass the readiness probe (silently testing against a stale binary) and made two concurrent runs in different worktrees cross-talk — one run's shutdown DELETE kills the other's servers. `runtime.js` now listens on an OS-assigned ephemeral port and reports it as the first stdout line, which the runner reads as both the port and the readiness signal (the polling loop and port math are gone); remaining server stdout is drained by a background thread so `DEBUG=1` output can't deadlock a full pipe.
- **Transport retry**: monitor-oxc's first live Test262 run flipped 13 for-of cases to `timeout: global` — ureq's 10s client timeout tripping under CI load while requests queued, not a semantic change. A localhost-specific agent (no proxy, one-minute timeout) plus a single retry fixes it; the server responds even for failing tests, so a transport `Err` never carries a verdict.

Result-neutral: 17279/18277, `runtime.snap` byte-identical across repeated runs.
2026-07-02 09:19:22 +00:00
Dunqing 89c32cb4f8 refactor(coverage): run the runtime suite via run_tool (#24052)
## Summary

Self-review follow-up to #24034 (stacked on #24049): the runtime suite now fits the standard `run_tool` framework — `runtime::run` is a plain `fn(&[Test262File]) -> Vec<CoverageResult>` runner, deleting its hand-copied print/snapshot tail so reporting-convention changes can't silently skip it. `cargo coverage all` no longer reads the ~52k-file test262 tree twice (`run_all_with` shares one loaded `TestData`); the standalone `runtime` command still loads only test262, which monitor-oxc CI relies on. Also hoists the per-request `workspace_root()` walk to once per file.

Result-neutral: 17279/18277, `runtime.snap` byte-identical, verified via both `cargo coverage runtime` and `cargo coverage all`.
2026-07-02 09:10:00 +00:00
Dunqing c2bb384c55 fix(coverage): size runtime servers to the rayon pool (#24049)
## Summary

Follow-up to #24034 from self-review: `available_parallelism()` spawned N Node servers even when `--debug` caps the rayon pool at 1 thread, leaving N−1 servers idle (only `current_thread_index() % num_servers` = server 0 is ever used). Size the server count from `rayon::current_num_threads()` instead. Full suite verified unchanged: 17279/18277, byte-identical `runtime.snap`.
2026-07-02 08:55:19 +00:00
Dunqing 9d09a875b5 test(coverage): reimplement test262 runtime execution (#24034)
## Summary

#18478 reduced the test262 runtime runner to a stub ("not yet implemented"), and since oxc's own CI never runs `cargo coverage runtime`, the transformer/minifier semantics coverage it provided has been dark — monitor-oxc's Test262 job (the only consumer) has been disabled since July 2025.

This restores execution on the simplified architecture: each eligible test262 case runs through codegen / transform / minify and executes in the Node runtime server, driven by rayon with blocking HTTP instead of the old tokio design. Skip lists and per-variant semantics are ported verbatim from the pre-#18478 runner.

- `main.rs` now loads `TestData` lazily, so `cargo coverage runtime` works with only the test262 fixtures checked out (which is how monitor-oxc CI invokes it).
- Execution is parallelized: one Node server per core with each rayon worker pinned to its own server, and the test262 harness is compiled once per distinct include list as a reusable `vm.Script` instead of re-parsed per request. Full suite: ~10s wall locally (~45s single-server).
- Results at test262 `de8e621c`: 17279/18277 positive tests pass (94.54%); `runtime.snap` is committed and byte-stable across repeated runs; clippy/fmt clean.
- monitor-oxc side: oxc-project/monitor-oxc#178 (must merge after this one).

Note: oxc CI still does not run the runtime suite, so `runtime.snap` can go stale and turn monitor-oxc's job red — the failure mode that led to the original "skip 262". Possible follow-ups: run it in conformance CI, or add a regression-only mode (fail on new failures, tolerate improvements).
2026-07-02 05:35:57 +00:00
Boshen 633d226081 test(coverage): add TypeScript symbol, type, and error baseline conformance suites (#23999)
## Summary

Ports typescript-go's symbol/type/error baseline harnesses
(`internal/testutil/tsbaseline/{type_symbol_baseline,error_baseline}.go`)
into `tasks/coverage` as new conformance suites, measuring oxc against
the `.symbols`, `.types`, and `.errors.txt` baselines already shipped in
the TypeScript submodule (~14k each). All report through the shared
`CoverageResult` machinery, so their summaries/snapshots look exactly
like the other suites.

Run with `cargo coverage symbols` / `cargo coverage types` / `cargo
coverage errors`.

## What's measured

- **symbols** — walk the AST (`oxc_ast_visit`), resolve lexical bindings
via `oxc_semantic`, emit `Symbol(name, Decl(file, line, col), ...)` with
declaration positions recovered from the parser token stream (to match
TypeScript's trivia-inclusive `node.pos`), then diff against the
baseline.
  `AST Parsed 8364/8364 (100%)`, `Positive Passed 1765/8364 (21.10%)`.
- **errors** — match oxc parser diagnostic positions + TS codes (oxc's
parser attaches real `TSxxxx` codes via `ts_error`) against the
`.errors.txt` summary headers.
  `AST Parsed 7699/7699 (100%)`, `Positive Passed 7251/7699 (94.18%)`.
- **types** — **scaffold**. Same harness parameterized by kind
(mirroring typescript-go's `isSymbolBaseline`), but oxc has no type
checker, so every type payload is `<<unresolved>>`. The full runner
(baseline discovery, walk, output format, comparison, snapshot) is wired
and ready for a checker to fill in the walker's `Types` arm.
`AST Parsed 8364/8364 (100%)`, `Positive Passed 78/8364 (0.93%)` — the
passes are files with empty type baselines.

## Notes

- oxc has no type checker, so `.types` and the type-checker surface of
`.symbols`/`.errors.txt` (member/`this` symbols, qualified names, lib
globals, `TS2xxx`/`TS18xxx` errors) are out of reach — that gap is the
measurable target for a future checker, which is exactly what the
`.types` scaffold sets up.
- The suites are opt-in subcommands (like `transpiler`), not part of
`cargo coverage all`.

---

🤖 Written with [Claude Code](https://claude.com/claude-code) (AI
assistance); reviewed by the author, per oxc's AI usage disclosure
policy.
2026-07-01 17:53:25 +08:00
overlookmotel 85a6853e0b fix(tasks): enable disable_old_builder Cargo feature for oxc_ast crate for all tasks (#23885)
Part of #23043.

We don't enable `oxc_ast`'s `disable_old_builder` Cargo feature in any of our published crates, or crates that are depended on by published crates.

Tasks are private to the repo, so enable this feature on them, to ensure no usage of legacy `AstBuilder` methods sneak in during the transition period before we delete these methods.
2026-06-28 12:13:17 +00:00
overlookmotel 7a76cd3dc3 feat(estree)!: make whether to include TS fields a runtime option (#23574)
Previously, whether to serialize AST to ESTree JSON with/without TS fields was a compile-time option - via 2 different configs `CompactTSSerializer` and `CompactJSSerializer` (and their pretty-printing and with-fixes counterparts).

Turn this into a runtime option instead -

This make serialization a little slower (more branches in either mode, and dead code in JS-only mode) but reduces the size of `oxc-parser` binary as only one `ESTreeSerializer` is generated, instead of 2 (JS-only, and with-TS).
2026-06-17 23:22:37 +00:00
sapphi-red 38c4b0628b feat(parser): add friendly error for adjacent JSX elements (#23378)
Add a friendly error for adjancent JSX element case:

```
  × Adjacent JSX elements must be wrapped in an enclosing tag.
   ╭─[misc/fail/jsx-adjacent-elements.jsx:3:3]
 2 │   <div />
 3 │   <span />
   ·   ─
 4 │ );
   ╰────
  help: Did you want a JSX fragment `<>...</>`?
```

This error message exists in babel.
2026-06-16 14:50:53 +00:00