Commit Graph

63 Commits

Author SHA1 Message Date
camc314 32d00c55bc fix(codegen): preserve instantiation expression precedence (#26424)
Preserve parentheses around TypeScript instantiation expressions in postfix contexts. Previously, `(f<T>).x` and `(f<T>)[x]` were emitted as `f<T>.x` and `f<T>[x]`, producing invalid syntax or changing how the expression is parsed.

The printer now respects the surrounding precedence while retaining grouping for lower-precedence operands.
2026-09-07 18:20:11 +00:00
camc314 b156333a23 fix(codegen): order accessibility before abstract on accessors (#26392)
Codegen emits invalid TypeScript when an abstract accessor has an explicit accessibility modifier. Both normal and minified output put `abstract` before `public` or `protected`, causing TS1029 because accessibility must precede `abstract`.

For this valid input:

```ts
abstract class C {
  public abstract accessor x: number;
  protected abstract accessor y: string;
}
```

The previous output reordered the members to:

```ts
abstract public accessor x: number;
abstract protected accessor y: string;
```

`AccessorProperty::gen` now prints accessibility before `abstract`, matching the neighboring method and property emitters and preserving the input's valid modifier order. The same ordering applies in minified output:

```ts
abstract class C{public abstract accessor x:number;protected abstract accessor y:string}
```

The change is confined to accessor modifier ordering; subsequent `static`, `override`, and `accessor` emission remains unchanged.
2026-09-07 13:27:26 +00:00
camc314 2da73b7824 fix(codegen): print matching quoted import names as identifiers (#26386)
Codegen omitted the alias whenever an imported name matched its local binding, comparing the decoded names without accounting for whether the imported name was a string literal. That produces invalid syntax for quoted import names, which require an explicit `as` binding:

```js
// Input
import { "foo" as foo } from "m";

// Before
import { "foo" } from "m";

// After
import { foo } from "m";

// After, minified
import{foo}from"m";
```

When a string-literal import name matches the emitted local binding name, print the local binding directly and use identifier shorthand. The matching binding already supplies a valid identifier, so this does not need a separate identifier-validity check or an AST mutation. The conversion applies in both default and minified output.

The comparison uses the decoded string value, so escaped names and Unicode names can also use shorthand. Declaration-level and inline type imports follow the same rule:

```ts
// Input
import { "a\u0062" as ab } from "m";
import { "π" as π } from "m";
import type { "Foo" as Foo } from "types";
import { type "Bar" as Bar } from "types";

// After
import { ab } from "m";
import { π } from "m";
import type { Foo } from "types";
import { type Bar } from "types";
```

Quoted names that differ from their local binding retain their quotes and aliases, including `"foo-bar" as foo`, `"" as foo`, and `"default" as foo`. Ordinary identifier imports retain the existing shorthand behavior.
2026-09-07 09:58:17 +00:00
overlookmotel b4e6a9e717 fix(codegen): output newline after export default interface (#25487) 2026-08-11 08:01:54 +00:00
camc314 d07a293d12 fix(codegen): preserve cast parentheses in conditional tests (#25115)
## Summary

- preserve parentheses around as and satisfies expressions used as conditional tests
- prevent a following regular expression consequent from being parsed as part of the type expression
- add regression coverage for both TypeScript expression forms

Part of #25111.
Closes #25114.
2026-08-09 12:26:21 +00:00
camc314 8b7d4419ef fix(codegen): preserve satisfies parentheses before bitwise operators (#25113)
## Summary

- preserve parentheses around a satisfies expression used as the left operand of bitwise OR or AND
- prevent the operator from being consumed as part of the satisfies type
- add regression coverage for both operators

Part of #25111.
Closes #25112.
2026-08-09 12:15:44 +00:00
camc314 4d723caaff fix(parser): report TS1035 for quoted module names (#25305)
Quoted module names are only valid in ambient contexts in TypeScript, but we were accepting them in regular TypeScript files.

This reports TS1035 when a quoted module name appears outside a declaration file or ambient declaration. The conformance snapshots now cover both TypeScript cases, and the old invalid codegen fixture has been replaced with a valid internal module declaration.
2026-08-05 10:21:52 +00: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
Boshen f5721c29f7 fix(codegen): preserve parentheses around intrinsic type reference (#23156)
At the top of a type alias body, a bare `intrinsic` is parsed as the `intrinsic` keyword, whereas `(intrinsic)` is a reference to a type named `intrinsic`. TypeScript treats these differently:

- `type T = intrinsic` → `intrinsic` keyword (TS2795)
- `type T = (intrinsic)` → type reference (TS2304)

With `preserve_parens: false`, the parser drops the `TSParenthesizedType` wrapper, leaving a bare `intrinsic` identifier reference. Codegen then printed `type t = intrinsic;`, which is reparsed as the keyword — a semantic change.

Fix: in `TSTypeAliasDeclaration` codegen, wrap the type annotation in parentheses when it is a bare `intrinsic` identifier reference (no type arguments, not qualified).

Closes #22216
2026-06-09 15:57:12 +00:00
Boshen 556acdce30 fix(codegen): parenthesize TS-cast assignment targets (#23112)
A TypeScript wrapper used as an assignment target — `(x as T) = v`, `(x satisfies T) = v`, `(<T>x) = v` — must keep its parentheses, otherwise codegen emits invalid output such as `x as T = v`.

`AssignmentTarget`'s codegen printed the simple target at `Precedence::Comma` (1), too low to make the wrapper parenthesize itself: `TSAsExpression` / `TSSatisfiesExpression` wrap at `>= Compare` (13) and `TSTypeAssertion` at `>= Prefix` (18). So the parentheses were dropped and the output no longer re-parsed.

It now passes the minimal precedence that forces each wrapper to wrap — `Compare` for `as` / `satisfies`, `Prefix` for the angle-bracket type assertion.

Surfaced while round-tripping code through `oxc_react_compiler`, but it is a general codegen bug affecting any TS-cast assignment target.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-06-08 09:22:17 +00:00
Boshen a4b1bf7337 fix(codegen): drop redundant whitespace in minified TypeScript output (#23038)
Removes redundant whitespace from minified output across many TypeScript constructs. Each change is minify-only: pretty-print output is byte-identical, all outputs round-trip, and a conservative `type_starts_with_non_identifier` helper only drops a space when the following token definitely begins with punctuation.

### Fixes

- **Decorators** — `@dec()class`, `export@dec class`, `accessor#x`
- **`as` / `satisfies`** — `foo()as X`, `` `s`as const ``, `as{a:1}`, `as(x)=>y`, `as[T]`
- **Non-null `!`** — `opts!.x`, `x!;`, `a!()`; the separator is kept only before `=`/`==`/`===` (which would retokenize as `!=`/`!==`), in both binary and assignment positions
- **`enum`** — `enum E{…}`
- **Conditional types** — `T extends[U]?X:Y`, `Foo<T>extends…`; the `? ?C` separator is preserved for a prefix JSDoc-nullable true branch
- **Heritage & constraints** — `class A<T>extends B<T>implements I`, `interface I<T=string>extends…`, `<T extends[a,b]>`
- **Type operators / constructors** — `readonly[…]`, `keyof[a,b]`, `readonly(keyof T)[]`, `new()=>T`, mapped-type `readonly[P in …]`, `export type*from`

### Verification

A whitespace analyzer over ~400 real-world `.ts` files went from **1410 → 4** removable spaces. The remaining 4 are a deliberate `i-->0` tie (handled elsewhere) and two higher-risk edge cases (`f<T>,` instantiation, mapped `in` before a template literal).

`oxc_codegen` and `oxc_minifier` suites pass, `just minsize` shows no drift, clippy is clean, and regression tests were added for each construct.
2026-06-07 02:42:28 +00:00
Boshen 325c94fefb fix(codegen): tighten conditional-type and constructor-type whitespace when minifying (#23033)
## What

Batches the remaining low-risk TS-minify whitespace patterns surfaced by the whitespace analyzer.

### Conditional types
`?`/`:` are now tight when minifying, like a JS conditional expression:

| Input | Before | After |
| --- | --- | --- |
| `A extends B ? C : D` | `A extends B ? C : D` | `A extends B?C:D` |

The leading `extends` space is emitted only when the check type ends in an identifier (so `T extends …` keeps it, `{} extends …` doesn't). The space *after* `extends` is kept to avoid merging a following type keyword (`keyof`, etc.).

### Constructor types
No space after `new` before `(`/`<`:

| Input | Before | After |
| --- | --- | --- |
| `new () => Foo` | `new () => Foo` | `new()=>Foo` |
| `abstract new (x: number) => Foo` | `abstract new (x: number) => Foo` | `abstract new(x:number)=>Foo` |

Pretty-print output is unchanged; `ts` minify snapshot updated. Verified round-trip.
2026-06-06 18:14:46 +00:00
Boshen 90180b8b37 fix(codegen): drop space after : in function return type when minifying (#23028)
## What

Found with the whitespace analyzer run over TypeScript sources. `Function` return-type annotations and `TSThisParameter` printed a hardcoded `": "`, so minified TS had a stray space — and inconsistent with methods/arrows which were already tight:

| Input | Before | After |
| --- | --- | --- |
| `function f(): Promise<void> {}` | `function f(): Promise<void>{}` | `function f():Promise<void>{}` |
| `function h(this: Foo): void {}` | `function h(this: Foo): void{}` | `function h(this:Foo):void{}` |
| `class C { m(): void {} }` | `m():void{}` (already tight) | `m():void{}` |

## Fix

Replace `print_str(": ")` with `print_colon()` + `print_soft_space()` (the soft space is dropped when minifying, kept when pretty-printing) — the same form methods, arrows, and parameter annotations already use. Pretty-print output is unchanged; the `ts` minify snapshot is updated.
2026-06-06 17:29:42 +00:00
Boshen cb299261f2 fix(codegen): drop redundant space after export default when minifying (#23024)
## What

Found with a self-written whitespace analyzer (for each space in oxc's minified output, remove it and check the result still canonicalizes to the same AST — if so the space was non-optimal). The most common hit:

`ExportDefaultDeclaration` printed `"export default "` with an unconditional trailing space, kept before non-identifier values when minifying:

| Input | Before | After |
| --- | --- | --- |
| `export default {a:1}` | `export default {a:1}` | `export default{a:1}` |
| `export default [1]` | `export default [1]` | `export default[1]` |
| `export default (a,b)` | `export default (a,b)` | `export default(a,b)` |
| `export default "s"` | `export default "s"` | ``export default`s` `` |

## Fix

Use a soft space (kept when pretty-printing) and let the value insert a hard space only before an identifier-like token — matching how `return` already works, and esbuild's `SExportDefault` printer (`print("export default")` + `printSpace()`).

Spaces that are required are preserved: `export default function(){}`, `export default 5`, `export default foo`, `export default class C{}`.

### TypeScript

Exposed a latent bug: `TSInterfaceDeclaration` printed `interface` without a `print_space_before_identifier()` guard, so `export default interface I {}` would have minified to `export defaultinterface`. Added the guard (same fix as #23013 for enums). `export default interface`, `export default abstract class`, and `export default <const>x` all verified to round-trip.

Pretty-print output is unchanged. Codegen (115) and minifier (506) suites pass.
2026-06-06 16:04:27 +00:00
Boshen 8b631bfeca fix(codegen): remove stray space before mapped type value colon (#23010)
## What

`TSMappedType` printed a `soft_space` immediately before the value colon, so the colon was spaced off from the key:

| Input | Before | After |
| --- | --- | --- |
| `{ [K in U]: V }` | `{ [K in U] : V }` | `{ [K in U]: V }` |
| `{ [K in U]?: V }` | `{ [K in U]? : V }` | `{ [K in U]?: V }` |
| `{ -readonly [K in U]-?: V }` | `{ -readonly [K in U]-? : V }` | `{ -readonly [K in U]-?: V }` |

Every other member colon (object types, interfaces) is printed as `key: value`; mapped types now match. Minified output was already correct (`[K in U]?:V`).

The stray `print_soft_space()` before `print_colon()` is removed.
2026-06-06 11:23:46 +00:00
Boshen 600cd6f400 fix(codegen): parenthesize lower-precedence TSInstantiationExpression operand (#23007)
## What

A type-instantiation expression `expr<T>` forwarded the incoming precedence to its operand, so a lower-precedence operand wasn't parenthesized. `(a ?? b)<T>` was emitted as `a ?? b<T>`, which re-parses as `a ?? (b<T>)` — the `<T>` binds to `b` instead of the whole `a ?? b`, a **different AST**.

The operand of `expr<T>` is a member/LHS expression, so it's now printed at `Precedence::Prefix`, wrapping lower-precedence operands while leaving member/call operands bare.

## Examples

| Input | Before | After |
| --- | --- | --- |
| `(a ?? b)<T>` | `a ?? b<T>` ❌ | `(a ?? b)<T>` ✅ |
| `(a + b)<T>` | `a + b<T>` ❌ | `(a + b)<T>` ✅ |
| `(a as B)<T>` | `a as B<T>` ❌ | `(a as B)<T>` ✅ |
| `(-a)<T>` | `-a<T>` ❌ | `(-a)<T>` ✅ |

Member/call operands keep needing no parentheses: `a.b<T>`, `f<T>`, `a()<T>`.

`Prefix` (not `Postfix`) is used so the pure-annotated-call wrap rule isn't triggered — `(() => {})()<X>` stays as-is rather than gaining redundant parens.
2026-06-06 08:25:29 +00:00
Boshen 294c473696 fix(codegen): don't over-parenthesize TSTypeAssertion operand (#23004)
## What

The operand of an angle-bracket assertion `<T>x` is a `UnaryExpression` (TS grammar: `< Type > UnaryExpression`), but codegen printed it at `Precedence::Member`. That wrapped **every** unary operand in redundant parentheses.

It now prints the operand at `Precedence::Exponentiation` — exactly what `UnaryExpression::gen_expr` uses for its own argument — so a `UnaryExpression` operand stays bare while looser operands (binary, conditional, `**`) are still wrapped.

## Examples

| Input | Before | After |
| --- | --- | --- |
| `<T>-x` | `<T>(-x)` | `<T>-x` |
| `<T>typeof x` | `<T>(typeof x)` | `<T>typeof x` |
| `<T><U>x` | `<T>(<U>x)` | `<T><U>x` |
| `<T>x()` | `<T>(x())` | `<T>x()` |

Operands that genuinely require parentheses keep them:

| Input | Output |
| --- | --- |
| `<T>(b + c)` | `<T>(b + c)` |
| `<T>(d ** e)` | `<T>(d ** e)` |
| `<T>(h ? i : j)` | `<T>(h ? i : j)` |

Follow-up to #23002.
2026-06-06 07:51:38 +00:00
Boshen 786d96f210 fix(codegen): give TSTypeAssertion unary precedence (#23002)
## What

A TS angle-bracket assertion `<T>x` is a unary expression (ECMA/TS grammar: `< Type > UnaryExpression`), but `TSTypeAssertion::precedence()` returned `Precedence::Lowest`. The wrap condition `precedence >= self.precedence()` is therefore always true, so the assertion was parenthesized in **every** position.

It now reports `Precedence::Prefix` like other unary expressions, and joins the `**`-base special case (a unary expression can't be a `**` base, so it must stay wrapped there).

## Examples

| Input | Before | After |
| --- | --- | --- |
| `y = <T>x` | `y = (<T>x)` | `y = <T>x` |
| `foo(<T>x)` | `foo((<T>x))` | `foo(<T>x)` |
| `z = <T>x + 1` | `z = (<T>x) + 1` | `z = <T>x + 1` |
| `c = -<T>x` | `c = -(<T>x)` | `c = -<T>x` |

Positions that genuinely require parentheses still keep them, because they print the assertion at a higher precedence than `Prefix`:

| Input | Output |
| --- | --- |
| `(<T>x).foo` | `(<T>x).foo` |
| `(<T>x)()` | `(<T>x)()` |
| `(<T>x) ** 2` | `(<T>x) ** 2` |
2026-06-06 07:44:12 +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
camc314 5f28a3f57b fix(codegen): print type param on class expression with no id (#20144) 2026-03-09 10:35:58 +00:00
camc314 36b2e56910 fix(codegen): print type for TSImportEqualsDeclaration (#20128) 2026-03-09 00:59:52 +00:00
camc314 5a246ec848 fix(codegen): print type arguments for JSXOpeningElement (#20127) 2026-03-09 00:59:52 +00:00
camc314 a40870e838 fix(codegen): preserve parens for TSNonNullExpression (#20125) 2026-03-09 00:59:52 +00:00
camc314 ae830b2466 fix(codegen): print declare for TSInterfaceDeclaration (#20124) 2026-03-09 00:59:52 +00:00
Dunqing 588009ed65 fix(codegen): print static keyword for TSIndexSignature (#19755)
The codegen was missing the `static` keyword when printing `TSIndexSignature`
nodes, causing `static [key: string]: string` index signatures to lose the
`static` modifier during code generation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 16:25:56 +00:00
camc314 abc7e19b98 fix(codegen): improve parenthesised checks when printing types (#19880) 2026-03-02 02:18:36 +00:00
Dunqing 1710f56360 fix(codegen): remove double indentation for enum inside namespace (#19775)
## Summary

- `TSEnumDeclaration::gen()` called `p.print_indent()`, but the `Statement` handler already calls `print_indent()` before dispatching — causing enums inside namespaces to get double indentation (e.g. 4 spaces instead of 2).
- No other declaration type (`Class`, `TSModuleDeclaration`, `TSInterfaceDeclaration`, `TSTypeAliasDeclaration`) has this issue.

**Before:**
```ts
declare namespace ns {
  class Foo {}
    enum Bar {}
  type Baz = undefined;
}
```

**After:**
```ts
declare namespace ns {
  class Foo {}
  enum Bar {}
  type Baz = undefined;
}
```

## Test plan

- [x] Added `test_same` case for `declare namespace` with class, enum, and type alias
- [x] Verified test fails without the fix, passes with it
- [x] All 92 `oxc_codegen` tests pass

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-02-27 12:24:26 +00:00
camc314 9e4995cd3d fix(codegen): print type annotation on CatchParameter (#19790) 2026-02-27 08:28:13 +00:00
camc314 297b2bbe10 fix(codegen): wrap TSConditionalType in parens when necessary (#19788) 2026-02-27 08:28:12 +00:00
camc314 cec7878b6c fix(codegen): print definite property on AccessorProperty (#19786) 2026-02-27 08:28:12 +00:00
camc314 6f395cff26 fix(codegen): print definite property on PropertyDefinition (#19785) 2026-02-27 08:28:12 +00:00
camc314 b74937317b fix(codegen): correctly parenthesise TSArrayType (#19784) 2026-02-27 08:28:11 +00:00
camc314 876dc1b0d6 fix(codegen): print object property this param (#19783) 2026-02-27 08:28:11 +00:00
Dunqing ed17bbfff6 fix(codegen): print override keyword for method and property definitions (#19753)
## Summary
- Add `override` keyword printing for `MethodDefinition` and `PropertyDefinition` in codegen
- Previously, class members with the `override` modifier would silently drop the keyword during code generation

## Test plan
- [x] Added `test_same` cases for `override` on methods and properties
- [x] Passes `cargo clippy` and existing tests

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-02-26 13:43:52 +00:00
Boshen 06bd17be03 fix(codegen): remove unnecessary double parentheses from satisfies expressions (#17986)
## Summary
- Fixed `TSSatisfiesExpression` to only add parentheses when precedence requires it
- Before: `((x) satisfies y)`, After: `x satisfies y`
- Aligned implementation with `TSAsExpression` pattern
- Added idempotency tests to ensure semantic correctness

## Test plan
- [x] Added `ts_satisfies_expression` test with 9 idempotency test cases
- [x] All codegen tests pass
- [x] Clippy passes

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-01-14 08:57:39 +00:00
camc314 c32e8d5b8f fix(codegen): wrap TSAsExpression in parens when used with in/instanceof operators (#17752) 2026-01-08 12:34:40 +00:00
Copilot 5233d737c4 test(codegen): Add regression tests for TSImportType string literal output (#16120)
PR #16114 fixed TSImportType codegen to prevent backticks in minified
output (which produces invalid TypeScript). This adds regression tests
to ensure the fix persists.

## Changes

- Added 4 test cases covering TSImportType variants:
  - Basic import types with single/double quotes
  - Import types with qualifiers (`.SomeType`)
  - Import types with type arguments (`<string>`)
- Tests verify both normal and minified output via snapshots

## Example

Input:
```typescript
type T = typeof import('react');
```

Minified output (now tested):
```typescript
type T=typeof import("react");  // ✓ double quotes, not backticks
```

The minify snapshot ensures backticks are never used, preventing invalid
TS like `import(\`react\`)`.

<!-- START COPILOT CODING AGENT SUFFIX -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>Codegen: Do not use backticks when printing argument of
`TSImportType`</issue_title>
> <issue_description>Input:
> 
> ```ts
> type T = typeof import('react');
> ```
> 
> Codegen output (with `minify: true`):
> 
> ```ts
> type T=typeof import(`react`);
> ```
> 
>
[Playground](https://playground.oxc.rs/#eNptU01rGzEQ/StGl7TgQhooBJceSlJDIW3SJjSXXma1s44SrUYdzcY2xv+9o/VKTiCn1b7RfLw3TztjzcLINuLsbvZllg/UzVwfieXdCSNYOXn/+W8wc0NmsTM8hPzxLohZdOATzk1H3IMIckWEIaQMV8Ql8iDYXqL1wCCOQqrB9YMTTBEsmoXwoEgPYeX1b7pgqY+M6ZiRLMV6OW37hnz5s91qurafmwic8lw7gxvBkLRtppuUDnhP698oA4frQZJrcTkEmwcrlXJL5Ge8AdbUgo55f86/B2GnBW0NJNSpxdlvzMQTqiNkqcYR9PxCqZ0ZEt5Bc+Qk0Ny7Vh7M4mxuMLTX3ZULStL4TseN2k2m+PmpdnNZoV8DyVGmx7S5fQP+l/9umKL2MpA+BMQWW62pa3I63uqC+h5yzHtFlYerZJXLuvDX+Bq2WbuGwT6h3OrKNL1cLij0eJh86k/NI1q5Z4hao4iaG42zfhUVshl0QuRXabiJyK7HIOCv9QhCfEPJHVaUFTIqabXaQVQBXqFa02A6O/34SbuozJfYaeEl8YWHlJYOfVu39rKLmpPGNsdo76SiP1CgBVGlptW+beqdScooqkGQA6gvixkttbjC8f2EbIRq2cfUkj7DSfIQSMZaBfG4KnfHKuUtZEeVh6LMKV7hM9aiT4jxp66iGGxMVdOSX6qBc8YzckOpCJ75hLyoHKqnvcLtKF+G62mf8Sxz4bT/D3SBh38=)
> 
> This is invalid TypeScript. TS appears to require the argument to be a
string literal, and nothing else - template literal is not allowable
here.
> 
> [TS
Playground](https://www.typescriptlang.org/play/?#code/C4TwDgpgBAglC8VSQPYDMoEsC2YUCdgAKAA3wgEMBjYEgSgG4AoIA)
> 
> Related to oxc-project/oxc#16074.</issue_description>
> 
> <agent_instructions>The issue itself is solved. Add a test for
it.</agent_instructions>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> <comment_new><author>@overlookmotel</author><body>
> We might want to do oxc-project/oxc#16111 first. That'll make this fix
easier to implement.</body></comment_new>
> <comment_new><author>@overlookmotel</author><body>
> oxc-project/oxc#16114 should have fixed this. We just need to add a
test to make sure.</body></comment_new>
> <comment_new><author>@camc314</author><body>
> There are tests for this, they regressed after just the AST change. I
fixed them back up in 16114 to avoid the regression</body></comment_new>
> </comments>
> 


</details>

- Fixes oxc-project/oxc#16078

<!-- START COPILOT CODING AGENT TIPS -->
---

✨ Let Copilot coding agent [set things up for
you](https://github.com/oxc-project/oxc/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: overlookmotel <557937+overlookmotel@users.noreply.github.com>
2025-11-25 22:44:17 +00:00
Ives van Hoorne e2ca770f64 fix(codegen): add support for printing type arguments in new expressions (#15963)
Code that's parsed as follows:

```
const a = new Map<string, number>();
```

Is printed by codegen as follows:

```
const a = new Map();
```

While for `CallExpression` we do render them:

```
const a = test<string, number>();
```

Is rendered the same. 

This PR adds support for rendering type parameters also for new
expressions.
2025-11-24 15:49:22 +08:00
sapphi-red b3d6f45d37 test(all): check parse errors existence (#15865)
Added `assert!(ret.errors.is_empty());` in many places so that invalid inputs are caught properly.
2025-11-19 13:56:55 +00:00
Boshen 7266200faa fix(parser): parse @x() @y() export default abstract class {} (#11630)
Also took the opportunity to reduce a rewind on `export default interface`.
2025-06-12 10:00:46 +00:00
Boshen e4804bafaf fix(parser): parse decorator on abstract class (#11625) 2025-06-12 04:53:10 +00:00
camchenry 392752f63e fix(parser): handle import {type as as} correctly (#11488)
- closes https://github.com/oxc-project/oxc/issues/11484
2025-06-05 05:37:27 +00:00
Ulrich Stark fa06d7f71d feat(codegen): print override modifier of FormalParameter (#11134) 2025-05-19 22:51:27 +08:00
Boshen 751876bf6a refactor(parser): rewrite parse class element (#11035)
closes #10942
closes #11010
2025-05-14 14:44:21 +00:00
Boshen 1673ffb05a feat(codegen): rework printing normal / legal / annotation comments (#10997)
fixes #10948

This PR changes how comment options are interpreted.

`CodegenOptions::comments`, `CodegenOptions::annotation_comments` and
`CodegenOptions::legal_comments` are now independent of each other.

### `CodegenOptions::comments`

Controls printing of normal comments. At present, only some leading
comments are preserved. It does not control legal and annotation
comments.


### `CodegenOptions::annotation_comments`

Controls printing of annotation comments

* jsdoc: `/** jsdoc */`                                                 
* pure: `/* #__PURE__ */` and `/* #__NO_SIDE_EFFECTS__ */`              
* webpack: `/* webpackChunkName */`                                     
* vite: `/* @vite-ignore */`                                            
* coverage: `v8 ignore`, `c8 ignore`, `node:coverage`, `istanbul ignore`

### `CodegenOptions::legal_comments`

Controls printing of legal comments

* starts with `//!` or `/*!`.                   
* contains `/* @license */` or `/* @preserve */`

---

Comment generation is also changed:

codegen first builds a comments map by keeping only the needed comments.
Printing functions will then print out comments in their respective
positions.

---

This PR reveals some incorrect comment interpretation:  

* https://github.com/oxc-project/oxc/issues/10998
2025-05-13 19:24:42 +08:00
Boshen 2c05fa1753 fix(parser): fix rhs precedence while parsing PrivateInExpression (#10866)
fixes #10839

```
class Foo {
  #name: string;
  f() { #name in other && this.#name === other.#name }
                 ^^^^^ rhs is only this part
}

RelationalExpression[In, Yield, Await] :
  [+In] PrivateIdentifier in ShiftExpression[?Yield, ?Await]
```
2025-05-07 14:44:35 +00:00
Boshen 087af52ba9 fix(parser): set the correct context for class property definition (#10859)
fixes #10840

```
class C {
  p = await(0);
}

FieldDefinition[Yield, Await] :
  ClassElementName[?Yield, ?Await] Initializer[+In, ?Yield, ?Await]opt
```
2025-05-07 13:17:58 +00:00
Boshen 4825eb593a fix(codegen): add missing in out from ts type parameter (#10696)
```ts
interface I<in out T> {}
function F<const in out T>() {}
```
2025-04-29 14:47:11 +00:00
Boshen 06f796fd3e fix(codegen): add missing return type from object methods (#10694)
```
({ foo(): string {} })
          ^^^^^^
```
2025-04-29 13:54:10 +00:00
sapphi-red b4ee617028 feat(codegen): prefer backquotes over double / single quotes (#8839)
When thinking about why #8443 made the gzip size increased, I thought it maybe because the backquotes appear more than before the PR. So I changed the codegen to prefer backquotes than double/single quotes. It seems this separate change have a positive effect with some projects.
My guess is that in most projects, back quotes does not appear in string literals than double quotes and single quotes.

The gzipped size slightly increases for `bundle.min.js`, `victory.js`, `antd.js`, but those will be decreased by #8443 except for `bundle.min.js`.
2025-02-03 07:21:18 +00:00