Commit Graph

1582 Commits

Author SHA1 Message Date
oxc-guard 9e72aa0312 chore(submodules): update submodule SHAs to latest commits (#23451)
Updates submodule dependencies to their latest commits.

## Changes

- test262: `05bb032` → `de8e621`
- babel: `2688fbd` → `1fb0b77`
- TypeScript: `7539c04` → `7964e22`
- estree-conformance: `ca42c3d` → `6514ad7`

This PR is automatically generated by the [update_submodules workflow](https://github.com/oxc-project/oxc/blob/main/.github/workflows/update_submodules.yml).
2026-06-15 14:31:01 +00:00
Boshen 7a24911846 perf(codegen)!: borrow sourcemaps from codegen (#23422)
Summary:
- Upgrade oxc_sourcemap to 8.0.1.
- Return borrowed SourceMap from CodegenReturn.
- Support no-sourcemap feature builds used by benchmarks.

AI-assisted: yes
2026-06-15 19:07:21 +08:00
camc314 65f9233148 refactor(parser): emit all TS1274 checks from parser (#23361)
Move TS1274 variance modifier validation into the parser and remove the duplicate semantic diagnostic path.
2026-06-12 21:47:05 +00:00
camc314 47991bd7b5 feat(semantic): report TS1228 for invalid type predicates (#23174)
- Emit TS1228 for invalid type predicate positions from semantic syntax checks.
- Treat valid predicates as only those that are the immediate return type of a function, method, function type, call signature, or non-accessor method signature.

## Why semantic
TypeScript parses type predicates as part of the normal type grammar, then validates their placement later in checker logic. This is not a parser recovery decision: the syntax can be represented in the AST, but whether it is legal depends on the predicate node's parent chain.

Keeping this check in semantic avoids parser mode plumbing and matches that model. The semantic checker can inspect ancestry to reject predicates in property annotations, constructor types, accessors, construct signatures, and nested or parenthesized type positions while reporting the span on the predicate node itself.
2026-06-11 19:50:06 +00:00
camc314 1d3af58c4a feat(parser): add TS2398 parameter property diagnostic (#23216)
## 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){}}
   ·                               ───────────
   ╰────
```
2026-06-11 08:39:25 +00:00
Boshen 45388ed097 refactor(parser): remove speculative JSX parsing for jsx-in-non-jsx error (#23244)
Part of the effort to remove all checkpoint usage from the parser.

Replace the speculative JSX parse (checkpoint + rewind) in `parse_jsx_in_non_jsx_error` with a direct fatal error on the `<` token, with help to enable JSX in the parser options.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-06-10 16:58:16 +00:00
Boshen 777f02ae10 refactor(diagnostics)!: return a Diagnostics type instead of Vec<OxcDiagnostic> (#23217)
## Summary

Introduces `oxc_diagnostics::Diagnostics` — a `Vec<OxcDiagnostic>` newtype that knows the difference between errors and warnings — and makes it the standard diagnostics return value across oxc.

- **New type**: `Diagnostics` with `has_errors()`, `has_warnings()`, `errors()`, `warnings()`, plus `Vec`-like ergonomics (Deref, `IntoIterator`, `Extend`, `From`/`Into<Vec>`) so most call sites are unchanged.
- **Return types**: `ParserReturn`, `SemanticBuilderReturn`, `IsolatedDeclarationsReturn`, the React Compiler `TransformResult`/`LintResult`, and `TransformerReturn` now expose `diagnostics: Diagnostics` instead of `errors: Vec<OxcDiagnostic>` (the React Compiler's separate `errors`/`warnings` are merged into one severity-tagged list).
- **Behaviour**: a React Compiler **error** now stops the transform (no output), while **warnings** flow through and the transform continues. `compile()` aborts codegen only when `diagnostics.has_errors()` — warnings alone no longer abort (previously any diagnostic did).

## Breaking change

Consumers reading `*.errors` on these return values must read `*.diagnostics`. React Compiler consumers that read `.errors`/`.warnings` separately should use `diagnostics.has_errors()` / `diagnostics.errors()` / `diagnostics.warnings()`.

Parser/semantic/isolated-declarations fatality is otherwise unchanged. Builds on the React Compiler transform feature (#23201).

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-06-10 14:46:52 +00:00
camc314 e5050c082d feat(parser): improve diagnostic for rest initializer (#23205)
This improves the readability of parser diagnostics by distinguishing rest parameter initializer errors from rest binding element initializer errors.
2026-06-10 08:14:58 +00:00
Boshen ec266bb733 feat(transformer): run React Compiler as a feature-gated transform pass (#23201)
## Summary

Exposes the React Compiler from `oxc_transformer` behind a Cargo feature so callers no longer need a separate `oxc_react_compiler::transform` + scoping-rebuild step before transforming.

- **`oxc_transformer`**: new `react_compiler` Cargo feature (off by default) + `TransformOptions::react_compiler` field. When set, `Transformer::build_with_scoping` runs the React Compiler first (via a private `run_react_compiler` method), replacing the program and rebuilding scoping for the downstream transforms.
- **Opt-in**: the feature is **not** enabled by `oxc_transformer`'s defaults, nor by `oxc`'s `transformer`/`full` features — enabling the transformer does not pull the heavy `oxc_react_compiler` dependency. It is a separate `react_compiler` feature on `oxc` (which implies `transformer`); the napi transform binding opts in explicitly.
- **Dedupe**: removes the inline React-Compiler orchestration (and the `react_compiler_options()` hook) from `oxc`'s `CompilerInterface` and the napi transform binding; both now drive it through `TransformOptions::react_compiler`.
- **Diagnostics**: the compiler's errors and warnings are merged into `TransformerReturn::errors` (each keeps its severity; downstream filters). `compile()` reports them but no longer aborts codegen — the transformer always leaves a valid program, matching the documented "code may still be available even if there are errors" behaviour.
- **Links**: updates the React Compiler references to the merged upstream location (`react/react/tree/main/compiler`).

## Notes

Transform/codegen output is unchanged when the feature is off (the field defaults to `None` everywhere). The diagnostics behaviour change (no codegen abort) is conformance-safe — the transform-conformance harness keys off reported diagnostics, not printed output.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-06-10 08:03:07 +00:00
camc314 8edd23459d fix(parser): report accessor definite assertion on token (#23203)
## Summary
- Pass the definite-assignment assertion token offset through the class accessor-property parser path.
- Report invalid ambient and abstract `accessor prop!` diagnostics on the `!` token, matching the span behavior used by variable declarators and normal class properties.
- Add focused misc parser coverage for the accessor-specific invalid cases.

## Rationale
This follows up #23170. That parser change already narrowed definite-assignment diagnostics for variables and normal class properties, but accessor properties still kept only a boolean. That meant `accessor prop!` could only report TS1255 using the full class element span. Carrying the offset into `parse_class_accessor_property` aligns accessor diagnostics with the other definite-assignment diagnostics and keeps the AST shape unchanged by storing only `definite.is_some()`.

The misc fixture is needed because upstream TypeScript coverage exercises invalid definite assertions on normal fields, but not invalid accessor properties. Existing misc coverage only had a valid `accessor y!` pass case, so `just coverage` did not specifically protect the accessor diagnostic span this fixes.
2026-06-10 07:46:45 +00:00
camc314 e7374feffc feat(parser): report error for const modifier on interface type parameter (#23173)
i think this got lost on Boshen 's stacks, as this appeared to get merged in https://github.com/oxc-project/oxc/pull/22829/changes
2026-06-09 16:25:25 +00:00
camc314 d74964cda6 perf(parser): store class definite assertion offset (#23170)
- Store class property definite assignment assertion positions as `u32` offsets instead of carrying a full `Span`.
- Reconstruct the one-character diagnostic span only when emitting class definite-assignment diagnostics.
- aligns the behaviour for definite assertion errors with variables by reporting on the definite assertion rather than on the whole class member
2026-06-09 15:33:10 +00:00
camc314 a7c1c9be05 feat(parser): report ambient definite variable assertions (#23165)
## Summary
- Report TS1255 for definite assignment assertions on ambient variable declarations.
- Preserve TypeScript’s diagnostic precedence for variable declarations: initializer errors first, missing type annotation errors second, then invalid ambient context.

## Details
This covers ambient variable cases from the TypeScript conformance fixture, including:

```ts
declare let v1!: number;
declare var v2!: number;

declare namespace foo {
  var v!: number;
}
```
2026-06-09 14:42:43 +00:00
camc314 d169fcd3af feat(parser): report invalid class definite assertions (#23164)
- Match TypeScript’s diagnostic precedence for class property definite assignment assertions.
 - Report TS1264 when a class property uses ! without a type annotation.
 - Report TS1255 when a definite assignment assertion is used in disallowed class property contexts, including static.
2026-06-09 14:42:42 +00:00
camc314 00244d8e10 feat(parser): report definite property initializer errors (#23160)
Report TS1263 for TypeScript class properties that combine a definite assignment assertion with an initializer.
2026-06-09 14:42:42 +00:00
Boshen 8a04149e29 fix(parser): reject module-referencing imports/exports in a namespace body (#22829)
Inside an internal `namespace N {}` / `module N {}`, statements that
reference a
module are not permitted — this matches both babel and TypeScript:

- `import ... from "m"` / `import x = require("m")`  → TS1147
- `export ... from "m"` / `export * from "m"`         → TS1194
- `export default ...`                                → TS1319
- `export = ...`                                       → TS1063

Bare `export { x }` (re-export of locals, no module source) and `import
x = A.B`
(entity alias) stay valid, as do external modules (`declare module "x"
{}`) where
these forms are allowed — the check only runs for internal namespaces,
so those
never reach it.

Also removes TS1147 from the coverage denylist
(`NOT_SUPPORTED_ERROR_CODES`), since
oxc now detects it.

Conformance (no regressions, positive/AST stay 100% everywhere):
- parser_babel  negative 1696 → 1704
- parser_typescript negative 1585 → 1594
2026-06-09 00:52:10 +08:00
Boshen 1260f03b4f refactor(semantic): don't build the AstNodes store by default (#23005)
## What

Make the full `AstNodes` store **opt-in**, so the compiler pipeline (transformer / codegen / minifier) can run semantic analysis without building it at all.

Previously every `SemanticBuilder` run allocated and populated the full `AstNodes` store, even for consumers that only need scoping + the syntax checker. This separates the node-related builder state into three independent pieces:

- a standalone `NodeId` counter — the source of truth for node ids, valid in either mode;
- an **ancestry stack** — an upward-walk-only stack of the current node's ancestors, the only ancestry the syntax checker and binder actually read;
- the full **`AstNodes`** store — random access to every node, needed by the linter and mangler.

## How

- A new `AstNodeStore` (in `crates/oxc_semantic/src/node/store.rs`) bundles the node-id counter, the current-node cursor/flags, and the storage. The storage is an enum (`AstNodeStoreKind`) with two variants — `Full(AstNodes)` and `Ancestry(AncestryStack)` — so the full store and the ancestry stack are **mutually exclusive by construction**; they can never both be maintained at once.
- The checker and binder read ancestry through an `Ancestry` view (`node/ancestry.rs`) that dispatches between the full store (linter / mangler) and the stack (compiler pipeline). They no longer do random `NodeId` access into the store — all ancestry access is upward-walk-only.
- `SemanticBuilder` gains `with_build_nodes(bool)`. The default is **off** (ancestry stack only). `new_linter()` turns it on (the linter needs the full store); `new_compiler()` leaves it off.
- `CompilerInterface::build_semantic_nodes()` lets `oxc::Compiler` consumers opt back in if their `after_semantic` hook reads `Semantic::nodes`.

## Notes

- Behaviour-neutral: semantic conformance snapshots are unchanged.
- Allocation snapshots updated — the default (ancestry) path allocates slightly less (the growing `Stack` trades a couple of fixed allocations for a few reallocs).
- Builds on the already-merged `SymbolFlags`-based redeclaration checks (#23060) and the `new_linter`/`new_compiler` preset adoption (#23057), which removed the last random node reads from the redeclaration path so the checker works without the store.
2026-06-08 16:13:56 +00:00
Boshen da1a6c6e2a perf(diagnostics): migrate to allocation-optimized oxc-miette (#23094)
## Summary

Adopts the allocation-optimized oxc-miette diagnostic APIs (oxc-miette v3):

- `OxcDiagnostic` stores labels in `miette::Labels` (1–2 inline, no `Vec`); **drops the `smallvec` dependency**.
- `Diagnostic::labels`/`related` return owned inline containers; `code`/`help`/`note`/`url` return `Cow<str>`; `SourceCode::read_span` returns the concrete `MietteSpanContents` — all consumer call sites updated (linter `fixer`/`lib`/`runtime`/`tsgolint`, `oxc_napi`, napi/parser, oxlint LSP, coverage).
- `usize → u32` span conversions for the u32 `SourceSpan`.

## Allocation impact (parser benchmark)

`just allocs` — **~33% fewer sys allocations, no change in reallocations**:

| File | Sys allocs (before → after) | Sys reallocs |
|------|---|---|
| checker.ts | 5303 → 3543 | 10 (unchanged) |
| antd.js | 5392 → 3720 | 221 (unchanged) |
| App.tsx | 632 → 444 | 13 (unchanged) |
| pdf.mjs | 518 → 356 | 67 (unchanged) |
| binder.ts | 281 → 169 | 0 (unchanged) |

(The inline `Labels` removes the per-diagnostic `Vec`; an earlier `Box<str>` realloc regression was fixed in oxc-miette before this snapshot was taken.)
2026-06-08 16:00:57 +00:00
oxc-guard b4f9cb9d8c chore(submodules): update submodule SHAs to latest commits (#23118)
Updates submodule dependencies to their latest commits.

## Changes

- test262: `7e115f4` → `05bb032`
- babel: `d9fe348` → `2688fbd`
- TypeScript: `e5509e2` → `7539c04`
- estree-conformance: `faf089d` → `ca42c3d`

This PR is automatically generated by the [update_submodules workflow](https://github.com/oxc-project/oxc/blob/main/.github/workflows/update_submodules.yml).
2026-06-08 14:49:36 +00:00
Boshen cf53285466 fix(parser): report reserved type-declaration names in the parser (#23035)
## What

Moves the reserved built-in type name check (a type's name may not be `any`, `string`, `number`, …) out of the semantic checker into the parser, via a reusable `check_reserved_type_name` helper. Covers **all** declaration forms:

- class → TS2414
- interface → TS2427
- type alias → TS2457
- enum → TS2431
- type parameter → TS2368

The semantic `check_type_name_is_reserved` helper and its diagnostic are removed.

## Why it moves cleanly

- **Zero state:** each is a name-vs-reserved-list match at the parse site where the identifier is parsed.
- **Node-final:** these declarations are never reinterpreted by cover grammar.
- **Negative-only:** confirmed by `cargo coverage` — no positive/negative count changes; only the errors relocating in `parser_typescript.snap`.

## Class needs an `is_ts` guard + a fixture fix

`class string {}` is valid JavaScript (these names are reserved only as *type* names), so the class check is guarded by `is_ts`. The interface/type-alias/enum/type-parameter forms are TypeScript-only parser paths, so they need no guard.

The `no-shadow-restricted-names` rule had `class undefined {}` / `(class undefined {})` fixtures. Since the lint test harness parses fixtures as TSX, those are now parse errors (TS2414). They're dropped — class-name shadowing is still covered by `class globalThis {}` (globalThis isn't a reserved type name), and `undefined` shadowing by the `var`/`import` fixtures.

## Verification

- `class number {}`, `interface any {}`, `type any = number`, `enum string {}`, `function f<any>() {}` → error; `class string {}` in `.js` → clean; valid names → clean.
- Parser/semantic/linter (1155) tests pass; clippy clean.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-06-07 02:05:14 +00:00
Boshen 6da876eeed fix(parser): report abstract private class field in the parser (#23029)
## What

Moves the "'abstract' modifier cannot be used with a private identifier" check (TS18019) for **class fields** out of the semantic checker (`check_property_definition`) into the parser.

## Why it's a clean move

- **Zero state:** the check is `r#abstract && name.is_private_identifier()` — only node fields, evaluated where the class element's modifiers and key are already in hand (next to the existing `abstract_property_cannot_have_initializer` check).
- **Node identity is final at parse time:** a `PropertyDefinition` is a class field; classes are never reinterpreted by cover grammar (unlike object literals → patterns), so there's no value-vs-pattern ambiguity.
- **Negative-only:** `abstract #x` is broken code, confirmed by `cargo coverage` — no positive-suite regressions.

The identical diagnostic for abstract **methods** (`check_method_definition`) stays in the semantic checker, so the shared diagnostic is kept.

## Conformance

No count changes in any suite; the only snapshot delta is the TS18019 error relocating (now emitted during parsing) in `parser_typescript.snap`. Parser/semantic/linter tests pass.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-06-06 17:25:02 +00:00
Boshen 4d722e09f8 fix(parser): report duplicate switch default clause in the parser (#23012)
## What

Moves the "A 'default' clause cannot appear more than once in a 'switch' statement" (TS1113) check out of the semantic checker (`check_switch_statement`) and into the parser's `parse_switch_statement`.

## Why

The check only reads the switch statement's own `cases` list, which is fully built at the parse site — it needs no scope, symbol, or strict-mode information, so it can move to the parser without introducing any new parser state. Reporting it during parsing surfaces the error in source order and removes a node-kind dispatch from the semantic builder.

## How

- The duplicate-`default` check is folded into the case-parsing pass (no second loop over `cases`). To do this without duplicating `parse_normal_list`'s open/loop/close logic, its callback bound is relaxed from `Fn` to `FnMut` (a safe generalization — all existing callers already satisfy it), so the case callback can track the first `default` span inline.
- Only the first duplicate per `switch` is reported, matching the previous semantic-checker behavior.
- A `unicorn/no-useless-switch-case` pass fixture that relied on a two-`default` switch being a *recoverable* (semantic-only) error was removed: the linter treats any parser error as fatal to the file, so a duplicate `default` now stops that file from being linted.

## Conformance

No positive/negative count changes in any suite. The only snapshot delta is a reordering in `parser_typescript.snap` (the error now fires during parsing, in source order, ahead of later errors in the same switch).

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-06-06 13:20:00 +00:00
Boshen 1295882c65 fix(parser): report new.target and import.meta syntax errors in the parser (#23003)
## What

Move the `MetaProperty` early-error checks from the semantic checker (`oxc_semantic`) into the parser:

- **`new.target` outside a valid context** — e.g. at the top level, in a top-level arrow, or in a computed class-member key.
- **`import.meta` outside a module** — i.e. in script / CommonJS code.

Consumers that only run the parser (without `SemanticBuilder`) now get these diagnostics.

## How

- `new.target` validity is tracked with a new inherited `Context::NewTarget` flag (widening `Context` from `u8` to `u16`). The flag is *added* by three constructs — a regular (non-arrow) function's parameters + body, a class static block, and a class field initializer — and *inherited* through arrow functions and class bodies. This naturally models the spec rule, including cases like `function g(){ class D { [new.target](){} } }` (valid, inherits `g`'s context).
- `import.meta` reuses the existing `error_on_script` deferral, so in unambiguous source `visit_import_meta` marks the file a module and the deferred error is discarded.
- `check_meta_property` and its now-unused diagnostics are removed from `oxc_semantic`.

## Spec correctness

Verified all cases against V8 (Node v24). One behavior change vs. the old semantic checker: a computed class **field** key such as `class C { [new.target] = 1 }` at the top level is now correctly a **SyntaxError**, matching V8 — the old checker accepted it due to a coarse `PropertyDefinition` AST-ancestor match.

| Source | V8 | this PR |
| --- | --- | --- |
| `new.target;` | SyntaxError | error |
| `function f(){ new.target; }` | ok | ok |
| `() => new.target;` | SyntaxError | error |
| `class C { x = new.target; }` | ok | ok |
| `class C { static { new.target; } }` | ok | ok |
| `class C { [new.target] = 1; }` | SyntaxError | error |
| `class C { [new.target](){} }` | SyntaxError | error |
| `function g(){ class D { [new.target](){} } }` | ok | ok |
| `import.meta` in script | SyntaxError | error |
| `import.meta` in module | ok | ok |

Parser & semantic conformance remain 100% positive / 100% negative on test262; all unit tests pass.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-06-06 07:35:41 +00:00
Boshen 17e7cf3ce4 fix(parser): disallow unerasable as/satisfies assertions (#22986)
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)
2026-06-05 13:10:42 +00:00
leaysgur 5778a2dfb5 refactor(formatter_core): purify core and define rules (#22952)
The Printer never consumes these; they belong with each language formatter.

- Evict `Quote` (each formatter owns `QuoteStyle`)
  - `normalize_string` takes a quote byte
- Evict `Expand` / `BracketSpacing` / `TrailingCommas` into oxc_formatter and oxc_formatter_json
- JSON's `TrailingCommas` is now two-variant (`Always`/`Never`)
  - collapse Prettier's `all`/`es5` at each translation layer
- Rename `util/` -> `spec/` (pure shared helpers)
- Split `SourceText`: mechanical access stays in core, JS/TS lexis moves to `SourceTextExt`
- Drop the `oxc_syntax` dependency from core

All behaviros, Prettier conformance are unchanged.
2026-06-04 07:03:56 +00:00
Boshen beb46d31fa fix(parser): commit to module goal on decorated exports (#22941)
## Summary

In unambiguous (`.js`) sources, `@foo export default class C { x = await + 1 }` reported a spurious `A module cannot have multiple default exports`.

A leading decorator makes the statement start with `@`, not `export`, so the eager Module-goal switch from #22684 didn't fire. The `await` identifier in the field initializer then triggered the unambiguous-mode top-level-await reparse, which re-ran `parse_statement_list_item` and recorded the `export default` a second time.

## Fix

- Commit to the Module goal in `parse_export_declaration` — the single place both leading and decorated exports flow through — so the export body parses under `Await` on the first pass, matching a non-decorated leading `export` (`ExportDeclaration` is unambiguously a `ModuleItem`, ECMA-262 §16.2.3).
- Skip the reparse for module declarations (`!stmt.is_module_declaration()`): an `export` / `import` is recorded on the first pass and is goal-independent, so reparsing only double-records it.

This also simplifies `parse_directives_and_statements`: the mutable `track_await_reparse` flag and the inline eager-commit block are removed; committing is now driven by `!ctx.has_await()`.

`await` stays correctly reserved in the module, so the input is still a syntax error (`The keyword 'await' is reserved`) — just no longer a *spurious* duplicate-export one. `tasks/coverage/misc/fail/oxc-22684.js` covers this.

Conformance: zero snapshot drift outside the new `misc` fixture.

Follow-up to #22684.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-06-04 04:05:46 +00:00
camc314 5b8dd68142 feat(parser): report TS1255 for invalid class definite assertions (#22917)
This adds the TypeScript parser diagnostic for definite assignment assertions in class member contexts where TypeScript rejects them.

`!` on class properties is still allowed for normal initialized-check suppression, but we now report TS1255 when it appears on ambient class members or abstract properties/accessor properties. This covers cases like `declare property!: T`, `declare class C { property!: T }`, and `abstract property!: T`.
2026-06-02 12:42:49 +00:00
camc314 81b86eb618 feat(parser): report TS1095 for setter with return type (#22889) 2026-06-01 12:19:30 +00:00
camc314 089948513e feat(parser): report TS1051 for optional setter parameter (#22887)
Fixes a missing TypeScript parser diagnostic for optional setter parameters.

TypeScript reports `TS1051` for setters like:

```ts
class C {
  set Foo(a?: number) {}
}
```

Oxc already had the diagnostic defined and used it for TypeScript accessor signatures, but concrete class/object setter validation only checked rest parameters and initializers. This adds the missing `param.optional` check in TypeScript mode and updates the parser TypeScript coverage snapshot.
2026-06-01 11:48:58 +00:00
camc314 139b53195c feat(parser): emit TS1094 for accessor type parameters (#22885)
Adds parser validation for TypeScript accessor declarations with type parameters.

TypeScript reports TS1094 for accessors like `get foo<T>()` and `set foo<T>(value)`. Oxc already parsed the type parameters, but did not emit the matching parser diagnostic, so the relevant TypeScript conformance cases were still listed as expected syntax errors.
2026-06-01 11:29:59 +00:00
leaysgur 705c0e969b refactor(formatter): introduce text-in public APIs (#22872)
Align `oxc_formatter` with `oxc_formatter_json`, both now expose `format(...) -> Result<Formatted<'a, _>, OxcDiagnostic>`.

- Add text-in `format` and `format_fragment`, also `format_program`, `parse_for_format` and the `FragmentContext` enum
  - Parse options, JSX enabling, js-in-xxx context aware handlings are applied internally
  - Make the `Formatter` struct and AST/IR primitives crate-internal
- Fold `get_parse_options` / `enable_jsx_source_type` and the `service` module into `parse_for_format`
2026-06-01 06:40:34 +00:00
Boshen cf5769c9e2 fix(parser): reject TypeScript declarations in single-statement context (#22827) 2026-05-31 16:24:00 +08:00
Boshen c360fb6e20 fix(parser): reject generators in ambient contexts and overload signatures (TS1221/TS1222) (#22848)
A generator (`function*` / `*method`) is not allowed in an ambient context
(TS1221), and a generator overload signature with no body is not allowed
(TS1222). Mirrors tsc's `checkGrammarForGenerator`:

    declare function* f(): any;              // now TS1221
    declare namespace N { function* g(); }   // now TS1221
    declare class C { *m(); }                // now TS1221
    function* f(): any;                       // overload → now TS1222
    function* f() { yield 1; }

    function* f() { yield 1; }               // normal generator → still valid

The check lives in `parse_function` next to the TS1183 implementation-in-ambient
check and keys off `ctx.has_ambient()` / `body.is_none()`. Class methods are
covered too (`class.rs` does not check generators, so there is no duplicate
diagnostic).

Also fixes a latent bug: `parse_ts_declare_function` hard-coded `generator: false`
and never consumed the `*`, so `declare function* f()` silently dropped the
generator flag. It now eats the `*` and threads the flag through (which is what
lets TS1221 fire there).

parser_typescript +7 negative-pass (generatorInAmbientContext1-4, generatorOverloads1-3);
positive/AST stay 100%.
2026-05-31 08:02:50 +00:00
Boshen cc60d8d871 fix(parser): reject invalid index signature parameter types (TS1268/TS1337) (#22852)
An index signature parameter type must be `string`, `number`, `symbol`, or a
template literal type. This adds the syntactic check oxc was missing for the
direct cases:

    interface I { [x: boolean]: number; }   // now TS1268
    interface I { [x: "a"]: number; }        // now TS1337

The check accepts the valid key keywords (`string`/`number`/`symbol`/`any`) and
rejects any other keyword type (via `TSType::is_keyword`) or a literal type; the
single-parameter validation is folded into the same `match`. Non-keyword nodes
(type references, unions, templates) need type resolution and remain a checker
concern, so this is a conservative, regression-safe subset of the full rule.

parser_typescript +1 negative-pass; positive/AST stay 100%.
2026-05-31 04:57:19 +00:00
Boshen 3d13e293e4 fix(parser): reject declare in an already-ambient context (TS1038) (#22850)
A `declare` modifier is redundant and not allowed when its declaration is nested
directly inside an ambient `declare namespace` / `declare module` body (TS1038).
A top-level `declare` in a `.d.ts` file stays valid:

    declare namespace N { declare function f(): void; }  // now TS1038
    declare module "m" { declare function f(): void; }   // now TS1038

    // foo.d.ts
    declare function f(): void;                            // valid (top level)
    namespace N { declare function f(): void; }           // valid (non-ambient namespace)

Checked in `parse_ts_declaration_statement` against the enclosing context captured
before the declaration unions in its own ambient flag: `declare` modifier present,
`reserved_ctx.has_ambient()`, and `!reserved_ctx.has_top_level()`. The
`has_top_level()` guard is what exempts a `.d.ts` source file (whose parent is the
SourceFile, not a module block) while still covering internal namespaces and
external `declare module "x"` bodies. No valid construct has
`declare + ambient + !top_level`, so there is no positive regression.

Two linter fixtures used a redundant nested `declare` and are updated to valid TS
(`no_namespace`, `prefer_namespace_keyword`).

parser_typescript +9 negative-pass; positive/AST stay 100%.
2026-05-30 09:58:14 +00:00
Boshen 51528545ea fix(parser): reject statements in ambient contexts (TS1036) (#22849)
A non-declaration statement (`if`/`for`/`while`/expression/`try`/block/etc.) is not
allowed directly inside an ambient block — a `.d.ts` top level or a `declare`
namespace/module body:

    declare namespace M { while (true); }   // now TS1036
    // foo.d.ts
    foo();                                    // now TS1036

    declare namespace M { export const x = 1; }  // declarations stay valid
    namespace N { while (true); }                // non-ambient namespace: valid

Implemented inline in `parse_directives_and_statements`. Ambient-ness is captured
once at block entry (`(is_top_level || in_ts_namespace_body) && has_ambient()`),
which excludes function bodies (they report TS1183 for the body instead) and keeps
non-ambient blocks unaffected. A statement is flagged when it is neither a
`Declaration` nor a `ModuleDeclaration` (so imports/exports keep their specific
namespace diagnostics). The error is reported once per block, matching tsc's
`checkGrammarStatementInAmbientContext`. The hot path is unchanged: `has_ambient()`
short-circuits for all non-ambient code.

Three linter fixtures used invalid ambient statements and are updated to valid TS:
`no_shadow` (`declare; foo5: boolean;` -> `declare var foo5: boolean;`),
`check_tag_names` (a `.d.ts` block -> `declare namespace`), and
`prefer_namespace_keyword` (an assignment in a module body -> an ambient binding).

parser_typescript +18 negative-pass; positive/AST stay 100%.
2026-05-30 08:08:44 +00:00
Boshen 4f9afc56bd fix(parser): reject export as namespace inside a namespace body (TS1316) (#22846)
`export as namespace X` declares a UMD global export, which may only appear at the
top level of a module or a `.d.ts` file. Inside an internal `namespace`/`module`
body it is invalid:

    namespace N { export as namespace N; }          // now TS1316
    module M { export as namespace M; }             // now TS1316
    declare namespace N { export as namespace N; }  // now TS1316

    export as namespace Lib;                         // top level → still valid

This extends the namespace-body validation (`check_namespace_body_statement`) with
a `TSNamespaceExportDeclaration` arm emitting TS1316 ("Global module exports may
only appear at top level."), matching tsc and babel. The statement is already
checked inline as each direct child of the namespace body is parsed, so there is
no extra pass. External module declarations (`declare module "x" {}`) are left
unrestricted, consistent with the existing namespace-body checks.

parser_babel +1 negative-pass; positive/AST stay 100%.
2026-05-30 04:29:50 +00:00
Boshen 2eafea6681 fix(parser): reject function implementations in ambient contexts (TS1183) (#22845)
A function declaration with a body is an implementation, which is not allowed in
an ambient context. oxc already emitted TS1183 ("An implementation cannot be
declared in ambient contexts") when the function carried its own `declare`
modifier, but missed functions that inherit the ambient context from an enclosing
`declare module` / `declare namespace` or a `.d.ts` file:

    declare module "m" { function f() {} }   // now TS1183
    declare namespace N { function f() {} }  // now TS1183
    // foo.d.ts
    function foo(): any {}                    // now TS1183

Bodyless signatures stay valid (`declare module "m" { function f(): void; }`,
`export declare function f(): void;`).

The check now keys solely off `ctx.has_ambient()` instead of the function's own
`declare` modifier, scoped to function declarations. Class methods are excluded
because they are already validated in `check_method_definition`, which avoids a
duplicate diagnostic. This matches `typescript-go`'s
`checkGrammarStatementInAmbientContext` / function-like body check, and babel.

The fast path is unchanged: `has_ambient()` is a cheap bitflag test that
short-circuits for all non-ambient code.

parser_babel +3 and parser_typescript +1 negative-pass; positive/AST stay 100%.
2026-05-30 03:15:38 +00:00
Boshen c645615002 fix(parser): reject incompatible class member modifiers (#22843)
`static`/`abstract` and `declare`/`override` are mutually exclusive in either
order (TS1243):

- `static abstract m()` / `abstract static m()`
- `declare override x` / `override declare x`

oxc already validated modifier order (TS1029) and duplicates (TS1030). This extends
the existing `ILLEGAL_PRECEDING_MODIFIERS` table in both directions for these pairs
and reports them as "cannot be used with" (TS1243) rather than "must precede" — the
fast path is unchanged (still a table lookup + AND); only the cold error path picks
the message.

Matches babel and TypeScript: parser_babel +1 negative-pass
(`class/modifiers-incompatible`), positive/AST stay 100% across all suites, and the
correct TS1243 diagnostic is now emitted on existing TypeScript cases.
2026-05-30 02:23:40 +00:00
Boshen 276b78bd84 fix(parser): reject module-referencing imports/exports in a namespace body (#22836)
Inside an internal `namespace N {}` / `module N {}`, statements that reference a
module are not permitted — this matches both babel and TypeScript:

- `import ... from "m"` / `import x = require("m")`  → TS1147
- `export ... from "m"` / `export * from "m"`         → TS1194
- `export default ...`                                → TS1319
- `export = ...`                                       → TS1063

Bare `export { x }` (re-export of locals, no module source) and `import x = A.B`
(entity alias) stay valid, as do external modules (`declare module "x" {}`) where
these forms are allowed — the check only runs for internal namespaces.

Each statement is validated inline as the namespace body is parsed (no second pass).

Also removes TS1147 from the coverage denylist (`NOT_SUPPORTED_ERROR_CODES`), since
oxc now detects it.

Conformance: parser_babel +8 and parser_typescript +9 negative-passes vs main, with
positive/AST staying 100% across all parser suites (no regressions).
2026-05-29 15:35:20 +00:00
leaysgur 5733868456 refactor(formatter_core,formatter,formatter_json): share Expand and BracketSpacing options (#22821)
We chose `core` as the location for duplicate `struct`s, but the final options will continue to be built by each formatter.
2026-05-29 09:13:38 +00:00
Boshen dc6ebb9bcb fix(coverage): respect // @alwaysStrict variants in TypeScript test suite (#22806) 2026-05-29 04:11:40 +00:00
leaysgur c323187f37 refactor(formatter): Split oxc_formatter and oxc_formatter_core (#22611)
Split `oxc_formatter` into:

- `oxc_formatter(_js)`: JS/TS specific formatter, comment handling, sortImports, jsdoc, etc
- `oxc_formatter_core`: Language agnostic IR, printer, etc

The naming convention is different from Biome or Ruff (they do not have `_core`, and `_formatter` is equivalent to the core), but this is because in Oxc, items without `_js` are the default.

As a basic task, I have added `Context` as a generic to all relevant parts to ensure support for multiple languages.

There might still be other components that could be refactored into the core, but I would like to finish them as I implement support for other languages.

Also moved some shared utilities to the core in advance.
2026-05-29 00:49:49 +00:00
Boshen 842ed1c981 fix(parser): parse class implements with implements as the class name (#22801) 2026-05-28 14:55:00 +00:00
Boshen 18079db1d4 fix(coverage): increase rayon worker stack to 8 MB (#22790)
## Summary

`cargo coverage` (a.k.a. `just c`) crashes locally on macOS with `fatal runtime error: stack overflow` while running `semantic_typescript` on `typescript/tests/cases/compiler/binderBinaryExpressionStressJs.ts`. That fixture builds a ~1500-deep left-leaning `BinaryExpression` chain (`0 + 1 + 2 + ... + 1499`).

macOS's `std::thread` default stack is 2 MB; Linux is 8 MB, which is why CI doesn't see this. The file used to fit because `OxcDiagnostic` was 8 bytes (`Box<OxcDiagnosticInner>`); after #22406 inlined the ~200-byte inner, every recursive frame holding a diagnostic grew, pushing past 2 MB on macOS.

This sets the rayon pool's `stack_size` to 8 MB to match Linux's default. Scope is limited to the dev coverage task — the perf win from #22406 is preserved, and no runtime consumers (parser, semantic, oxlint, oxfmt) are affected.

Verified `just c` runs end-to-end on macOS after the change.
2026-05-28 09:48:53 +00:00
Cameron e1d064e498 fix(transformer/class-properties): reparent lifted private method helpers (#22716)
## Summary

Fixes semantic scope metadata for private method helper functions that
are lifted out of classes nested inside static field initializers.

The class-properties transform converts a private method into a helper
function declaration and emits that helper outside the class. For a
nested class inside a static field initializer, `current_scope_id()`
points at the nested class scope, but the helper is actually emitted
into the surrounding hoist scope. That made semantic rebuild disagree
with the transformed AST.

## Before

```js
class Outer {
  static value = class Inner {
    static #method() {}
  };
}
```

The helper function was reparented as if it still lived under the nested
class scope:

```mermaid
flowchart TD
  Program["enclosing hoist scope"] --> Outer["Outer class scope"]
  Outer --> Field["static field initializer"]
  Field --> Inner["Inner class scope"]
  Inner --> Helper["lifted helper function scope"]
  Helper -.-> Problem["incorrect parent + strict-mode source"]
```

In code, the old logic always used the current scope and current scope
flags:

```rust
let new_parent_id = ctx.current_scope_id();
ctx.scoping_mut().change_scope_parent_id(scope_id, Some(new_parent_id));
let make_sloppy_mode = !ctx.current_scope_flags().is_strict_mode();
```

That is correct for normal private methods, but not for private methods
inside a class expression that appears in a static field initializer.

## After

When the transform is running under a static `PropertyDefinitionValue`,
the helper is parented to the current hoist scope instead:

```rust
let new_parent_id = if Self::is_inside_static_property_initializer(ctx) {
    ctx.current_hoist_scope_id()
} else {
    ctx.current_scope_id()
};
ctx.scoping_mut().change_scope_parent_id(scope_id, Some(new_parent_id));
let make_sloppy_mode = !ctx.scoping().scope_flags(new_parent_id).is_strict_mode();
```

The predicate checks the field is actually static:

```rust
matches!(ancestor, Ancestor::PropertyDefinitionValue(property) if *property.r#static())
```

The resulting scope shape now matches where the helper is emitted:

```mermaid
flowchart TD
  Program["enclosing hoist scope"] --> Helper["lifted helper function scope"]
  Program --> Outer["Outer class scope"]
  Outer --> Field["static field initializer"]
  Field --> Inner["Inner class scope"]
```

The strict/sloppy adjustment also reads from the selected parent scope,
so the helper's flags match the output location rather than the original
nested class context.

## Validation

- `just fmt`
- `cargo test -p oxc_transformer`
- `just coverage` was run before review. It aborted later with a stack
overflow / signal 6 in `target/coverage/oxc_coverage`; before the abort,
the targeted `semantic_test262` failures were removed from the generated
snapshot output.

AI assistance: Codex was used to cherry-pick, review, test, and draft
this PR description.
2026-05-26 13:44:11 +08:00
oxc-guard[bot] 50baca037c chore(submodules): update submodule SHAs to latest commits (#22721)
Updates submodule dependencies to their latest commits.

## Changes

- test262: `78fc3f8` → `7e115f4`
- babel: `3d34928` → `d9fe348`
- TypeScript: `f350b52` → `e5509e2`
- estree-conformance: `576e7d8` → `faf089d`


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-05-25 22:16:39 +08:00
sapphi-red 661132d5ac feat(parser): more friendly error messages for rest assignment target and rest binding element (#22719)
Made the errors for `({...[]} = {});` and `const {...[]} = obj;` a bit more easier to understand:

```
  × Invalid rest element target in destructuring assignment
   ╭─[misc/fail/rest-assignment-target.js:1:6]
 1 │ ({...[]} = {});
   ·      ──
   ╰────
  help: Expected an identifier or member expression, like `...rest` or `...obj.prop`.
```

```
  × Invalid rest element target in destructuring pattern
   ╭─[misc/fail/rest-binding-element.js:1:11]
 1 │ const {...[]} = obj;
   ·           ──
   ╰────
  help: Expected an identifier, like `...rest`.
```
2026-05-25 12:47:34 +00:00
camc314 e184f74d11 fix(parser): improve invalid import property access diagnostic (#22693)
This improves the parser diagnostic for invalid `import.<property>` access.

Previously, invalid properties like `import.sync("baz")` were reported as if only `import.meta` were valid, which is misleading now that `import.source()` and `import.defer()` are also supported.

Before:

```text
  × The only valid meta property for import is import.meta
    ╭─[index.ts]
 37 │
 38 │ import.foo();
      ──────────
 39 │
    ╰────
```

After:

```text
  × The only valid property accesses on import are `import.meta`, `import.source()`, and `import.defer()`
    ╭─[index.ts]
 37 │
 38 │ import.foo();
      ──────────
 39 │
    ╰────
```

Also adds a coverage fixture for the `import.sync("baz")` case and updates the parser coverage snapshots.
2026-05-25 09:58:50 +00:00
camc314 7baed9c4b7 fix(transformer/private-method): clear inherited strict flags (#22508)
Fixes private method transforms so scopes inherited from a transformed private method are converted back to sloppy mode when the surrounding scope is sloppy.

Previously we only cleared `StrictMode` on the private method function scope itself. That left child scopes, such as async/generator wrapper scopes, marked as strict even though the transformed output is no longer inside a class method. This caused semantic rebuild mismatches across Babel and Test262 coverage.

Nested classes are still left strict, since class bodies are always strict mode.
2026-05-25 09:39:48 +00:00