Add a method `Utf8ToUtf16::convert_program_and_comments`, and use it in a couple of places.
This is marginally faster than `convert_program` followed by `convert_comments`, as it avoids branching on the same condition twice.
Adds `ParseOptions::enable_ident_hashes` (default `true`) and `Ident::new_unhashed` in `oxc_str`, and turns it off in the parse-only paths of the `oxc-parser` napi crate and the JS/JSON formatters.
### Why
`Ident`'s precomputed hash (#19143) is a parse-time investment that pays off in semantic analysis — but parse-only consumers (parse + serialize, formatting) pay it for nothing. Profiling against other native parsers showed identifier hashing at 3.5-4.6% of parse time.
Measured on M-series (yuku-style native harness, 50 warmup + 300 runs, median):
| fixture | default | option off |
|---|---|---|
| react.development.js | 0.156 ms | 0.152 ms (−2.3%) |
| binder.ts | 0.383 ms | 0.370 ms (−3.5%) |
| App.tsx | 1.140 ms | 1.111 ms (−2.5%) |
| checker.ts | 7.862 ms | 7.499 ms (−4.6%) |
| typescript.js | 25.07 ms | 24.16 ms (−3.6%) |
### Contract
Unhashed `Ident`s store hash `0`; `Eq`/`Hash`/`ContentEq` include the stored hash, so unhashed and hashed `Ident`s of the same string do not compare equal. Semantic analysis (or anything relying on `Ident` hashing) must not run on an AST parsed with the option disabled. Default behavior is unchanged.
Every `Ident` the parser creates funnels through the `ParserImpl::ident()` helper, so the option applies uniformly. This covers identifiers lexed directly (`parse_identifier_kind`, `parse_private_identifier`) as well as those reconstructed from a `&str`/`Str` — import/export specifier locals, JSX element/member names, the TS `intrinsic` type name, TS import-type option keys (`with`/`assert`), and the `import x = this` recovery path — which would otherwise always be hashed through `Into<Ident>`. Exhaustively checked by parsing the test262/babel/typescript/misc/prettier corpora (96.5k files, 5.6M identifiers) in both option states and walking every `Ident` in the AST.
On 64-bit platforms `Ident::new_unhashed` compiles to a no-op: an unhashed `Ident` has the same layout and bit representation as `&str`.
### Opt-outs
- **napi `oxc-parser`** ties `enable_ident_hashes` to whether semantic errors are requested. Both parse entry points run `SemanticBuilder` only when `showSemanticErrors` is set, so the common parse-and-serialize path skips hashing while the semantic-errors path keeps it. Serialized output is unchanged — the hash is internal to `Ident` and never emitted.
- **JS and JSON formatters** turn it off: they never run semantic analysis and only read `Ident::as_str` / compare idents against string literals. Exception: the JS formatter keeps hashes when built with the `detect_code_removal` feature, whose check runs `SemanticBuilder` on the formatter-parsed AST.
Part of #23043.
`Vec::new_in`, `Vec::with_capacity_in`, `Vec::from_array_in` etc previously took an `&'a Allocator`. Instead make them take an `&A where A: GetAllocator<'a>`.
This makes them more flexible - you can pass a reference to any type which implements `GetAllocator` e.g. `ParserImpl`, `TraverseCtx` etc.
```rust
// Before (`ctx` here is `&mut TraverseCtx`)
let vec = ArenaVec::new_in(ctx.ast.allocator);
// After
let vec = ArenaVec::new_in(ctx);
```
The main motivation is to make them workable replacements for what are currently methods on `AstBuilder`, but will be removed in the new `AstBuilder`:
```rust
// Before (`ctx` here is `&mut TraverseCtx`)
let vec = ctx.ast.vec();
// After
let vec = ArenaVec::new_in(ctx);
// Instead of
let vec = ArenaVec::new_in(ctx.ast.allocator);
```
This is still longer code than the original, which is not ideal, but it's as short as can make them.
The main downside of this change is that when calling these methods with an `&Allocator`, you have to double reference:
```rust
let allocator: &'a Allocator = get_allocator_somehow();
// Passing `&&Allocator`
let vec = ArenaVec::new_in(&allocator);
```
This has no perf impact - these methods are inlined, and compiler collapses the double-reference like it wasn't there, but it's just ugly. Unfortunately, there's no way to implement `GetAllocator` so it'll accept both `&Allocator` and `&mut TraverseCtx`, and the latter is the much more common use case.
Pure refactor.
Use `ArenaBox` and `ArenaVec` everywhere for the arena-allocated types from `oxc_allocator`, instead of plain `Box` and `Vec`.
This disambiguates when `Vec` is `oxc_allocator::Vec` and when it's `std::vec::Vec`, making code clearer to follow.
Previously it was easy to confuse the two, and such confusion led to UB in `Traverse` (fixed in #23745).
Ditto other arena types - `ArenaHashMap`, `ArenaHashSet`, `ArenaStringBuilder`.
The only exceptions are:
1. Inside `oxc_allocator` crate itself.
2. AST type definitions.
3. Generated code (migrated separately in #23749).
Pure refactor.
It's a common pattern in repo to import `Vec` and `Box` etc from `oxc_allocator` and alias them to `ArenaBox` / `ArenaVec`.
```rust
use oxc_allocator::{Box as ArenaBox, Vec as ArenaVec};
```
Make this pattern less verbose by re-exporting `Box` and `Vec` as these aliases from `oxc_allocator`.
Ditto other arena types: `ArenaHashMap`, `ArenaHashSet`, `ArenaStringBuilder`.
Use those aliases in all other crates to shorten code.
```rust
use oxc_allocator::{ArenaBox, ArenaVec};
```
Previously, whether to serialize AST to ESTree JSON with/without TS fields was a compile-time option - via 2 different configs `CompactTSSerializer` and `CompactJSSerializer` (and their pretty-printing and with-fixes counterparts).
Turn this into a runtime option instead -
This make serialization a little slower (more branches in either mode, and dead code in JS-only mode) but reduces the size of `oxc-parser` binary as only one `ESTreeSerializer` is generated, instead of 2 (JS-only, and with-TS).
## Summary
Introduces `oxc_diagnostics::Diagnostics` — a `Vec<OxcDiagnostic>` newtype that knows the difference between errors and warnings — and makes it the standard diagnostics return value across oxc.
- **New type**: `Diagnostics` with `has_errors()`, `has_warnings()`, `errors()`, `warnings()`, plus `Vec`-like ergonomics (Deref, `IntoIterator`, `Extend`, `From`/`Into<Vec>`) so most call sites are unchanged.
- **Return types**: `ParserReturn`, `SemanticBuilderReturn`, `IsolatedDeclarationsReturn`, the React Compiler `TransformResult`/`LintResult`, and `TransformerReturn` now expose `diagnostics: Diagnostics` instead of `errors: Vec<OxcDiagnostic>` (the React Compiler's separate `errors`/`warnings` are merged into one severity-tagged list).
- **Behaviour**: a React Compiler **error** now stops the transform (no output), while **warnings** flow through and the transform continues. `compile()` aborts codegen only when `diagnostics.has_errors()` — warnings alone no longer abort (previously any diagnostic did).
## Breaking change
Consumers reading `*.errors` on these return values must read `*.diagnostics`. React Compiler consumers that read `.errors`/`.warnings` separately should use `diagnostics.has_errors()` / `diagnostics.errors()` / `diagnostics.warnings()`.
Parser/semantic/isolated-declarations fatality is otherwise unchanged. Builds on the React Compiler transform feature (#23201).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
Adds two named constructor presets to `SemanticBuilder` that bake in the options each use case needs, so the configuration lives in one place instead of being repeated at call sites:
- **`SemanticBuilder::new_compiler()`** — compiler pipeline. Enables syntax-error checking; leaves linter-only analyses (control flow graph, class table) off.
- **`SemanticBuilder::new_linter()`** — linter. Enables syntax-error checking, the control flow graph, and the class table.
The presets are applied at the real pipeline entry points:
- `new_linter()` → the linter service build.
- `new_compiler()` → `oxc::Compiler`, and the napi parser/transform bindings.
Everywhere else keeps `SemanticBuilder::new()` and turns on only the features it needs (mangler, minifier, formatter, transformer plugins, examples, tests, ...). Individual options can still be overridden after a preset (e.g. the linter service overrides `check_syntax_error` with its runtime flag).
Behavior is preserved at every migrated site. Node-store access is intentionally untouched in this PR.
## Verified
- Builds across the affected crates + napi; clippy clean; `oxc_linter` tests pass; full `cargo coverage` with no snapshot changes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Add a check that the input passed to raw transfer parser implementations is valid - both in `napi/parser` and in the raw transfer implementation used in Oxlint's `RuleTester`.
Check that `source_start` and `source_len` which are passed from JS side are within bounds of the active region of the `Arena`. This check is not strictly necessary - it's part of the safety contract, and is enforced on JS side - but it's critical as the setup of the `Arena` on Rust side depends on the accuracy of these values. If they were wrong, it could lead to reading/writing out of bounds. The check is cheap, so it seems worthwhile - safety trumps the tiny perf impact here.
The 3rd invariant of these functions is that the bytes in the buffer between `source_start` and `source_start + source_len` represent a valid UTF-8 string. Here a full runtime check isn't appropriate, as it would involve scanning and validating the whole source text string (expensive). But _do_ enable the full check in debug builds (used by raw transfer parser tests, and Oxlint conformance tests).
Oxlint's raw transfer implementation stores the source text at end of the buffer. Prior to this PR `napi/parser` stored source text at the start of the buffer.
Bring `napi/parser` into line with Oxlint, by also storing source text at end of the buffer.
Making all versions of raw transfer that we use align with each other removes complication (all versions now have the same implementation of `deserializeStr`) and also removes some fragile code where it'd be easy to accidentally trigger UB (see the updated comments in `arena/fixed_size/windows.rs` and `arena/alloc_impl.rs`).
Unfortunately, storing source at end of buffer is slightly less efficient than storing it at the start. We'll switch all implementations to storing source at start of buffer when we move to storing all strings (source text and all other strings) together in a single contiguous block. But in meantime, this slight inefficiency is outweighed by the gain in safety.
Refactor. Simplify raw transfer code in `napi/parser`, by consistently using `NonNull` pointers, rather than converting back and forth between `NonNull` and `*mut` pointers.
Large change to how raw transfer stores metadata about the allocations it uses.
Previously the two metadata structures `RawTransferMetadata` and `FixedSizeAllocator` after the chunk's `ChunkFooter`.
This had a few problems:
1. It was confusing and unwieldy - a recipe for bugs.
2. `ChunkFooter`'s memory was exposed on JS side - a bit unsafe as altering bytes in this region could easily trigger UB.
3. It entwined `Arena` (which is just the thing that allocates) with the details of exactly _what_ raw transfer allocates.
4. Imposed annoying alignment requirements, because `ChunkFooter` must be aligned on 16, and so anything after it must ensure it doesn't break that invariant.
Old layout:
```
WHOLE BLOCK - aligned on 4 GiB
<-----------------------------------------------------> Allocated block (`BLOCK_SIZE` bytes)
ALLOCATOR
<-----------------------------------------> `Allocator` chunk (`CHUNK_SIZE` bytes)
<----> `ChunkFooter` (aligned on 16)
<-----------------------------------> `Allocator` chunk data storage (for AST)
(`ACTIVE_SIZE` bytes)
METADATA
<----> `RawTransferMetadata`
<----> `FixedSizeAllocatorMetadata`
BUFFER SENT TO JS
<-----------------------------------------------> Buffer sent to JS (`BUFFER_SIZE` bytes)
```
This PR moves `RawTransferMetadata` and `FixedSizeAllocatorMetadata` into the chunk itself. New layout:
```
WHOLE BLOCK - size 2 GiB - 16, aligned on 4 GiB
<-----------------------------------------------------> Allocated block (`BLOCK_SIZE` bytes)
ARENA
<-----------------------------------------------------> Chunk (fills whole block)
<--------------------------------------> Allocatable region for AST (`ACTIVE_SIZE` bytes)
<---> `RawTransferMetadata`
<---> `FixedSizeAllocatorMetadata`
<---> `ChunkFooter` (aligned on 16, last in block)
BUFFER SENT TO JS
<-------------------------------------------> Buffer sent to JS (`BUFFER_SIZE` bytes)
```
`FixedSizeAllocatorMetadata` and `ChunkFooter` are no longer in the region which is shared with JS side. As far as `Arena` is concerned, they're now just some data (like any other data) which is allocated in the arena.
Also:
- Introduce more consistency to the naming of constants which specify the size and position of these various data structures in the arena.
- Add more const assertions to ensure everything is laid out and aligned as it should be.
Previously, fixed size allocators stored the pointer to the start of `Allocator`'s backing memory in `FixedSizeAllocatorMetadata`. Instead, store this pointer in `ChunkFooter`, in the field introduced in #21865.
#19885 added support for tokens in `oxc-parser`, but only via raw transfer and behind an undocumented `experimentalTokens` option. It's currently only used in tests for the purpose of conformance testing.
This slowed down `oxc-parser` a little (very little as the difference in execution time on Rust side is dwarfed by the cost of JSON transfer).
The worse effect is that it caused a large binary size increase in Rolldown (https://github.com/rolldown/rolldown/issues/9166) because Rolldown re-exports `napi/parser`'s Rust code, which meant that Rolldown now contains 2 versions of Oxc's parser with different `ParserConfig`s, leading to the entire parser being compiled and included in the binary twice.
Fix this by introducing a Cargo feature `tokens` on `napi/parser` crate. Only when `tokens` feature is enabled is a `ParserConfig` which generates tokens used. When disabled (the default), the default `ParserConfig` which does not produce tokens is used.
Enable the `tokens` feature only in tests.
Refactor.
Don't hard-code the minimum alignment of `Arena` chunks in `apps/oxlint` and `napi/parser`. Get the value from a property on `Allocator`. This will avoid this code getting out of sync if the value changes in future.
Also rename the vars `BUMP_ALIGN` to `ARENA_ALIGN`, as the arena type is now called `Arena` not `Bump`, and update some comments which were out of date.
For historical reasons, `oxc_span` crate was re-exporting string types which now live in `oxc_str` crate.
Remove these re-exports, and import these types directly from `oxc_str`.
Main motivation is just that it makes sense, but it should also have a minor positive effect on compile times - `oxc_span` and `oxc_str` crates can now be compiled in parallel.
`>>` is cheaper than `>>>` because `>>` produces a 32-bit _signed_ integer which is V8's native number type (SMI). `>>>` produces a 32-bit _unsigned_ integer, which needs to be boxed and stored on the heap.
Source text in raw transfer is limited to 1 GiB, and therefore source offsets, number of lines, number of tokens, and number of comments after all less than `1 << 30`. Therefore even the sum of 2 of them cannot reach `1 << 31` (the maximum positive integer which can be stored as a positive signed 31-bit int. Therefore it's safe to use `>>` in these binary loops.
Pure refactor.
Rename `Atom` to `Str`. The name "Atom" is a leftover from when we used to intern strings (years ago), and is misleading now.
Just call it `Str`. This follows the naming convention we have for arena-allocated versions of other types e.g. `Box`, `Vec`, `HashMap` - which we name the same as the native equivalents but with a lifetime (`Box<'a>` not `ArenaBox<'a>`, so `Str<'a>` not `ArenaStr<'a>`).
Rename all variables that contained "atom", and methods which relate to `Str`s to match the new type name.
Rename `as_atom` methods to `as_arena_str`. The longer name is required here to disambiguate from `as_str` methods which return a `&str`.
Some variables called "atom" still exist in `oxc_regular_expression` crate - that's a different meaning of "atom" - the meaning defined in regexp spec.
The diff of this PR is large but it's 100% renaming. No substantive or unrelated changes whatsoever.
Refactor. Generate assertions for type sizes in the order which they are in memory. This makes it easier to see how these types are laid out in memory.
Transfer tokens via raw transfer in Oxlint JS plugins.
Deserializer is written by hand. `Token` is not a normal struct, so deserializer cannot be generated.
Implement the beginnings of support for tokens in `napi/parser`.
This PR only adds support for tokens via raw transfer, and behind an undocumented `experimentalTokens` option.
Add tests checking that tokens received on JS side via raw transfer match snapshots for all Test262, AcornJSX, and TypeScript test cases. They do!
The tests are the main purpose of this PR, making sure it works before we switch over to tokens via raw transfer in Oxlint.
We can add full tokens support to `napi/parser` (including via JSON transfer) later on.
Builds on #19497. Use the tokens generated by Oxc's parser in linter plugins, instead of running TS parser to tokenize source.
This is a sizeable perf gain, and also allows us to remove TS parser from `oxlint`'s bundle (#19531).
Additionally, our parser is more accurate than TypeScript - we handle HTML comments and space before slash in closing JSX elements (`< /div>`) - so this fixes a few conformance tests.
## Summary
- Add `pub node_id: NodeId` as the first field in all AST structs (~190 structs across js.rs, ts.rs, jsx.rs, literal.rs)
- Update codegen to special-case `node_id`:
- `Dummy`: Use `NodeId::DUMMY` instead of `Dummy::dummy(allocator)`
- `CloneIn`: Use `NodeId::DUMMY` for regular clone, preserve ID for semantic clone
- `ContentEq`: Skip `node_id` from equality comparisons
- `ESTree`: Skip `node_id` from serialization
- `AstBuilder`: Exclude `node_id` from builder parameters, use `NodeId::DUMMY`
- Update pattern matching in minifier and transformer to use `..` for new field
- Update traverse script to include `NodeId` import
This is the foundational step for assigning unique IDs to AST nodes. The `node_id` defaults to `NodeId::DUMMY` (value 0) for uninitialized nodes.
## Test plan
- [x] `cargo build` succeeds
- [x] `cargo test` passes
- [x] `just ast` regenerates code correctly
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
- Disable mimalloc as the global allocator on Windows for all NAPI packages (`oxc-parser`, `oxc-minify`, `oxc-transform`)
- On Windows, packages now use the system allocator instead
Fixes#15518
## Root Cause
mimalloc has known issues with DLL unloading on Windows when the DLL is loaded by the main thread but unloaded by a worker thread ([mimalloc issue #288](https://github.com/microsoft/mimalloc/issues/288)). The cleanup code has `_mi_is_main_thread()` checks that prevent proper memory cleanup when called from a non-main thread, causing `STATUS_ACCESS_VIOLATION` crashes.
## Platforms with mimalloc enabled
| Platform | mimalloc |
|----------|----------|
| macOS | ✅ |
| Linux x86_64 | ✅ |
| Linux aarch64 | ✅ |
| Windows | ❌ (disabled) |
| FreeBSD | ❌ |
| ARM 32-bit | ❌ |
| WASM | ❌ |
🤖 Generated with [Claude Code](https://claude.ai/code)
Previously we had to store source text at start of buffers sent to JS via raw transfer.
#18376 made changes to how raw transfer deserializer handles strings, in order to support files containing a BOM. Building on that, we're now able to remove the requirement that source text be at start of the buffer entirely.
This PR changes the deserializer used in Oxlint JS plugins to accept source text being anywhere in the buffer, *as long as no other strings are after it*. In practice this just means that the source text must be allocated before anything else, which is easy to satisfy.
Now the source text can be allocated with just the usual safe `allocator.alloc_str(source_text)` method.
This change removes a ton of dodgy workarounds and unsafe code we used previously to get source text at the start of buffer. It makes the code less labyrinthine and far less likely a slip up can inadvertently introduce UB.
Note: In `napi/parser`, source text still *is* at start of the buffer, as that's simpler and more efficient when the source text is written into the buffer on JS side. This change only affects Oxlint.
## Summary
- Add detailed JSDoc documentation to `parse` and `parseSync` functions explaining their performance characteristics
- Clarify that `parseSync` is generally preferable since AST deserialization happens on the main thread anyway
- Recommend using worker threads with `parseSync` for parallelizing multiple files
Closes#15361🤖 Generated with [Claude Code](https://claude.ai/code)
Closes#12526.
Handle BOM on start of files in the same way that ESLint does - do not include it in the source text on JS side, but `context.sourceCode.hasBOM` evaluates to `true`.
Method:
* Alter `program.source_text` to trim off the BOM before passing AST to JS side.
* Add a `has_bom` flag to `RawTransferMetadata`.
* Add ability to add an offset in the conversion from UTF-8 to UTF-16 spans.
The result is that the file as it's seen on JS side is as if the BOM didn't exist (except for the `hasBOM` flag). Spans are converted accordingly in JS-side AST, and converted back when passing diagnostics back to Rust.
#18089 added support in parser for `commonjs` source type.
Extend this support to the NAPI packages - accept `sourceType: 'commonjs'` in options for `oxc-parser` and `oxc-transform`.
## Summary
Now that bumpalo has been inlined into oxc_allocator (#18168), this PR cleans up comments and documentation that still reference bumpalo as an external dependency.
- Update module docs in `bump.rs` and `bumpalo_alloc.rs` to say "originally derived from" instead of "ported from"
- Remove obsolete comments about bumpalo version pinning in `from_raw_parts.rs`
- Update inline comments in `allocator.rs` from "delegates to bumpalo" to "it's a small function"
- Remove outdated TODO about replacing bumpalo in `tracking.rs`
- Update `ARCHITECTURE.md` and parser docs to reference `oxc_allocator` instead of bumpalo
- Clean up bumpalo references in other crates (`oxc_semantic`, `oxc_data_structures`, `apps/oxlint`, `napi/parser`, `tasks/ast_tools`)
## Test plan
- [x] `cargo check -p oxc_allocator` passes
- [x] `cargo test -p oxc_allocator` passes
- [x] Changes are documentation/comment only - no functional changes
🤖 Generated with [Claude Code](https://claude.ai/code)
When parsing tokens for JS plugins, the TypeScript parser was always using `ScriptKind.TSX`, regardless of file extension. This caused TypeScript to incorrectly parse generic arrow functions like `<T>() => {}` in `.ts` files, creating bogus `JsxText` tokens that overlap with comments.
This PR adds an `is_jsx` flag to `RawTransferMetadata`. Rust side sets the flag depending on source type, and JS side uses that information to pass the correct `ScriptKind` for the file to TypeScript parser.
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: overlookmotel <theoverlookmotel@gmail.com>
Follow-on after #16383 and #16403.
While working on those I discovered an option NAPI-RS has to represent `Option::None` as `null`, instead of omitting the field entirely.
Use that option on the structs used for transferring errors and module record over to JS.
I think this is likely more performant because:
1. NAPI-RS can create all properties of the objects using only the faster `node_api_create_object_with_properties` API.
2. It produces consistent object shapes, so JS engine can better optimize code using these objects.
It also brings the shape of the data perfectly into line between standard transfer and raw transfer, and is consistent with how empty fields in the AST are represented as `null`.
I would have used this option before if I'd known it existed.
### Breaking change
I've marked this as a breaking change because code consuming these objects would now need to check for empty fields with `value === null` instead of `value === undefined`.
However in practice, most people probably use `!value` or `value ?? ...`, so it's unlikely to affect many users. This only affects module record and errors anyway, not the AST itself, as we transfer that as JSON, not via NAPI.
NAPI-RS 3.6.0 makes a change to the ordering of objects. It now puts optional fields last.
This made tests in `napi/parser` for module record fail when we tried to update (#16383) because the `module_request` field of `ExportEntry` moves to last which breaks the snapshots.
The change in NAPI-RS is unlikely to be reverted, because it's a sizeable perf optimization: https://github.com/napi-rs/napi-rs/pull/2990
To work around this problem:
1. Move the field in the `ExportEntry` intermediate struct in `napi/parser` to last, so NAPI's output matches what you'd expect from the struct definition.
2. Alter the `#[estree]` attr on `ExportEntry` struct in `oxc_syntax` crate to match.
Note: The `ExportEntry` struct in `napi/parser` is just an intermediate structure used for serialization. So I think it's fine to fiddle with its field order. The actual `ExportEntry` struct used in the module record is in `oxc_syntax` crate, and it remains unaltered.
Pure refactor. Instead of having 2 feature-gated implementations of `raw_transfer_supported`, just have one. This makes it clearer on what platforms raw transfer is supported.
Pure refactor. Remove blanket disable of `clippy::needless_pass_by_value` lint rule, and disable it on individual NAPI functions instead. This reveals one other function which was taking a `String` when it could take a `&str`.
Fixes#13694.
Some 32-bit platforms give `u64` and `f64` alignment of 8, and others alignment of 4. WASM32 uses alignment 8, and layout calculator assumes that.
Skip layout assertions for platforms where alignment is 4, because we know some layouts are wrong for those platforms, and it causes compilation failure in debug builds. But retain the assertions for other 32-bit platforms (notably WASM), to make sure they remain correct. This will make it easier to extend raw transfer support to WASM later on.
Pure refactor. All these generated modules have no exports, so importing them with `pub mod` is misleading - there is nothing to make public. Import them with plain `mod` instead.
```diff
mod generated {
- pub mod assert_layouts;
+ mod assert_layouts;
}
```
Tiny perf optimization.
Reduce complexity of maths by doing as much calculation as possible using consts.
Shaves off 1 operation! https://godbolt.org/z/5h4hzznxs
This change does not alter the result. `data_offset + RAW_METADATA_SIZE` couldn't overflow because `data_offset` was derived from a `u32`, and this code (raw transfer) is only run on 64-bit systems, so there's plenty of headroom in `usize`. But it does make it easier to support 32-bit in future.
Pure refactor. When this code was written, `usize::is_multiple_of` was not available in our MSRV. Now it is, so use it instead of writing the same function ourselves.
Refactor to oxlint JS plugins and raw transfer. Remove source text length field from `RawTransferMetadata`. It's not necessary - source text is part of `Program`, so the length can be obtained from there, it doesn't need to be duplicated.
Add a field `source_len` to `RawTransferData`, which stores the byte length of source text.
In `napi/parser`, this wasn't required, as the source text is passed in from JS side, so JS already knows how long it is. But in linter, source text passes in the opposite direction, so Rust needs to tell JS it's length. It will do so by recording it in this field, and JS reads it from the buffer.
`RawTransferMetadata` is used to store basic info about the data in the buffer which is used on JS side to locate `Program` in the buffer etc.
This struct lives in `napi/parser` crate but we're going to need it in `napi/oxlint2` too. So make a 2nd copy of it in `napi/oxlint2` and use `oxc_ast_tools` to enforce that the 2 copies are identical.
This is a bit of a hack, but it doesn't seem worthwhile creating a new crate just to hold this one struct, and it doesn't really fit in `oxc_allocator`, or any of our other existing crates.