Commit Graph

20389 Commits

Author SHA1 Message Date
Cameron Clark 572cea4548 perf(codegen): benchmark ASCII-only output 2026-09-10 17:34:31 +01:00
Samuel Attard 9ef028c2ad feat(codegen): add ascii_only option (#25994)
Closes #17068. Supersedes #18095 / #18118.

Adds `CodegenOptions::ascii_only` (and `codegen.asciiOnly` in
`oxc_minify_napi`): escape every non-ASCII character in string literals,
untagged template literals, regexp literals, directives and identifier
names so the output is 7-bit clean — like esbuild `--charset=ascii` /
terser `format.ascii_only`. Off by default; the default path is
untouched (codegen bench and conformance unchanged).

```js
// Input
let café = "naïve 😀";
let re = /[–—]/u;

// Output with ascii_only: true
let caf\u00E9 = "na\u00EFve \u{1F600}";
let re = /[\u2013\u2014]/u;
```

Characters above U+FFFF use ES2015 code-point escapes. Regex patterns
use escaped surrogate pairs instead; RegExp.prototype.source reflects
the escaped spelling.
Tagged template quasis, JSX names/text/attribute strings, hashbangs and
preserved comments may still contain non-ASCII characters. JavaScript
expressions inside tagged templates and JSX are escaped normally.

Performance; with the option disabled, codegen codspeed benchmarks are
withing noise (<1%). With the option on, performance is only affected
for files that contain non ascii characters.

---

Our use case is a large Vite/Rolldown app served through proxies that
mangle non-ASCII JS (previously handled by terser's `ascii_only`);
#17068 also lists deno_core snapshots and Chrome extension content
scripts.

AI-assisted (Claude Code); I reviewed the code, wrote the tests, and
have been running this in production builds via a vendored
`oxc_codegen`.

---------

Co-authored-by: Samuel Attard <6634592+MarshallOfSound@users.noreply.github.com>
Co-authored-by: Cameron Clark <cameron.clark@hey.com>
Co-authored-by: Dunqing <dengqing0821@gmail.com>
2026-09-10 17:10:02 +01:00
camc314 d7713ad4cb fix(parser): classify Unicode line breaks in block comments (#26536)
Block comments containing U+2028 or U+2029 were marked `SingleLineBlock` unless they also contained LF or CR. Switch to the multiline-comment scanner after either Unicode separator so downstream consumers receive the correct comment kind.

This prevents the formatter from dropping parentheses around a return argument with such a leading comment, which could change the returned value to `undefined`.
2026-09-10 15:28:49 +00:00
camc314 75cd919ffb fix(transformer): preserve receivers in private optional chains (#26535)
Only bind a private field when it is the result of an optional chain being called. In `(this.#items.get(key)?.find(fn))?.()`, the intermediate `#items` field must not receive `.bind(this)`.

Normalize non-null assertions in the TypeScript transform before other transforms inspect the chain. This preserves the receiver for `(this?.#fn!)()` and `(this?.#fn!!)()` without mixing TypeScript assertion removal into the class transform.

Fixes #26528
2026-09-10 15:09:24 +00:00
camc314 b32d25d418 fix(parser): reject escaped import-phase keywords (#26534)
The parser consumes `source`, `defer`, and sometimes `from` as binding identifiers before resolving their role in an import declaration. Validate escapes once they are known to be keywords, so declarations such as `import s\u006furce wasm from "m"` and `import source fr\u006fm "m"` report an error.

Escaped binding names remain valid, including `import s\u006furce from "m"` and `import source fr\u006fm from "m"`.
2026-09-10 14:55:08 +00:00
renovate[bot] 59e8d5fb91 chore(deps): update napi (#26533)
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Adoption](https://docs.renovatebot.com/merge-confidence/) |
[Passing](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) | Type |
Update |
|---|---|---|---|---|---|---|---|
| [@napi-rs/cli](https://napi.rs/)
([source](https://redirect.github.com/napi-rs/napi-rs)) | [`3.9.0` →
`3.9.1`](https://renovatebot.com/diffs/npm/@napi-rs%2fcli/3.9.0/3.9.1) |
![age](https://developer.mend.io/api/mc/badges/age/npm/@napi-rs%2fcli/3.9.1?slim=true)
|
![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@napi-rs%2fcli/3.9.1?slim=true)
|
![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@napi-rs%2fcli/3.9.0/3.9.1?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@napi-rs%2fcli/3.9.0/3.9.1?slim=true)
| pnpm.catalog.default | patch |
| [napi](https://redirect.github.com/napi-rs/napi-rs) | `3.12.2` →
`3.12.3` |
![age](https://developer.mend.io/api/mc/badges/age/crate/napi/3.12.3?slim=true)
|
![adoption](https://developer.mend.io/api/mc/badges/adoption/crate/napi/3.12.3?slim=true)
|
![passing](https://developer.mend.io/api/mc/badges/compatibility/crate/napi/3.12.2/3.12.3?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/crate/napi/3.12.2/3.12.3?slim=true)
| workspace.dependencies | patch |
| [napi-derive](https://redirect.github.com/napi-rs/napi-rs) | `3.6.3` →
`3.6.4` |
![age](https://developer.mend.io/api/mc/badges/age/crate/napi-derive/3.6.4?slim=true)
|
![adoption](https://developer.mend.io/api/mc/badges/adoption/crate/napi-derive/3.6.4?slim=true)
|
![passing](https://developer.mend.io/api/mc/badges/compatibility/crate/napi-derive/3.6.3/3.6.4?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/crate/napi-derive/3.6.3/3.6.4?slim=true)
| workspace.dependencies | patch |

---

### Release Notes

<details>
<summary>napi-rs/napi-rs (@&#8203;napi-rs/cli)</summary>

###
[`v3.9.1`](https://redirect.github.com/napi-rs/napi-rs/compare/@napi-rs/cli@3.9.0...@napi-rs/cli@3.9.1)

[Compare
Source](https://redirect.github.com/napi-rs/napi-rs/compare/@napi-rs/cli@3.9.0...@napi-rs/cli@3.9.1)

</details>

---

### Configuration

📅 **Schedule**: (in timezone Asia/Shanghai)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/oxc-project/oxc).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC43MS4wIiwidXBkYXRlZEluVmVyIjoiNDQuNzEuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Cameron Clark <cameron.clark@hey.com>
2026-09-10 14:26:42 +00:00
camc314 47b83115f0 fix(parser): recognize contextual binding names in type lookaheads (#26532)
Recognize `await` and `yield` as binding names when looking ahead for TypeScript function types and index signatures. This allows valid syntax such as `(await: number) => void` and `interface I { [await: string]: unknown }`, while leaving contextual legality to actual parsing.
2026-09-10 14:05:25 +00:00
camc314 1d681b0d4c perf(linter/react/jsx-pascal-case): avoid temporary name segment vector (#26531)
Iterate JSX name segments directly instead of collecting them into a temporary vector. Namespaced names still split on `:`, member expressions on `.`, and simple names remain a single segment.
2026-09-10 13:25:00 +00:00
camc314 d6b6705f8f fix(parser): require arrow separator in TypeScript function types (#26529)
Require `=>` when parsing TypeScript function and constructor types, while retaining `:` for function, method, and arrow return annotations. Previously, any token could be consumed as the separator, accepting invalid types such as `type F = (): number` and `type F = new () + number`.

This also prevents a valid conditional expression from being silently grouped into the wrong arrows:

```ts
const a = true, b = 1, c = 2;
const f = a ? (b) : (): any => b ? c : (x = 1): any => x;
console.log(typeof f);
```

The transformed program now prints `number`; previously it printed `function`.
2026-09-10 13:05:18 +00:00
camc314 42315366b1 fix(linter): compare label text in runtime optimization assertion (#26526)
Include label text when sorting diagnostics for the optimized/unoptimized runtime assertion. Diagnostics with identical spans and messages but different labels previously compared equal, so sorting could pair different diagnostics and trigger a false assertion failure.

Fixes the assertion seen in the [Kibana ecosystem CI job](https://github.com/oxc-project/oxc-ecosystem-ci/actions/runs/34459300249/job/102815162719).
2026-09-10 11:05:59 +00:00
camc314 e98beef227 fix(parser): disambiguate await using in for initializers (#26527)
Allow classic `for` initializers such as `for (await using;;)` when `using` is an ordinary identifier. Reuse the statement parser’s `await using` lookahead so resource declarations require a following binding identifier, preserving the existing line-break restrictions.
2026-09-10 10:59:58 +00:00
camc314 36d5534689 fix(linter): include file path in diagnostic assertion (#26525) 2026-09-10 10:37:11 +00:00
camc314 92afee6734 fix(parser): allow parenthesized JSX comma expressions with preserve_parens=false (#26524)
Allow parenthesized comma expressions such as `<A>{(a, b)}</A>` and `<A x={(a, b)} />` when `preserve_parens` is false.

Compare the sequence expression's start with the first token's start to retain the grouping distinction after parentheses are omitted from the AST. Ungrouped comma expressions such as `{a, b}` and `{(a, b), c}` remain invalid.
2026-09-10 10:30:38 +00:00
camc314 31508b1be5 fix(parser): reject return types on constructor overloads (#26523)
Constructor overloads and ambient signatures previously bypassed the return type check because it required a body. Reject their return annotations with TS1093, matching constructor implementations.

Highlight only the return type itself, excluding the colon and preceding whitespace.
2026-09-10 10:10:39 +00:00
camc314 38533ace80 docs(ast): move type annotation span comment to span field (#26522) 2026-09-10 10:01:29 +00:00
leaysgur 586f27a166 feat(formatter_core): add prefix_align builder and Tag::(Start|End)Prefix (#26520)
Mainly for blockquote for Markdown.

```md
> If this line is long and to be broken, how printer know new line needs `> ` prefix?
```

This will also help JSDoc formatting (`* ` prefix) if we update it via IR, currently just splitting lines.
2026-09-10 09:08:50 +00:00
Pablo García d35d89f78c fix(oxfmt): skip shutdown delay on fixed Node 24 releases (#26518)
Oxfmt still schedules its 50 ms forced-exit workaround on every Node 24
release, although Node 24.13.1 backported the ThreadsafeFunction fix.
Exempt fixed Node 24 releases while retaining the existing workaround
for older Node 20/22/24 versions and Node 25 before 25.4.0.

The backport is documented in [Node 24.13.1's release
notes](https://nodejs.org/en/blog/release/v24.13.1) and
[nodejs/node@1e13e84f16](https://github.com/nodejs/node/commit/1e13e84f162397f1adbe58f7a6f62974cfd0fa95).
This narrows the workaround introduced in #18980; it preserves worker
disposal and `process.exitCode` handling.

Earlier downstream validation of this same condition on Linux/Node 24.19
included ten successful checks of 12,032 synthetic files with complete
output. In eleven paired downstream Vite+ check rounds, removing the
timer saved a median of about 42 ms for full checks and 44 ms for
three-file checks. These are project-specific workflow timings, not a
universal 50 ms guarantee.

Validation on `805650e8f60e25abb8ae1038580ab799e7f8dcd9`, using the
repository's frozen pnpm 12.3.2 dependency installation and Rust 1.98.1:

- `pnpm --dir apps/oxfmt build-dev`: native and JavaScript build passed.
- `env -u NO_COLOR -u FORCE_COLOR pnpm --dir apps/oxfmt test
--maxWorkers=4`: **480 passed, 10 skipped**, using the pinned Vitest
5.0.0. This covers the complete Oxfmt JavaScript suite, including CLI,
API, LSP and the ten new regression cases. The first run had two color
snapshot mismatches caused by inherited `NO_COLOR`; clearing the ambient
color variables resolved them without changing tests or snapshots.
- `cargo test -p oxfmt --locked`: **84 passed**.
- `cargo clippy -p oxfmt --all-targets --locked -- -D warnings`: passed.
- Changed-file formatting and repository-configured type-aware
Oxlint/type checks: passed with the pinned tools.

Additional checks exercised the freshly built native CLI on **real Node
24.13.1 and 24.19.0**: five successful runs per runtime over 12,032
synthetic JS/Markdown files, including worker callbacks; no 50 ms timers
were registered. Both runtimes preserved all 497,780 bytes of a large
stdin-formatting result and the expected parse-error exit code 2. These
are correctness/stress checks of the dev build, not performance
benchmarks.

The entire Oxc workspace's other packages and the cross-platform CI
matrix were not run locally.

The follow-up commit `1c98d210501e276c2d6e3009562b2ebe41217ab3` removes
the ten mocked shutdown regression cases at the maintainer's request.
Its only change is deleting that test file; the production CLI is
byte-for-byte unchanged from the fully validated revision above. The
final PR changes only `apps/oxfmt/src-js/cli.ts`. The suite counts above
describe the earlier run, including the subsequently removed tests; no
new full-suite run is claimed for the deletion-only follow-up.

AI assistance: implementation and self-review performed with OpenAI
Codex using GPT-6 Astra (`gpt-6-astra`), with reasoning effort set to
`high`.
2026-09-10 16:45:24 +09:00
overlookmotel 35f4ead974 docs(lexer): document chunk functions (#26510)
Docs-only change. Add doc comments to all the primitive functions in `chunk.rs`.
2026-09-10 07:27:19 +00:00
overlookmotel 44bf12d17d refactor(lexer): make veq and mm safe functions (#26509)
Small internal change.

`veq` and `mm` impose no safety preconditions on the caller. Make them safe functions.
2026-09-10 07:27:19 +00:00
overlookmotel f5b0b9ed19 refactor(lexer): rename load8 to load64 (#26508)
Pure refactor - just renaming.

`load8` loads 8 bytes. Rename it to `load64` (64 bits).

This matches `load256`, which loads 256 bits (not bytes).
2026-09-10 07:27:19 +00:00
overlookmotel 795a9fe1bb refactor(lexer): rename finder! macro to define_find_function! (#26507)
Pure refactor - just renaming.

Rename the `finder!` macro to the more descriptive `define_find_function!`.
2026-09-10 07:27:18 +00:00
overlookmotel a15dd9b635 refactor(lexer): split find module into multiple files (#26506)
Pure refactor.

Split `find` module into parts.

- `find` directory contains find primitives (`find1`, `find2` etc) and specialized `find_*` functions.
- `scan` directory contains `scan_*` functions.
- `chunk` module contains primitives for reading and manipulating chunks (`load256`, `mm`, `veq` etc).

In `find` and `scan`, AVX2 and generic code is split into separate files, which both export the same functions.

Each component is now small enough to read as a whole.

This is pure refactor in the strictest sense. The ASM the crate compiles to remains identical to before this PR.
2026-09-10 07:27:18 +00:00
leaysgur 4ae43015c0 refactor(formatter_tests): trim conformance helpers (#26517)
Remove redundant lines.
2026-09-10 04:10:57 +00:00
leaysgur 1c6b1424bf docs(formatter_tests): arrange comments (#26516) 2026-09-10 03:57:54 +00:00
leaysgur 41abcba2cc docs(formatter): note why jsx-test-suite snippets stay off (#26515)
For now, `jsx-test-suite` are off by intension. Almost all cases are already covered by our fixtures.
2026-09-10 03:57:54 +00:00
leaysgur aef8b4acce fix(formatter_css): handle less-test-suites failures (#26513)
Follow up on #26469 for CSS.

Updated `oxc-css-parser` to `v0.0.15`.

---

- Keep parens for `calc((a + b))` by adding `CalcParenthesized` AST
  - Do not follow JS formatter approach (remove all, then add back), only works for CSS, not for SCSS/Less
- Fix Less operand spacing: `2em*1em` -> `2em * 1em`
- Rework `@import` prelude fill
- Leave glued `and(` and `when(` as-is
  - `@media screen and (max-width:1280px) { }` and `@media screen and(max-width:1280px) { }` is different
  - We do not alter behavior
- Format `LessMixinDefinition` and `LessConditionalQualifiedRule`
  - We still have a room to go better than Prettier here, but keep for now
2026-09-10 03:31:42 +00:00
Armano 029c84bcda perf(minfier): update expressions in place when substituting alternate syntax (#26460)
- `substitute_typeof_undefined`: do not recreate binnary expression and
instead just update right/left argument and operator
- `substitute_rotate_binary_expression`: replace `take_in*2` and
reassign with `std::mem::swap`
- `substitute_object_or_array_constructor`,
`substitute_global_new_expression`: introduce new helper
`transform_new_expr_to_call_expr` to convert new to call expr
- `substitute_iife_call`: use array to alloc all items in sequence
without reallocs
2026-09-10 09:44:47 +08:00
overlookmotel 0df2b6c197 refactor(lexer): move KwSet selection out of lex_raw (#26503)
Pure refactor. Small change to `oxc_lexer`.

`coalesce` stage selects a `KwSet` depending on source type - JS or TS. Move making this selection from `lex_raw` into `coalesce` itself. This just removes a little clutter from `lex_raw` and makes it clear that only `coalesce` stage uses it.
2026-09-09 16:47:21 +00:00
camc314 2ad7d498a0 perf(linter/promise/catch-or-return): avoid temporary formatting vectors (#26505)
Join formatted termination methods directly when building diagnostic and help text, avoiding temporary vectors while preserving method order and wording.
2026-09-09 16:42:06 +00:00
camc314 203235baa3 perf(linter/jsx-a11y/no-static-element-interactions): avoid role vector (#26504)
Read the first role token directly instead of collecting every token into a vector. The rule continues to inspect only the first role, preserving its existing behavior for multi-role values.
2026-09-09 16:35:09 +00:00
camc314 2e951679cc perf(linter/jsx-a11y/anchor-is-valid): avoid temporary attribute vector (#26501)
Join the allowed attribute names directly when formatting missing-href help text, avoiding a temporary vector while preserving the diagnostic wording and attribute order.
2026-09-09 15:59:52 +00:00
camc314 deafdba010 perf(linter/react/exhaustive-deps): avoid temporary dependency vector (#26502)
Join formatted dependency names directly when building the missing-dependency diagnostic, avoiding a temporary vector while preserving dependency order and wording.
2026-09-09 15:55:19 +00:00
camc314 4f1627fdc9 perf(linter/oxc/branches-sharing-code): compute deletion spans lazily (#26500)
Compute deletion spans while building shared-code suggestions instead of collecting them into temporary vectors. This also defers span computation until the suggestion closure runs, preserving deletion order and replacement text.
2026-09-09 15:31:59 +00:00
camc314 8296f9eb81 test(codegen): enable number printing cases (#26496)
Enable all 43 commented-out number-printing cases ported from esbuild, with expectations matching Oxc's existing output.

The old expectations preserved the input spelling, but Oxc uses the same value-based number printer with and without whitespace minification. It removes numeric separators and compares decimal, exponent, and hexadecimal spellings by length, keeping the current candidate on ties. For example, `1e-3` becomes `.001` (equal length), while `1000000000001` becomes `0xe8d4a51001` (shorter).

Large integer literals also reflect JavaScript `Number` rounding already applied during parsing. For example, `0xFFFF_FFFF_FFFF_FFFF` rounds to `0x10000000000000000`, so the changed spelling preserves the runtime value.
2026-09-09 15:27:09 +00:00
camc314 a091fc4b42 fix(parser): validate await context for await using declarations (#26495)
Reject `await using` in non-async functions and ordinary generators, including `for` and `for...of` loop heads. Treat top-level `await using` as module syntax when the source type is unambiguous.
2026-09-09 15:21:18 +00:00
camc314 c068fd2f44 perf(linter/react/jsx-curly-brace-presence): avoid newline position allocation (#26499)
Track line offsets while splitting multiline JSX text instead of collecting newline positions in a separate vector. Offsets remain byte-based, preserving fixes for Unicode text, blank lines, and trailing newlines.
2026-09-09 15:09:04 +00:00
camc314 ed4357c620 perf(linter/eslint/no-restricted-properties): skip empty configurations (#26497)
Skip the rule when no property restrictions are configured, avoiding node callbacks and property-access analysis that cannot produce a diagnostic.
2026-09-09 15:02:44 +00:00
camc314 92e41b7a54 perf(linter/oxc/no-barrel-file): iterate module requests directly (#26498)
Iterate matching module requests directly instead of collecting a temporary vector before counting loaded modules. Export traversal order and diagnostics remain unchanged.
2026-09-09 14:55:41 +00:00
camc314 5255ee3982 perf(linter/unicorn/prefer-single-call): avoid temporary argument vector (#26494)
Join source argument slices directly when building the merged-call fix, avoiding a temporary vector while preserving argument text and separators.
2026-09-09 14:48:05 +00:00
camc314 96ef3654ed perf(linter/unicorn/prefer-includes): reduce suggestion allocations (#26492)
Borrow the receiver source text and build argument text inside the suggestion closure. Join argument slices directly instead of collecting a temporary vector, preserving the generated replacement.
2026-09-09 14:11:13 +00:00
camc314 5501e86429 fix(parser): disallow in expressions in using for-loop initializers (#26490)
Reject invalid initializers such as `for (using x = a in b;;);` by parsing `using` and `await using` declarations with `Context::In` disabled, matching ordinary for-loop declarations. Restore the outer context afterward so parenthesized `in` expressions and the remaining loop expressions keep their existing behavior.
2026-09-09 14:03:17 +00:00
overlookmotel 5983db126d refactor(lexer): move unicode_ws_len out of classify stage (#26484)
Pure refactor. No code changes, just moving code around.

Move `unicode_ws_len` out of `classify` stage. It's used across `carve`, `misc`, `find`, and `regex_div` - but not `classify` (since #26482).

Move it into `find.rs`, which contains all the other primitives reading from the source buffer.
2026-09-09 13:51:26 +00:00
overlookmotel 8cf13112b5 refactor(lexer): move misc dispatch and early exit out of lex_raw (#26483)
`misc_pre` and `misc_post` both have early exit branches. `misc_pre` also dispatches to 2 different implementations depending on whether UTF-8 validation is required.

This logic was all in `Lexer::lex_raw`, mixed around the calls into other stages. Move it into the `misc` module, simplifying `lex_raw`.

The early exits are handled in the `misc_pre` / `misc_post` entry points (which are marked `#[inline]`), and only pass control into the main implementations `misc_pre_impl` / `misc_post_impl` if the early exit checks pass. ASM after this PR is completely unchanged from before, so this PR is pure refactor in the strictest sense.
2026-09-09 13:51:26 +00:00
overlookmotel 73847e8563 refactor(lexer): move misc_pre and misc_post into separate module (#26482)
Pure refactor. No code changes, just moving code around.

`misc_pre` and `misc_post` were part of `classify` stage. Move them into their own separate stage.

Splitting it up into `pre.rs` and `post.rs` files is likely overkill - they could live within a single file. It's just a bit tidier for each stage to have its own directory (following the pattern of `classify`, `carve`, `coalesce` and `compress`) and it'd be weird if that directory just contained a single `mod.rs` file.

Splitting it does have the advantage of making it clear which primitives each uses from the `use` statements at top of each file.
2026-09-09 13:51:25 +00:00
camc314 a71fd7f1ea perf(linter/unicorn/no-new-buffer): avoid temporary argument vector (#26491)
Join argument source slices directly when building the `Buffer.from` or `Buffer.alloc` suggestion, avoiding an intermediate vector while preserving the replacement text.
2026-09-09 13:46:07 +00:00
camc314 11085e7aee perf(linter/jsdoc/require-yields): short-circuit JSDoc checks (#26488)
Stop checking JSDoc blocks once a non-ignored block is found instead of counting all matching blocks. In the yield-expression path, pass tags directly to the missing-tag check rather than collecting a temporary vector.
2026-09-09 13:31:07 +00:00
camc314 c8e5fa7656 fix(parser): allow escaped type names in import and export specifiers (#26487)
Allow escaped value names such as `import { t\u0079pe as x } from "m"` and the equivalent named exports. Reject escapes only after resolving `type` as a type-only modifier.

Preserve the decoded identifier name in the ambiguous `type as as` form so its AST name remains `type`.
2026-09-09 13:22:34 +00:00
camc314 2dcee2f216 fix(parser): reject async modifiers on class fields (#26486)
`class C { async x; }` was accepted in JavaScript and TypeScript, silently discarding `async` from the resulting field. Reject the modifier after parsing a class field, once fields have been distinguished from methods.

Async methods, fields named `async`, and newline-separated fields remain valid.
2026-09-09 13:04:01 +00:00
camc314 9b1aff8c0c perf(linter/unicorn/no-useless-undefined): skip calls without trailing undefined (#26481)
Return early for calls whose last argument is not `undefined`, avoiding unnecessary callee and `bind` checks. Collect trailing undefined spans with pushes followed by one reversal instead of repeated front insertions, preserving diagnostic and fix order.
2026-09-09 12:48:10 +00:00
camc314 973d58e128 fix(parser): require comma after TypeScript this parameter (#26480)
Require a comma after a TypeScript `this` parameter when the parameter list continues. Previously, malformed syntax such as `function f(this: T x: T) {}` parsed without a diagnostic.
2026-09-09 12:26:51 +00:00