Introduce `VecData128` and `VecData256` types, in `simd/data.rs`.
They're byte arrays aligned on 16 and 32 bytes, for lookup tables and other data which is read into SIMD vectors.
- `Vec128::read` / `Vec256::read` read one into a vector, with an aligned load.
- `Vec128::write` / `Vec256::write` write a vector into one, with an aligned store.
- `VecData128::read(cpu)` / `VecData256::read(cpu)` are the same as `Vec128::read` / `Vec256::read`, but read better for tables, e.g. `PH_A.read(cpu)`.
Convert the lookup tables which SIMD code reads into vectors: `PH_A`, `PH_B`, `PH_T`, `MERGED_LUTS`, `WORD_LUTS`, `BITS` (Neon), `QCOMPACT` and `BCOMPACT`.
The aligned read and store operations have minimal advantage over their unaligned versions. The realbenefit is ensuring that loads/stores do not touch multiple cache lines, which has a perf cost.
The change to aligned types has a positive impact for `QCOMPACT` and `BCOMPACT`, which were previously under-aligned, so reads could cross cache lines. Now that they're made up of aligned `VecData256` / `VecData128` blocks, every load is guaranteed to be within a single cache line.
`VecData128::read` and `VecData256::read` are generic over the CPU type. To support that, `CpuSimd` gets `Vec128` and `Vec256` associated types, and there are new `Vec128Impl` and `Vec256Impl` traits, which only contain `read` for now.
Both types deref to a byte array, so they can be indexed like an array, except in `const` contexts. `as_bytes_mut` and `as_u32s_mut` are for building tables in a `const` or `static`.
Noticed that `unicorn/prefer-single-call` rule declared both `pending`
and `fix` as its fix status, this PR removes `pending` and also changes
to `fix` to `conditional_fix` since the fix is skipped in 2 cases.
Also small change to `declare_oxc_lint` so that it rejects a second fix
capability
Reading `object_name[..1]` panics when a ref-like identifier starts with a multibyte character, such as `한글Ref`. Use `.chars().next()` to preserve the ASCII name check without slicing through a UTF-8 character. Ports the fix and regression fixture from https://github.com/facebook/react/pull/38025.
Fixes#28278.
Cases ending in `while (true)`, `do ... while (true)`, or `for (;;)` cannot fall through unless a reachable break exits the loop. Oxlint reports these cases even though ESLint accepts them.
Traverse CFG edges within each switch and skip the normal exit from statically true loop conditions. Preserve reachable break paths and unused fallthrough comment diagnostics, with regression coverage for async polling, nested breaks, parenthesized conditions, and unreachable breaks.
Linter tests and lint pass. The broader Oxlint suite fails in type-aware suppression tests: one produces different suppression counts, and another aborts because its expected suppression file is missing.
Fixes#28579
`prefer-spread` now reports `(c ? a : b).apply(null, args)` and `m!.apply(null, args)`, matching ESLint. Check whether the applied expression is a member expression rather than requiring an identifier, while retaining receiver checks for method calls.
Fixes#28728
`oxlint --init` now exits with an error if any supported config filename already exists in the current directory, preserving existing configs and avoiding conflicting ones. Exclusive file creation also prevents overwrites if `.oxlintrc.json` appears after the check.
Fixes#28741
Trim trailing zeros from the fractional part while preserving the exponent suffix verbatim. This avoids false positives on literals such as `4.6566128731E+100` and fixes `1.0E+10` to `1E+10`, matching Unicorn 62.
Fixes#28743
Treat contextual keywords spelled with a Unicode escape (`st\u0061tic`,
`\u0061sync`, `g\u0065t`, …) as property names rather than modifiers.
Such a token is an IdentifierName and cannot match a keyword terminal,
so `class A { st\u0061tic
x }` declares two fields named `static` and `x`. Previously it was
parsed as `static x` and reported "Keywords cannot contain escape
characters".
`try_parse_modifier` and `parse_contextual_modifier` now skip escaped
tokens. Invalid forms such as `class X { st\u0061tic y() {} }` are still
rejected. The error is now reported at the token after the name, as
Babel does, which accounts for the updated parser snapshots.
The new `misc/pass` fixture covers fields named `static`, `async`,
`get`, `set`, and `accessor` that end at a line break. The rejected
forms are already covered by Babel and test262.
Validated with scoped Rust checks and full parser conformance.
---------
Co-authored-by: Cameron <cameron.clark@hey.com>
fixes https://github.com/oxc-project/oxc/issues/28729
Generated by Claude Sonnet 5.5 🤖
The upstream rules uses regex to detect if it is a combining character with the `\p` shorthand:
https://github.com/eslint/eslint/blob/main/lib/rules/utils/unicode/is-combining-character.js#L11
Because there is no similar utility in rust, we currently have a self-managed list of character detection.
This list now get extended to detect more characters for other languages like Arabic, Hebrew, Thai ...
Verified manually that the failing test cases also fails upstream.
Did not verfify if the list is really valid and covers all possible combining characters.
I hope that the AI did no mistakes and included characters which are still valid.
<!-- CURSOR_AGENT_PR_BODY_BEGIN -->
With `--import-plugin`, `main` builds the module graph in batches of `threads × 4` entry files and waits for each batch and its dependency closure to finish before starting the next. The waiter is a pool worker that polls with `try_recv` + `yield_now`. In the profiles, the other workers spend much of the run spinning in rayon's work-stealing loop, the spinning grows toward the end of the run, and the run ends with a long tail where only a few cores are busy.
The graph loop now runs on the calling thread (`rayon::in_place_scope`) and blocks on `recv`. A new batch can start while earlier ones are still open. When one open batch imports from another, union-find merges them and they finish together, so at most `3 × group_size − 1` entry files (plus their dependencies) are in flight. Without the import plugin, the loop keeps `rayon::scope` and is unchanged; scope selection and module resolution share one resolver predicate. The language server (`run_source`) and the rule test harness (`run_test_source`) choose the scope the same way, so with the import plugin they also run the graph loop on the calling thread.
The speedup comes mostly from less total CPU work and a shorter tail, not from higher core utilization. samply profiles (4 threads, `-A all --import-plugin`, median of 5 runs):
| Corpus | Wall | CPU | Spent in `steal` / `find_work` / `try_recv` |
|---|---|---|---|
| next.js | 799 → 482 ms | 1,728 → 1,272 ms | 25.3% → 0.1% of samples (438 → 2 ms) |
| VS Code | 1,479 → 1,183 ms | 4,240 → 3,887 ms | 9.6% → 1.3% (402 → 51 ms) |
On `main`, one worker is on-CPU for almost the whole run (next.js: 3,098 samples vs 899–1,493 on the other three workers). With this PR the four workers are even (1,124–1,405), and the top of the inverted call tree is lexer, allocator, and semantic code instead of crossbeam's deque.
<img width="1290" height="358" alt="next.js: main vs this PR" src="https://github.com/user-attachments/assets/ffd00f15-4ad9-46e1-bd60-ca23c0efa696" />
<img width="1290" height="358" alt="VS Code: main vs this PR" src="https://github.com/user-attachments/assets/b917dbee-21ce-4262-b374-93af0df0beb7" />
Thread timelines from Firefox Profiler, `main` above and this PR below, same time scale.
## Results
`-c empty.json --disable-nested-config --silent -A all --import-plugin`. VS Code `src` at `1306698e` (11,260 files) and next.js `packages/` at `3bccd4df` (3,404 files). Time is median (min … max). Peak RSS is the median of `wait4` max RSS. Δ time is the median of paired per-round differences.
| Machine | Threads | Corpus | main | this PR | Δ time | Δ peak RSS |
|---|---|---|---|---|---:|---:|
| Linux x86-64, 8 vCPU | 4 | VS Code | 1,673 ms (1,566 … 2,282) | 1,403 ms (1,231 … 1,754) | −19.7% | +3.8% |
| | 4 | next.js | 744 ms (649 … 949) | 444 ms (396 … 904) | −40.4% | +16.7% |
| | 8 | VS Code | 960 ms (832 … 1,256) | 771 ms (661 … 900) | −18.5% | +5.6% |
| | 8 | next.js | 626 ms (539 … 821) | 426 ms (374 … 509) | −30.1% | +14.1% |
| Apple M4 Max (12P + 4E) | 8 | VS Code | 440 ms (427 … 494) | 359 ms (354 … 404) | −18.3% | +4.4% |
| | 8 | next.js | 263 ms (248 … 282) | 191 ms (183 … 202) | −28.0% | +4.2% |
| | 16 | VS Code | 378 ms (362 … 571) | 328 ms (321 … 530) | −12.6% | +8.9% |
| | 16 | next.js | 238 ms (228 … 306) | 168 ms (164 … 249) | −29.1% | +2.6% |
Linux: 20 rounds per row. M4 Max: 40 rounds (two passes of 20). In every 20-round set, this PR was faster in at least 17 rounds.
CPU time also drops on the 8-thread Linux run: user + sys 1.73 → 1.26 s on next.js and 4.10 → 3.72 s on VS Code.
Without `--import-plugin`, time and RSS are within noise on both machines: paired medians range from −6% to +3%, and this PR was faster in 16–26 of 40 rounds. On the M4 Max, lint output (`-D correctness --import-plugin -f unix`, sorted) is byte-identical to `main`.
## Memory
Peak RSS is 3–17% higher with the import plugin. The largest increase is next.js on Linux; on the M4 Max the same corpus is +3% to +4%. Three things contribute:
- Overlapping batches keep up to `3 × group_size − 1` entry files and their dependencies in flight, compared with one batch on `main`.
- Lint jobs are spawned from the calling thread, so they go to rayon's global FIFO queue behind parses that are already queued. ASTs are linted and freed later.
- The per-file arena allocators keep their capacity and the pool does not shrink, so the higher peak persists until exit. On next.js, `MIMALLOC_PURGE_DELAY=0` reduced the gap from 86 MB to 28 MB in an earlier measurement.
Runs without the import plugin are unaffected. A lint-first scheduler did not reduce peak RSS on 4 cores. A cap on in-flight work is left for a follow-up.
Linking `loaded_modules` stays serial on the graph thread. A parallel iterator started from a non-worker thread would queue behind pending parses and block the loop.
## Tests
A unit test covers merging into a larger dependency group when `group_id` changes: it checks the new root, the accumulated counts and paths, and that the donor is cleared. Other `ModuleGroups` tests cover adding a group, path compression, and refusing to merge a finished group. The `import_plugin_multi_group` CLI fixture (9 files, `-D import/no-cycle`) matches `main`.
<details>
<summary>Reproduce</summary>
```sh
cargo build --release -p oxlint --bin oxlint --no-default-features --features allocator
echo '{}' > empty.json
# Linux: taskset -c 0-3 or 0-7. macOS: --threads 8 or --threads 16.
oxlint -c empty.json --disable-nested-config --silent -A all --import-plugin .
```
Run from VS Code `src` (`1306698e`) or next.js `packages/` (`3bccd4df`). Each build has its own `CARGO_TARGET_DIR`. Binaries run round-robin in rotating order with 2 warmups each. On Linux, rounds where other processes used more than 0.5 core were redone. On macOS, each round waited until other processes used less than 1.5 cores. Profiles: `samply record --rate 4000` pinned to separate cores, 1 warmup and 5 runs per binary.
`main` is `31cbe378d4`. Timings were taken on an earlier revision of this branch (`be6ef780c8`), before the branch was squashed into one commit. Changes made after that revision were not re-timed: tests and refactors, a deduplicated resolver check, the same scope selection for the language server and rule tests, one fewer `Arc` clone per already-queued import, and a simpler debug check.
</details>
<!-- CURSOR_AGENT_PR_BODY_END -->
If the target is `es2021` or lower, `this.#x += k`, `this.#x ??= k`, and
`++this.#x` on a private accessor give the wrong value. They should give
the new value of `#x`, but they give the return value of the setter
instead. Most setters return nothing, so the value is usually
`undefined`.
```js
class Counter {
#n = 1;
get #count() { return this.#n; }
set #count(v) { this.#n = v; }
add(k) { return (this.#count += k); }
}
console.log(new Counter().add(2)); // 3
```
The transformed code prints `undefined`, because the result of the
expression is the setter call:
```js
// before
return _set_count.call(_assertClassBrand(_Counter_brand, this), _get_count.call(_assertClassBrand(_Counter_brand, this)) + k);
// after
return _toSetter(_set_count.bind(_assertClassBrand(_Counter_brand, this)))._ = _get_count.call(_assertClassBrand(_Counter_brand, this)) + k;
```
Plain `=` and postfix `x++` are already correct, and plain `=` already
uses `_toSetter`. This PR uses the same form if the value of the
expression is used. If the expression is a statement, the output does
not change.
I did not use a temp var, because a temp var in a default parameter is
shared between calls, and a recursive setter overwrites it.
The new fixture `oxc/private-accessor-assignment-value` covers instance
and static accessors, all the operators above, an object from a function
call, arrow function bodies, and the recursive case. Its `exec.js` fails
on main with `expected 'from setter' to be 3`.
---
AI assistance was used for this change. I reviewed and tested it.
---------
Co-authored-by: qing deng <dengqing0821@gmail.com>
Each call in an array `concat` chain reads its arguments before the next call evaluates its own. Merging the calls moves those reads later, so a later argument can change an earlier one first:
```js
function f(arr) { return [].concat(arr).concat(arr.pop()); }
```
With `arr = [1, 2, 3]` this returns `[1, 2, 3, 3]`, but main merges it into `[].concat(arr, arr.pop())`, which returns `[1, 2, 3]`.
A chain now merges only when no later call has an argument with side effects after an earlier call has an argument that `concat` may read. Primitives and array literals don't count as reads. This is the array half of #27580; the string half landed in #27098.
When the merge is refused, the innermost call still folds its leading literals into its array: `[1].concat(1, arr).concat(arr.pop())` → `[1, 1].concat(arr).concat(arr.pop())`.
## Size
`echarts.js` grows by 8 B minified and 6 B gzipped; nothing else in `minsize` changes. The chain `[].concat(ecIns._componentsViews).concat(ecIns._chartsViews)` no longer merges, because with the default `propertyReadSideEffects` a getter on `_chartsViews` could change `_componentsViews`. With `propertyReadSideEffects: false` it merges as before.
monitor-oxc: 48 files larger (+960 B raw, +76 B gzip), 8 B per `concat` call that no longer merges.
## Not covered
With `propertyWriteSideEffects: false`, `arr[0] = 9` counts as free of side effects, so `[].concat(arr).concat(arr[0] = 9)` still merges. The string guard has the same gap; it needs a separate fix.
Part of #26242.
Implemented with AI assistance.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_018ogydZW3PPvmx3orpBQot4
Fixes#28600.
`var I; interface I {}` in a nested block merged the interface into the
hoisted `var`, so the type moved out of the block. TypeScript keeps the
interface in the block. #27936 fixed the opposite order, `interface I {}
var I;`.
## Cause
Hoisting a `var` records it in `hoisting_variables` for each
intermediate scope. `check_redeclaration` falls back to that map, and
`declare_symbol_on_scope` then reused the returned symbol, even for a
type declaration.
## Changes
- `declare_symbol_on_scope`: a declaration with no value flags only
reuses a symbol bound in the target scope. Otherwise it creates a new
symbol there.
- `check_redeclaration`: a binding in the scope and a hoisted `var` are
now checked separately. Without this, the block's type binding would
hide the conflict and the first change would lose the error in `{ var X;
interface X {} let X; }`.
- `check_redeclaration`: only the value flags of a hoisted symbol are
compared. The symbol can also carry type flags from a declaration in the
outer scope, and those do not conflict with a declaration in the block.
The second change also fixes a missed error in `{ interface X {} var X;
let X; }`. tsc rejects both forms with TS2481.
The value-flag restriction also fixes a false error on main: `type X =
number; { var X = 0; interface X {} }` was reported as a redeclaration,
but tsc accepts it.
An uninstantiated `namespace` in a block also has no value flags, so it
now gets its own block symbol too. tsc already rejects namespaces in
blocks (TS1235).
## Tests
- `tests/integration/symbols.rs`: symbol separation and reference
resolution, including the switch case, plus the redeclaration errors and
the valid programs where an outer type shares a symbol with the hoisted
`var`.
- `tests/fixtures/oxc/ts/interfaces/hoisted-var-then-interface.ts`: a
new snapshot of the scope placement. No existing semantic snapshots
changed.
---
AI assistance was used for this change. I reviewed and tested it.
---------
Co-authored-by: qing deng <dengqing0821@gmail.com>
When an unnamed parent node and a mangled identifier begin at the same source position, codegen deduplicated the identifier mapping. This retained location data but discarded the original identifier name, leaving consumers unable to restore inferred function names in source-mapped Node stack traces.
```mermaid
flowchart LR
A[AssignmentExpression mapping<br/>unnamed] --> B[Token at source position P<br/>name: none]
C[Identifier mapping<br/>name: longName] --> D{Same source position P?}
D -->|before| E[Drop duplicate<br/>names: empty]
D -->|after| F[Enrich existing token<br/>name: longName]
```
### Changes
- Cache whether the last emitted token has a name, keeping duplicate-position handling cheap in the source-map builder hot path.
- Enrich an unnamed duplicate token when a later identifier mapping supplies the original name.
- Add a unit regression test for the builder behavior.
- Extend the existing Node source-map stack-trace snapshot test with a mangled ES module fixture.
The Node fixture verifies:
```text
function longFunctionName(longName) { ... }
↓ mangled
function e(e) { ... }
```
and asserts that the source map includes both original names while Node restores the inferred inner frame as:
```text
at longName (/project/input.js:6:15)
```
<!-- claude-projects-attribution: {"github_login":"Brooooooklyn"} -->
_Requested by **Brooklyn** · [project thread](https://claude.ai/code/project/chan_018s9RxRdtH424j2EhXdzV3N?thread=cmsg_018s9RxRdtH424j2EhXdzV3NQxbeR8Pt7qaqSQwoq9rEFo)_
<!-- routine:prune-tests:duplicate-lsp-capability-test -->
Before: `capabilities::test::test_dynamic_watchers_intellij` and `test_dynamic_watchers_vscode` in `crates/oxc_language_server/src/capabilities.rs` have been byte-identical since both were added in #11075: the same `ClientCapabilities` with `workspace.did_change_watched_files.dynamic_registration: Some(true)`, and the same `assert!(capabilities.dynamic_watchers)`.
After: the IntelliJ copy is gone. Only lines inside `#[cfg(test)] mod test` change.
### Totals
- Files touched: 1.
- Cases deleted: **1 of 111** collected by `cargo test -p oxc_language_server -- --list` (110 run, 1 ignored); after: 110.
- Cases merged: 0. Net lines: **−17**.
- Runtime saved: 0.09 ms, the removed case's duration.
### Why it is safe
- Mutation M1, `capabilities.rs:41`: `dynamic_registration.is_some_and(...)` → `relative_pattern_support.is_some_and(...)`. Both capability tests fail identically; since the bodies are identical, every mutation affects both the same way.
- Still covered by `test_dynamic_watchers_vscode`. The 4 `tests::test_suite` dynamic-watcher tests also notice M1, but by hanging (see below).
Kept after defense: none.
| suite | before | after | delta |
|---|---|---|---|
| `oxc_language_server` (lib) | 111 (110 pass, 1 ignored) | 110 (109 pass, 1 ignored) | −1 |
0 failures before and after; the same test is ignored in both runs.
### What ran and what did not
- Ran at `d14dbd1e1` and on this branch: `cargo test -p oxc_language_server` (with `--list`, and JSON output with `--report-time`); M1, reverted; `cargo clippy -p oxc_language_server --all-targets -- --deny warnings`; `rustfmt --check --edition 2024` on the file; `git diff --check`. All clean.
- Not run: the rest of the workspace and the coverage/conformance suites.
Open pull requests: none of the open PRs touches `capabilities.rs`. Age: the test dates from 6b68de0da (#11075, 2025-05-18) and was not added for a bug.
To revert: `git revert 4bf9d3fea`.
---
_Generated by [Claude Code](https://claude.ai/code/session_01PxVsmvB9xfZKfVnUonY8kf)_
Two checks in `prefer_const.rs` collected resolved references into temporary vectors before scanning them. Borrow the resolved reference ID slices and map IDs to references in each existing pass, removing both allocations while preserving reference order, predicates, and behavior.
Sync the complete published `@babel/runtime@8.0.8` helper tree so future updates have a recorded upstream baseline.
Import all 95 CommonJS/ESM helper pairs, the MIT license, conditional exports, and `sideEffects: false`. Preserve 26 legacy Babel helper pairs, three TypeScript decorator helper pairs, and existing import paths.
189 of the 191 upstream files are byte-identical. The two `setFunctionName` implementations retain Oxc's existing behavior and match main. Add a hash manifest, a repeatable sync script, CJS/ESM tests in CI, and an async-generator execution regression. No new helper optimizations or correctness patches are included.
Validation: upstream hashes, compatibility preservation, sync idempotence and drift refusal, formatting, lint, syntax, and whitespace checks passed. Runtime tests were not rerun after restoring this tree because automatic approval blocked helper execution; the newer Babel fixture revision pinned by main was not run locally.
AI assistance: Claude.
The leading parens only guard a statement or arrow body start, so
Prettier prints the same object lookup idiom without them elsewhere
(`const get = ({ a: 1, b: 2 } as const)[key];`).
List that sibling and the assignment arrow body in `Why`, and replace
the `export default` example with a measured one.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
`should_add_parens` skipped the parens of an arrow's conditional body
when it starts with an object, function or class, assuming the leading
node prints its own.
Only an object does in an arrow body, so `() => (function () {}).a ? b :
c` printed with no parens at all.
Matches Prettier: skip them only for a leading object.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- bump oxc-markdown-parser 0.0.4 which skips autolink literal attempts that cannot match
- Compute a text's next words only under `proseWrap: always`, the only mode that reads them
- Print link destinations with nothing to escape as is
About 15% CPU instruction reduction.
The runtime snapshot still records a transformer timeout for async-private-gen-meth-static-ary-ptrn-elem-id-init-fn-name-arrow.js, which now passes. Regenerate the snapshot, increasing the passing count from 17,314 to 17,315 of 18,277.
Verified with cargo coverage runtime, which reproduced the monitor-oxc CI diff exactly, and an isolated run of the affected test.
AI assistance was used to prepare and verify this update.
- Only a spread dot precedes an operand, so a?.<T>(b) opens type
arguments instead of JSX and a./x/ is a division, as in tsc
- Split a << after a dot or a non-null mark into two type lists
- Accept const in a type parameter list nested in type arguments
Part of effort to move to runtime CPU feature detection.
Most of this stack has been converting to a pattern where the crate is compiled twice for different CPU feature sets - AVX2 and generic.
In the process, a few changes occured to the ASM, resulting from different inlining decisions.
Adjust inlining to bring the codegen for AVX2 back to as close as possible to what it was before all these changes.
Add `#[cpu_version(Generic)]` attribute to every function which is not compiled for every possible CPU feature set.
This has little effect - the macro doesn't alter the function - but it does check the function receives no params which suggest it should be compiled for a specific CPU feature set (e.g. `cpu: Avx2`), and makes it clear which paths through the code are intentionally not compiled twice for AVX2 and generic.
After this PR, every function that is part of the pipeline is marked with either `#[cpu_version]` or `#[cpu_multiversion]`.
`cpu_version` macro passes through the function unchanged where the function is unsafe or has an `#[inline(always)]` attribute. It checks that the function has an appropriate param which proves that the system supports the required CPU features (e.g. `cpu: Avx2` param for a function marked `#[cpu_version(Avx2)]`.
However, that check is based on the source text only. The macro can only see the name of the type in the param, not it's actual type. Add a line to the body of the function that checks the proof - making sure the type passed in is what it appears to be e.g.:
```rust
let _: crate::cpu::Avx2 = cpu;
```
Fix how the `cpu_version` and `cpu_multiversion` macros handle attributes on the function. Apply those attributes either to the dispatcher function or the implementation function, depending on their type.
Part of effort to move to runtime CPU feature detection. Follow-on after #28681.
Speed up the proc macros that PR introduced, by reducing `syn` usage. By not parsing the bodies of functions, the compile-time cost of the macros is reduced by 2x.
Part of effort to move to runtime CPU feature detection.
The `cpu_version` and `cpu_multiversion` macros previously could not identify associated functions (methods) of types which don't receive a `self` param. Fix this by also searching the tokens of the function for `Self`.
Switch some functions back to using `Self` where previously they couldn't due to the shortcomings of the macros.
Part of effort to move to runtime CPU feature detection.
The `cpu_version` and `cpu_versions` macros had become unweildly, and we'd reached the edge of what it's possible to do with declarative macros, even using all the tt-muncher tricks. Some improvements were impractical to make.
Convert both macros to proc macros in a new `oxc_lexer_macros` crate.
The proc macros are half as many lines of code, easier to understand, and more capable.
This also allows getting rid of the weird `apply` wrapper:
```rust
// Before
#[apply(cpu_version(Avx2))]
// After
#[cpu_version(Avx2)]
```
Rename `cpu_versions` to `cpu_multiversion`, which describes it better.