Keep the initial public API limited to operations needed by consumers.
Test fixtures can build values through a private helper; unused
convenience conversions can be added when callers need them.
Implemented with AI assistance.
JavaScript strings can contain lone surrogates that Rust str cannot
represent. Introduce arena-backed primitives with explicit encoding
invariants before migrating AST consumers.
Part of #26242.
Preserve parentheses around TypeScript instantiation expressions in postfix contexts. Previously, `(f<T>).x` and `(f<T>)[x]` were emitted as `f<T>.x` and `f<T>[x]`, producing invalid syntax or changing how the expression is parsed.
The printer now respects the surrounding precedence while retaining grouping for lower-precedence operands.
Class static blocks inherit the disabled `in` context of a surrounding `for` initializer, causing valid code such as `for (class { static { a in b; } };;);` to report a missing semicolon at `in`. Enable `Context::In` while parsing the static block, with the existing context helper restoring the surrounding flags afterward.
## Problem
Named tuple rest elements bypass the parser's existing checks for optional elements after an array rest and for multiple array rests. For example, both of these declarations currently parse successfully even though TypeScript rejects them:
```ts
type OptionalAfterRest = [...a: string[], b?: number];
type RestAfterRest = [...a: string[], ...b: number[]];
```
The equivalent unnamed forms already produce TS1266 and TS1265, respectively. Mixed named and unnamed array rests have the same gap when either rest is named.
## Cause and change
`parse_tuple_type` inspects `TSRestType.type_annotation` to decide whether an element is an array rest. For a named element, that annotation is a `TSNamedTupleMember`, and the actual type is stored in its `element_type`. Matching directly on the outer annotation therefore skips the array check and fails to track the rest element.
Unwrap the named member with `as_ts_type()` before applying the existing classification. Named and unnamed elements then share the same validation and existing diagnostics:
- An optional element after an array rest reports TS1266.
- A second array rest reports TS1265, including mixed named and unnamed forms.
The diagnostic spans continue to use the complete tuple elements, including their labels. The change borrows the underlying type without changing the AST representation or introducing allocations.
## Preserved behavior
A rest marker alone does not make a spread an unbounded array. Fixed-tuple and generic variadic spreads continue to be accepted, including:
```ts
type FixedBeforeOptional = [...a: [string], b?: number];
type RestBeforeFixed = [...a: string[], ...b: [number]];
type VariadicBeforeOptional<T extends unknown[]> = [...a: T, b?: number];
type RestBeforeVariadic<T extends unknown[]> = [...a: string[], ...b: T];
type MultipleVariadic<T extends unknown[], U extends unknown[]> = [...a: T, ...b: U];
```
This change preserves the existing type-reference classification; it does not add type resolution or change how shadowed `Array` references are handled.
## Problem
A `yield` expression in a classic `for` loop initializer can lose the parentheses required around an `in` operator in its argument. This turns valid JavaScript into output that cannot be parsed, in both default and minified code generation.
For example, this input is valid:
```js
function *g(o) {
for (yield (1 in o); false;);
}
```
Previously, codegen emitted:
```js
// Default output
function* g(o) {
for (yield 1 in o; false;);
}
// Minified output
function*g(o){for(yield 1 in o;false;);}
```
The unparenthesized `in` is not allowed at this position in a classic `for` initializer. The same restriction applies to the argument of `yield*`, and can also be lost through nested yields or an assignment inside the yield argument.
## Change
`ForStatement` already prints its initializer with `Context::FORBID_IN`. However, `YieldExpression::gen_expr` ignored its incoming context and always printed its argument with `Context::empty()`.
Preserve `FORBID_IN` when printing the argument of an unwrapped yield expression. This lets the existing expression printers retain the required grouping:
```js
// Default output
function* g(o) {
for (yield (1 in o); false;);
}
// Minified output
function*g(o){for(yield(1 in o);false;);}
```
Only the relevant `FORBID_IN` flag is forwarded; the argument's existing precedence remains `Precedence::Yield`. Both `yield` and `yield*` use this path.
## Parentheses around yield
When precedence requires parentheses around the entire yield expression, those parentheses already allow `in` in the argument. Clear the restriction in that case to avoid redundant inner grouping:
```js
// Input
function *g(o) {
for ((yield (1 in o)) + 1; false;);
}
// Default output
function* g(o) {
for ((yield 1 in o) + 1; false;);
}
// Minified output
function*g(o){for((yield 1 in o)+1;false;);}
```
Outside a restricted initializer, ordinary yield expressions continue to omit unnecessary parentheses: `yield (1 in o)` prints as `yield 1 in o`.
Private-in expressions can lose required parentheses around their right-hand operand in both default and minified code generation. When the operand is another relational expression, removing the grouping changes which value the private-field check receives and can change observable behavior.
For example:
```js
class D {
#x;
test(a, b) {
return #x in (a instanceof b);
}
}
new D().test({}, Object);
```
The original throws a `TypeError`: `a instanceof b` evaluates to `true`, and the private-field check requires an object as its right-hand operand. Previously, codegen emitted:
```js
return #x in a instanceof b;
```
Relational operators associate to the left, so this is parsed as `(#x in a) instanceof b`. The private-field check on `{}` produces `false`, and `false instanceof Object` then returns `false` instead of throwing.
The corrected output preserves the grouping in both modes:
```js
// Default output
return #x in (a instanceof b);
// Minified output
return#x in (a instanceof b)
```
`PrivateInExpression::gen_expr` now prints its right-hand operand with `Precedence::Compare` instead of `Precedence::Equals`. The printer wraps expressions whose precedence is equal to or lower than the requested precedence. Using `Compare` therefore preserves parentheses around relational operands, including `<`, `<=`, `>`, `>=`, `instanceof`, and nested private-in expressions. Equality and lower-precedence expressions continue to retain their required grouping, while shift, arithmetic, and exponentiation operands can still omit unnecessary parentheses.
This addresses the RHS grouping issue separately from #26383, which fixed the precedence passed to private-in expressions appearing as the left operand of another binary expression. The change is confined to the Rust `oxc_codegen` crate.
TypeScript allows a default import binding named `type` to contain Unicode escapes. Oxc currently reports `Keywords cannot contain escape characters` for these valid imports:
```ts
import t\u0079pe from "m";
import t\u0079pe, { x } from "m";
import t\u0079pe, * as ns from "m";
```
In each example, `t\u0079pe` is an identifier whose decoded name is `type`, and the declaration is a value import.
The parser initially recognizes the decoded `type` token before it has enough context to distinguish a default binding from a type-only import modifier. The escape check ran at that point, so it rejected the binding even when the following tokens established that this was a value import.
Move the escape check into the two branches that interpret `type` as a modifier: before a named or namespace import, and before another binding identifier after ruling out `import type from "m"`. The latter check also runs before the early return for a type-only import-equals declaration.
Escaped modifiers remain invalid, including these forms:
```ts
import t\u0079pe Foo = require("m");
import t\u0079pe { x } from "m";
import t\u0079pe * as ns from "m";
import { t\u0079pe Bar } from "m";
```
The change is limited to when the declaration-level escape diagnostic is emitted; import classification and specifier parsing retain their existing behavior.
## Summary
Getter accessors must have no formal parameters, but Oxc currently accepts a getter whose only parameter is a rest parameter. This affects class and object getters, as well as getter signatures in TypeScript interfaces and type literals.
```ts
class C { get x(...args) {} }
({ get x(...args) {} });
interface I { get x(...args: any[]): string }
type T = { get x(...args: any[]): string };
```
Each declaration above previously parsed without a diagnostic. It now reports the existing error: `A 'get' accessor must not have any formal parameters.`
## Cause and correction
`FormalParameters` stores ordinary parameters in `items` and the rest parameter separately in `rest`. Both getter checks inspected only whether `items` was empty, so a rest-only parameter list looked like a zero-parameter list.
Use `parameters_count() != 0` in both checks so the count includes the rest parameter. The shared `check_getter` path covers class and object getters; `parse_getter_setter_signature_member` covers interface and type-literal getter signatures.
The diagnostic still points at the full parameter list. Zero-parameter getters remain valid, ordinary getter parameters retain their existing diagnostic, and class/object accessors with type parameters retain the current type-parameter diagnostic precedence. Setter validation is unchanged.
## Summary
Allow the `in` operator inside an arrow function’s block body when the arrow appears in a `for` initializer:
```js
for (() => { a in b; };;);
```
This is valid JavaScript, but the parser previously reported a missing semicolon at `in`. The block now parses successfully, including async arrows and arrows with a single unparenthesized parameter.
## Cause and fix
A `for` initializer disables `Context::In` so that an unparenthesized `in` can delimit a `for…in` statement. Arrow block bodies inherited that disabled context through `parse_arrow_function_expression_body`, which called `parse_function_body` directly.
The block-body branch now calls `parse_function_body` through `context_add(Context::In, ...)`. This enables `in` throughout the function body and restores the enclosing context afterward. It also permits nested concise arrows inside that block to use `in`.
The change is confined to block bodies because concise expression bodies inherit the surrounding grammar’s `In` parameter. For example, this remains invalid:
```js
for (var f = () => a in b;;);
```
Restoring the enclosing context also keeps this invalid, rather than accidentally treating `a in b` as a regular initializer expression after parsing the first arrow:
```js
for (var f = () => {}, value = a in b;;);
```
The parser currently accepts mixed nullish and logical expressions when parentheses cover only the first operand of the logical expression:
```js
(a) || b ?? c;
a ?? (b) || c;
(a) && b ?? c;
a ?? (b) && c;
```
These expressions require a syntax error because `??` cannot be mixed directly with `||` or `&&`. Parentheses around `a` or `b` do not group the complete logical expression. This change reports the existing mixed-coalesce diagnostic for all four forms.
Fully grouped operands remain valid:
```js
(a || b) ?? c;
a ?? (b || c);
(a && b) ?? c;
a ?? (b && c);
```
### Why the existing check misses these expressions
`parse_binary_expression_rest` used `lhs_parenthesized` and `rhs_parenthesized` flags captured before parsing an operand. Those flags describe whether the initial token is `(`, but the parser can subsequently accumulate a larger logical expression outside those parentheses. Applying the initial flag to that complete expression incorrectly suppresses the diagnostic.
### Complete-operand checks
Check both operands independently for an `And` or `Or` logical expression whose span starts at the operand's starting position. A logical expression accumulated outside initial parentheses starts at that position and must be rejected. Checking both operands also prevents a grouped right operand from hiding an invalid left operand.
This works with either `preserve_parens` setting. When parentheses are preserved, a fully grouped operand is a `ParenthesizedExpression`. When they are omitted, its inner logical expression retains a span beginning after the opening `(`, so its start differs from the operand start and it remains allowed. For `(a) || b`, the complete logical expression instead starts at the opening `(` and is correctly rejected.
## Summary
Fix the generated defaults for `unicorn/numeric-separators-style`. The rule already uses `number.minimumDigits: 5`, matching Unicorn, but the generated documentation and JSON schema advertise `0`. The same schema issue also advertises `groupLength: 0` for every numeric base.
## Why the defaults are wrong
`NumericBaseConfig` is shared by binary, hexadecimal, octal, and decimal configuration. Its derived `Default` initializes both numeric fields to zero. The rule supplies the actual defaults in `NumericSeparatorsStyleConfig::default()` and `NumericNumberConfig::default()`.
Schema generation uses the shared type's defaults for its individual properties. In particular, flattening `NumericBaseConfig` into `NumericNumberConfig` preserves the zero-valued property defaults instead of the decimal defaults. This makes the documented threshold disagree with the rule's existing behavior:
```js
1234; // Allowed with the default configuration.
12345; // Reported; the fix is 12_345.
```
## Change
Add a single parameterized schema helper for `NumericBaseConfig`, then select the appropriate defaults with `schemars(schema_with = ...)` on each field. The helper retains the derived schema's property descriptions, types, and constraints, and overrides only the `groupLength` and `minimumDigits` default metadata.
The resulting defaults are:
| Configuration | `groupLength` | `minimumDigits` |
| --- | --- | --- |
| `binary` | 4 | 0 |
| `hexadecimal` | 2 | 0 |
| `octal` | 4 | 0 |
| `number` | 3 | 5 |
The schema annotation on the flattened decimal base also corrects `number.minimumDigits`. `number.fractionGroupLength` remains unchanged, and the documentation continues to display its default as `Infinity`.
Regenerate the JSON configuration schema and the TypeScript configuration types from it. The generated TypeScript types inline the binary, hexadecimal, and octal option objects because those properties now have individual schemas; their accepted configuration shapes are unchanged.
This changes schema and documentation metadata only. Runtime defaults, option parsing, diagnostics, and autofixes are unchanged.
Fixes#26391
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.
Use `Ident` in the property mangler. This reduces the `Set::contains` operation faster as the hashing doesn't happen.
The property names are not always an "ident" so it may not make sense to use the `Ident` type. But currently the `Ident` type allows characters that are not allowed in identifiers so the code works.
I used AI to generate the code and then reviewed the code and iterated a bit.
Private methods lowered from a class expression inside a concise arrow
were inserted next to the arrow's outer statement, while private field
storage remained inside the arrow. Starting with Oxc 0.143, this could
leave the generated helper unable to resolve the private field and throw
a `ReferenceError` at runtime.
Concise arrow bodies have no statement list where the helper declaration
can be inserted. In that context, the helper is now emitted as an
assignment in the class-expression sequence, with its `var` binding
inside the expanded arrow body. Ordinary statement-backed class
expressions keep block-local function declarations so classes created by
repeated block evaluation retain their own captured values. The
generated symbol flags and scope parents match the emitted form in both
cases.
## Example
```js
const makeClass = () => class {
#field = 41;
#read() { return this.#field; }
run() { return this.#read() + 1; }
};
new (makeClass())().run();
```
Before Oxc emitted a helper outside `makeClass`, and the call threw
`ReferenceError: _field is not defined`. After this change it returns
`42`.
Verified with the private-method transform conformance suite, runtime
regressions for concise arrows and repeated block evaluation, `cargo
test -p oxc_transformer`, and transformer clippy.
Fixes the upstream cause of
[rolldown/rolldown#10818](https://github.com/rolldown/rolldown/issues/10818).
AI assistance: Cursor was used for the original patch; OpenAI Codex was
used for follow-up review, fixes, and testing.
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Dunqing <dengqing0821@gmail.com>
Named exports must have a string literal module source once `from` is present. The parser previously combined consuming `from` with checking whether the next token was a literal:
```rust
if self.eat(Kind::From) && self.cur_kind().is_literal()
```
When the next token was not a literal, `from` had already been consumed, but parsing fell back to a local export. This incorrectly accepted `export {} from;`, `export {} from` at EOF, and this input:
```js
export {} from
foo();
```
In the last case, the newline allowed automatic semicolon insertion, so the parser accepted a local empty export followed by `foo()` despite the incomplete `from` clause.
Remove the literal-kind guard so consuming `from` always leads to `parse_literal_string()`. That helper already requires a string literal and handles malformed input through the existing parser diagnostics. A missing source now produces a syntax error instead of becoming a local export, while unterminated strings and comments retain the standard lexer diagnostics.
Valid local exports such as `export { foo };` and re-exports such as `export { foo } from "./module.js";` keep their existing behavior, including a module source placed on the next line.
adds new helper `merge_last_expression_into_sequence` and uses it
everywhere when we want to merge last expression to target expression
`a; b;` -> `a, b;`
this change avoids creation of 2 dummy nodes and unnecessary
`drop_statement` on dummy stmt per merge
Closes out remaining spec compliance gaps in the lexer, Regex vs
Division cases, `>>` cases, + many more.
Fully passes on Test262, All Typescript tests, Oxc tests, SWC tests,
VSCode (codebase), And 1_000 machine hours of differential fuzzing;
Confidence is high that it's either 'correct' or very close.
This PR specifically needs AI Disclosure in both finding and fixing the
cases now because the bitwise logic is complex; Something that I'll
start addressing once 'correctness' is locked in (and performance).
---------
Co-authored-by: overlookmotel <theoverlookmotel@gmail.com>
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.
`ParserReturn` contains a property `panicked`.
The name `panicked` is misleading. The parser did _not_ panic. When `true`, it means that the parser encountered a fatal error and is unable to parse the source, because it contains an unrecoverable syntax error.
Rename this property to `fatal_error`, to better describe what it means.
This is a breaking change, but one that's trivial to fix in downstream code - the property doesn't change its meaning or behavior, just its name.
All the changes in this PR in other crates are just reacting to this change and making everywhere use the term "fatal error" instead of "panicked", so the codebase is consistent.
Private-in expressions lose required parentheses when they appear on the left of a higher-precedence binary operator. This affects both default and minified code generation and can change the result or cause a runtime error.
For example:
```js
class C {
#x;
test(o) {
return (#x in o) + 1;
}
}
console.log(new C().test(new C()));
```
The input prints `2`. Previously, codegen emitted this return expression:
```js
return #x in o + 1;
```
Because `+` binds more tightly than `in`, this is parsed as `#x in (o + 1)`. The addition converts the object to a primitive, so the private-field check throws a `TypeError` instead of producing the boolean used by the original addition.
With this change, the required grouping is preserved:
```js
// Default output
return (#x in o) + 1;
// Minified output
return(#x in o)+1
```
The binary expression visitor already computes the precedence required for its left operand. However, its `PrivateInExpression` special case discarded that value and called `gen_expr` with `Precedence::Lowest` and an empty context. Passing `self.left_precedence` and `self.ctx` lets the existing private-in printer apply its parentheses rule using the same inputs as other left operands.
This preserves parentheses for arithmetic, exponentiation, and shift operators. Equal- and lower-precedence operators, such as `<`, `===`, and `&&`, continue to omit unnecessary parentheses.
Large hexadecimal, binary, and octal literals can round incorrectly when their digits are accumulated with repeated `f64::mul_add` calls. For example, `0x10000000000000801` currently becomes `2^64` instead of the correctly rounded `2^64 + 4096`.
Preserve the leading significant bits and a sticky bit in the nondecimal slow paths, then round once and scale by a power of two. This also covers numeric separators and legacy octal literals, without allocating or changing the existing integer fast paths.
Use `Ident` in the mangler for the variable names to keep. This reduces the `Set::contains` operation faster as the hashing doesn't happen.
I used AI to generate the code and then reviewed the code.
Oxc Transformer supports output down to ES2015, but the contributor guidance
did not state that floor and the Rust API docs still listed `es5`. This made
plugin-only transform combinations look like supported target configurations.
Document the ES2015 floor and require target-dependent regressions to be
reproducible through public target selection. Legacy runtime targets may still
select available transforms, but do not imply complete compatibility with
pre-ES2015 engines.
Stacked on #26326.
Verified with `cargo fmt --check`, `just doc`, and
`cargo test -p oxc_transformer`. `just ready` completed formatting and workspace
checks, but stopped in the test phase on the existing Node-version-only
`stacktrace_is_correct` snapshot difference (`v25.8.1` locally versus `v26.5.0`
recorded).
AI assistance was used to investigate the documentation gap, edit the guidance,
and run verification. I remain responsible for reviewing and understanding the
changes before merge.
For targets that support async functions but not async generators, async-only converter mode still treated every async function as if the enabled transform would move its body. Plain async arrows and methods gained generated `this` and `super` bindings, and class-field arrows were wrapped unnecessarily.
Use the shared body-movement predicate for every async-only rewrite. Functions left native by the selected target now remain untouched, while async generator functions that are lowered keep their required lexical captures.
## Example
A plain async method using `super` previously gained a generated `_superprop_getValue` binding even though the method remained native. This made `eval("typeof _superprop_getValue")` return `"function"` instead of `"undefined"`. The method now remains unchanged.
Verified with focused output/runtime conformance, full transformer output conformance, and `cargo test -p oxc_transformer`.
Stacked on #26317.
AI assistance was used to diagnose the remaining transform boundaries, implement the predicate checks, and add tests. I remain responsible for reviewing and understanding the changes before merge.
For targets that support async functions but not async generators, plain async methods and arrows remain native. Async-only converter mode still captured `arguments` for all of them, exposing generated `_arguments` bindings even though their bodies never move.
Gate `arguments` capture on the transform that owns the function body. Native async functions now remain untouched, while lowered async generator methods still capture their original arguments.
## Example
This native async method previously changed from:
```js
async method() {
void arguments;
return eval("typeof _arguments");
}
```
to:
```js
async method() {
var _arguments = arguments;
void _arguments;
return eval("typeof _arguments");
}
```
The generated binding changed the return value from `"undefined"` to `"object"`. The method now remains unchanged.
Verified with focused output/runtime conformance, full transformer output conformance, and `cargo test -p oxc_transformer`.
Stacked on #26227.
AI assistance was used to diagnose the transform boundary, implement the fix, and add tests. I remain responsible for reviewing and understanding the changes before merge.
For targets that support async functions but not async generators, plain async methods remain native. The shared arrow converter still captured `this` whenever either async transform was active, injecting an observable `_this` binding into methods whose bodies never move.
Track async-to-generator and async-generator lowering separately. Plain async methods are now left untouched when only async generators require lowering, while transformed async generator methods still preserve their receiver.
## Example
With a Chrome 55 target, this method previously gained a generated binding:
```js
async method() {
var _this = this;
void _this;
return eval("typeof _this");
}
```
It now remains unchanged, so the direct evaluation returns `"undefined"` as it does in the source program.
Verified with a Chrome 55 target output/runtime fixture, full transformer output conformance, and `cargo test -p oxc_transformer`.
AI assistance was used to diagnose the transform boundary, implement the fix, and add tests. I remain responsible for reviewing and understanding the changes before merge.
This PR is inspired by #26333, addresses the repeated `with_hasher_in(IdentBuildHasher, allocator)` call, and removes the extra `'ident` lifetime.
`ArenaHashMap::new_in` works with any `Default` hasher, so `ArenaIdentHashMap::new_in(allocator)` picks `IdentBuildHasher` automatically. `ArenaHashSet` only has `new_in`, `with_capacity_in` and `from_iter_in` for `FxBuildHasher`, so an `Ident`-keyed arena set has to call `with_hasher_in(IdentBuildHasher, allocator)` every time (see #26333).
Mirror the map's `S: Default` impl on the set and add an `ArenaIdentHashSet<'alloc>` alias next to `ArenaIdentHashMap`. Nothing calls the `FxBuildHasher`-only constructors today, so no other code changes.
The alias takes a single lifetime, same as `ArenaIdentHashMap`. A separate lifetime for the `Ident` keys is not needed, and dropping it is sound: both `ArenaHashSet` and `Ident` are covariant, so when the idents are borrowed from somewhere other than the arena (for example `Scoping` in the mangler), the borrow checker shrinks `'alloc` to the shorter of the two borrows. The set can never outlive the strings its idents point to.
`SequenceExpression` inlining from `minimize_conditional_after_if` is a
more optimal version of inlining when we are constructing conditional
expr, with this change we will do this always instead of falling to
`minimize_conditional_expression`
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
add test cases for uncovered code and branches that should be tested:
verified with llvm-cov
```sh
cargo +nightly llvm-cov clean --workspace && cargo +nightly llvm-cov --branch --html -p oxc_minifier --test mod
```
i found out that our coverage is not really ideal while working on
#26264
Fixes#26290, #26291.
Also, many changes to follow refined parser acceptance line.
---
CI will fail until parser version bumped, needs oxc-project/oxc-css-parser/pull/166
The duplicate class element check stored only the last element for each name. This allowed a public element to hide an earlier private declaration, and a setter to hide an earlier getter (or vice versa):
```js
class DuplicateField {
#x;
x;
#x;
}
class DuplicateGetter {
get #x() {}
set #x(value) {}
get #x() {}
}
```
Both classes were accepted despite declaring the same private field or getter twice. The same problem affected setter/getter/setter sequences.
Key a single map by both the element name and whether it is private, so public elements cannot replace private declarations. This keeps the namespaces separate while reserving map capacity only once. For each private name, retain separate slots for setters and other declarations. Look for a previous declaration in the matching slot first, then fall back to the other slot. This catches repeated getters and setters while still allowing one getter/setter pair when both have the same static status.
The existing diagnostic logic continues to reject private names shared by static and instance elements, including the TypeScript-specific diagnostic. Public elements continue through the existing public-element duplicate check.
The parameter check only recognized `FormalParameter`, allowing `await` and `yield` in destructuring defaults inside rest parameters:
```js
async function f(...[x = await 0]) {}
function* g(...[x = yield 0]) {}
```
Include `FormalParameterRest` so both cases report the existing parameter diagnostic. The check still stops at nested functions, where `await` and `yield` can be valid.
Reject labeled and unlabeled `break` and `continue` statements that cross an arrow-function boundary.
For example:
```ts
while (true) {
(() => {
break;
});
}
```
now reports an illegal break, while jumps targeting loops inside the arrow remain valid.