Commit Graph

798 Commits

Author SHA1 Message Date
overlookmotel 54f9464ad9 test(napi/parser): add benchmarks for lazy visit alone (#11866)
Add benchmarks for lazy visitor in isolation (i.e. without also parsing).
2025-06-23 12:39:19 +00:00
overlookmotel 6c5ee78b51 perf(napi/parser): lazy visit: cheaper for loop (#11864)
Tiny optimization to lazy visitor. It's marginally cheaper in a loop to compare to 0, rather than to a constant. I also assume that `!== 0` is cheaper than `> 0` as it doesn't involve type coercion.
2025-06-23 12:07:09 +00:00
overlookmotel 97b671f393 test(napi/parser): load internal modules with require in benchmarks (#11865)
Improve raw transfer benchmarks. Use `require` to load internal modules instead of `import`. `oxc-parser` uses `require` internally, so using `import` here was resulting in a lot of code being loaded and instantiated twice.
2025-06-23 11:59:33 +00:00
overlookmotel 0bf7815040 refactor(napi/parser): lazy visitor: pre-calculate count of node types (#11861)
Pure refactor. Pre-calculate number of node types in codegen. This prepares the way for replacing the `Map` with a plain JS object.
2025-06-23 12:46:08 +01:00
oxc-bot 94a418d201 release(crates): v0.74.0 (#11853) 2025-06-23 13:27:08 +08:00
renovate[bot] 15d84be165 chore(deps): lock file maintenance npm packages (#11850) 2025-06-23 13:02:38 +08:00
overlookmotel 93069a5b6c feat(napi/parser): add experimental lazy visitor (#11837)
Add lazy visitor to `oxc-parser`.

This API is experimental and not ready for use yet. AST is not ESTree-compatible at present (same as lazy deserializer).

Usage:

```js
import { parseSync, experimentalGetLazyVisitor } from 'oxc-parser';

// Get `Visitor` class.
// `Visitor` is not exported directly from `oxc-parser` as all code
// related to lazy deserialization is lazy-loaded.
const Visitor = experimentalGetLazyVisitor();

// Define visitor.
// This visitor counts how many identifiers in AST.
let identCount = 0;
const visitor = new Visitor({
  BindingIdentifier(ident) {
    identCount++;
  },
  IdentifierReference(ident) {
    identCount++;
  },
  IdentifierName(ident) {
    identCount++;
  },
});

const code = 'let x, y; x = { z: 2 };';
const { visit, dispose } = parseSync('test.js', code, { experimentalLazy: true });

visit(visitor);

assert(identCount === 4);

// Dispose of AST now we're done with it.
// This returns buffer storing AST data to the pool for reuse.
dispose();
```
2025-06-20 18:23:56 +00:00
overlookmotel 0260308afa refactor(ast_tools): prepare lazy deserializer codegen for visitor (#11836)
Pure refactor. Adapt lazy deserialization codegen in preparation for adding lazy visitor. Involves introducing a `State` struct, renaming things, and moving code around. No substantive changes.
2025-06-20 15:40:48 +00:00
overlookmotel b544be8fad refactor(napi/parser): remove options amendment from prepareRaw (#11828)
Pure refactor (raw transfer). Remove logic for amending `options` objects from `prepareRaw`. It's an unnatural place for it.
2025-06-20 10:11:35 +00:00
overlookmotel 6bbe048c98 perf(napi/parser): do not lazily create TextEncoder (#11817)
Tiny perf optimization to raw transfer. #11807 made this whole file lazy-loaded, so no need to lazily create the `TextEncoder` any more. If the file is imported, it's going to be used.
2025-06-19 14:05:00 +00:00
overlookmotel 4dc8a4e63b docs(napi/parser): add JSDoc comments to all functions (#11814)
Add JSDoc comments to all functions in `napi/parser`.
2025-06-19 14:05:00 +00:00
overlookmotel 9c960cd0d7 refactor(napi/parser): re-order code (#11813)
Pure refactor. Move `parseSync` to be before `parseAsync`, for consistency with all other code in `napi/parser`. Hoist all exports to top of file to make it a little more readable.
2025-06-19 13:21:50 +00:00
overlookmotel aef1770053 perf(napi/parser): destructure bindings on import (#11811)
Small perf optimization to `oxc-parser`. Destructure `bindings` object when importing it. Calling those methods repeatedly later on avoids overhead of an object property lookup each time.

The effect is infinitesimal, except when using lazy deserialization, which is so fast for small files that it makes sense to optimize every step of its call path.
2025-06-19 13:01:22 +00:00
overlookmotel bfed7f21ab refactor(napi/parser): rename file (#11808)
Pure refactor. Rename `raw-transfer/index.js` to `raw-transfer/common.js`. After #11807, it's no longer the entry point, so `index.js` is misleading.
2025-06-19 12:33:11 +00:00
overlookmotel 3a0a673b31 perf(napi/parser): lazy-load raw transfer and lazy deser code (#11807)
Raw transfer and raw lazy deserialization are experimental and not publicly advertised. Lazy-load all code for these features only when they're first used.

Lazy deserialization in particular requires a non-trivial amount of code.

`rawTransferSupported` still needs to be eagerly loaded, as user would call it before calling `parseSync` or `parseAsync`. So move it into a separate module.
2025-06-19 12:33:11 +00:00
overlookmotel 08e666fc2d refactor(ast/estree): add #[estree] attrs to RegExpFlagsAlias (#11794)
Pure refactor. Add more `#[estree]` attributes to `RegExpFlagsAlias` type. These have no effect on generated code for JSON serialization or raw transfer deserialization, as `RegExpFlagsAlias` already has a custom converter. But it simplifies the codegen for lazy deserialization.
2025-06-18 13:02:21 +00:00
oxc-bot 3de6b99990 release(crates): v0.73.2 (#11785) 2025-06-18 13:23:17 +08:00
overlookmotel 21c8852bde perf(napi/parser): faster deserialization of Vecs in raw transfer (#11776)
Small perf optimization to raw transfer. Don't use 2 different counters in the loop when deserializing `Vec`s. Do what Rust's slice iterators do, and use current and end pointers.
2025-06-17 13:56:36 +00:00
overlookmotel a47a6de311 fix(napi/parser): lazy deser: do not expose getElement method from NodeArray (#11777)
`getElement` is an internal method. Don't publicly expose it on `NodeArray` class.
2025-06-17 13:49:09 +00:00
oxc-bot 14f7033f66 release(crates): v0.73.1 (#11774) 2025-06-17 21:17:38 +08:00
LongYinan 81ef44329f feat(napi): add aarch64-linux-android target (#11769)
- Close https://github.com/oxc-project/oxc/issues/11566
2025-06-17 15:46:41 +08:00
overlookmotel 6feab7e748 fix(ast/estree): remove custom serializer for MethodDefinition key field (#11763)
Remove the custom ESTree serializer for `MethodDefinition`'s `key` field. This serializer was required to replicate a bug in TS-ESLint, which they've now fixed. This fixes the test case which was broken by #11762.
2025-06-16 21:37:42 +00:00
renovate[bot] 9525250ccb chore(deps): lock file maintenance npm packages (#11731) 2025-06-16 10:14:59 +08:00
overlookmotel 20efcd4bbf test(napi/parser): remove unnecessary RUN_SIMPLE_LAZY_TESTS env var (#11703)
This is unnecessary. One env var is sufficient.
2025-06-14 12:16:24 +00:00
overlookmotel 6848b242f3 test(napi/parser): lazy deser: tests for introspection of NodeArrays (#11702)
Add tests for results of `Object.keys`, `Object.getOwnPropertyDescriptors`, and other introspection methods on `NodeArray`s.
2025-06-14 12:16:24 +00:00
overlookmotel fcb3084f74 fix(napi/parser): lazy deser: remove outdated comments (#11699)
Remove outdated comments, and clean up comments for `NodeArray`.
2025-06-14 11:24:39 +00:00
overlookmotel d136acdf53 perf(napi/parser): lazy deser: remove getInternal function in NodeArray (#11698)
Move `getElement` function into `NodeArray` class definition, to avoid extra function call to intermediate `getInternal`. This is a hot path, so streamlining it is important for perf.
2025-06-14 10:55:57 +00:00
overlookmotel a6a82f9995 perf(napi/parser): lazy deser: avoid changing shape of NodeArray prototype (#11697)
Simple object shapes are faster. Adding extra property to `NodeArray.prototype` alters its shape. Prevent this by defining a placeholder method in class definition, and then mutating this property later, rather than adding a new property.
2025-06-14 10:55:57 +00:00
Ulrich Stark d057652c19 refactor(regular-expression): shorten Span construction (#11689) 2025-06-14 12:17:14 +08:00
overlookmotel dfdebc27e3 feat(napi/parser): lazy deserializer NodeArray slice method (#11680)
Implement an optimized `slice` method for `NodeArray` in lazy-deserialized AST. It returns a another `NodeArray`, instead of a plain `Array`, and doesn't deserialize any of the contents.
2025-06-13 18:31:18 +00:00
overlookmotel 2749931a40 fix(napi/parser): lazy deserializer block class constructors correctly (#11679)
Ensure get the appropriate error when user calls a forbidden class constructor for a lazy-deserializing type. Move code for this to a shared module.
2025-06-13 17:39:18 +00:00
overlookmotel 60f754e37c perf(napi/parser): lazily deserialize Vecs (#11678)
Lazy deserialization return `NodeArray`s which deserialize their contents lazily, instead of plain JS arrays.

`program.body.find(stmt => stmt.type === 'ImportDeclaration')` now only deserializes the nodes up until first `ImportDeclaration`, rather than deserializing every statement in the program into an array, and then searching it. Similarly getting `program.body.length` does not deserialize any nodes, and all other array methods are similarly optimized.

Also provide an optimized iterator for the common case of:

```js
for (const stmt of program.body) {
  doStuff(stmt);
}
```
2025-06-13 16:45:15 +00:00
overlookmotel f1f3c30606 refactor(napi/parser): lazy deserializer: prefix local cache property keys with $ (#11673)
Pure refactor. We prefix some property names on `internal` objects with `$` to avoid clashes between static properties (`pos`, `ast`) and cached fields. Switch the prefixing around - now prefix keys for cached fields, so the internal properties are called e.g. `pos` not `$pos`. This shortens generated code, and makes writing implementations simpler.
2025-06-13 12:41:13 +00:00
overlookmotel e523d864ea fix(napi/parser): lazy deserializer locally cache all Vecs and strings (#11667)
Fix a bug in lazy deserializer where `Vec`s were not getting cached because they were wrapped in `Option`. When determining if a node's field needs to be locally cached, drill down through any wrapping `Option`s / `Box`es / `Cell`s / enums.
2025-06-13 10:44:05 +00:00
oxc-bot e7af8c470c release(crates): v0.73.0 (#11669) 2025-06-13 18:33:56 +08:00
overlookmotel 586019549d feat(napi/parser): improved console.log output for lazy deserialized AST (#11642)
Improve the output from `console.log` when printing a lazy-deserialized AST.

Previously `console.log(program)` printed `Program { type: 'Program' }`. Now it prints much the same as a normal (eagerly deserialized) AST:

```
Program {
  type: 'Program',
  start: 0,
  end: 17,
  sourceType: SourceType { sourceType: 'module' },
  hashbang: null,
  body: [
    VariableDeclaration {
      type: 'VariableDeclaration',
      start: 0,
      end: 10,
      kind: 'let',
      declarations: [Array],
      declare: false
    }
  ]
}
```
2025-06-12 16:05:00 +00:00
overlookmotel 931fc739c3 fix(napi/parser): cache nodes in lazy deserialization (#11637)
In lazy-deserialized AST, cache node objects, so accessing the same field twice returns the same object. Previously `assert(binaryExpression.left == binaryExpression.left)` would fail, as each access returned a new object.

`pos` (i.e. memory address) is used as the cache key, with 2 exceptions: `RegExp` and `Program`.

`RegExp` doesn't have a `span: Span` field, so its first field `RegExpPattern` has the same memory address as the `RegExp`. So `pos` would not be a unique key.

```rs
pub struct RegExp<'a> {
    pub pattern: RegExpPattern<'a>,
    pub flags: RegExpFlags,
}

pub struct RegExpPattern<'a> {
    pub text: Atom<'a>,
    pub pattern: Option<Box<'a, Pattern<'a>>>,
}
```

The codegen identifies these cases, and applies a workaround - `pos + 1` is used as the cache key instead of `pos`, so the parent and child have different cache keys.
2025-06-12 14:26:06 +00:00
overlookmotel 8cab72fb79 test(napi/parser): env var to run lazy deserialization tests (#11636)
Enable lazy deserialization tests in `napi/parser` with `RUN_LAZY_TESTS=true pnpm test`. This is easier to use than a hard-coded value.
2025-06-12 12:43:03 +00:00
overlookmotel 0bdf718230 chore(napi)!: drop support for NodeJS before v20 in oxc-parser (#11586)
Drop support for NodeJS before v20 in `oxc-parser` NPM package.

All versions of NodeJS earlier than v20 are now EOL. I don't think we need to support them.

https://nodejs.org/en/about/previous-releases

I would like to use `FinalizationRegistry`, which is not available in Node v14 (our current lowest supported version).
2025-06-12 09:53:06 +00:00
overlookmotel 8ad30611b2 test(napi/parser): run raw transfer tests on multiple threads (#11611)
Fix #10519.

Run raw transfer tests across multiple threads. Vitest can run multiple test *files* in parallel on separate threads, but it doesn't have ability to run test *cases* in the same file in parallel.

So create a worker pool and send details of each test case to the workers, which then run them in parallel.

On my machine, this cuts down the time to run `napi/parser` tests by a factor of 3 - from 19s to 6s.

Also: Fix `parseAsync` tests: `Promise`s weren't being `await`-ed, and cut down number of iterations on `parseAsync` test from 100,000 to 10,000 so it completes in a reasonable amount of time.
2025-06-12 03:44:00 +00:00
overlookmotel ff7111ce52 refactor(napi/parser): use "construct" instead of "deserialize" in lazy deserializer (#11616)
Use the term "construct" for creating an AST node object in lazy deserializer. "Deserialize" was the wrong word to use, because the whole point is that it *doesn't* deserialize until you ask it to.
2025-06-11 22:52:12 +00:00
overlookmotel 5271951d48 perf(napi/parser): remove function calls from lazy deserialization (#11615)
Remove unnecessary intermediate functions from lazy deserializer. To create a node object, you can construct the node class directly.
2025-06-11 19:03:27 +00:00
overlookmotel 5a55a5856e feat(napi/parser): add lazy deserialization (#11595)
First iteration of lazy deserialization. It works (does not throw an error on any of Test262 or TS test cases), but has some major shortcomings at present:

* Does not match ESTree - shape of AST is more like our Rust types.
* Some missing fields.
* `Vec`s are not lazily deserialized.
* No caching of nodes, so you get a different object each time you get a node e.g. `assert(binaryExpression.left == binaryExpression.left)` fails!

Note: This is a lazy deserializer, which is first step towards a lazy visitor. But there's no visitor implemented yet.

I will build on this starting point in future PRs.
2025-06-11 15:04:19 +00:00
overlookmotel 120b00f98a feat(napi/parser): support old versions of NodeJS (#11596)
Add a fallback for `os.availableParallelism` in versions of NodeJS prior to v18.14.0, which don't support it.

As requested by Prettier, who support NodeJS v14. https://github.com/oxc-project/oxc/pull/11583#pullrequestreview-2913819661
2025-06-11 15:04:19 +00:00
overlookmotel 7c66637878 perf(napi/parser): re-use TypedArray objects in raw transfer (#11585)
Small optimization to raw transfer. Reuse the same `Uint32Array` and `Float64Array`, rather than re-creating them for each file.
2025-06-11 15:04:19 +00:00
overlookmotel c0027e0358 test(ast/estree): benchmark raw transfer deserialization in isolation (#11584)
Add a benchmark for just the deserialization part (JS side) of raw transfer.
2025-06-11 15:04:18 +00:00
overlookmotel 95ee174347 refactor(napi/parser): move raw transfer code into separate directory (#11583)
Pure refactor. Move code for raw transfer into separate directory. This will enable exposing some internals to benchmarks without exposing them publicly from the package. Also lazy deserialization is going to add a lot more code - don't want `index.js` to get too bloated.

Also make main entry point `index.js` run in strict mode (doesn't much matter, but it's good practice).
2025-06-11 15:04:18 +00:00
overlookmotel 8e74e05a60 refactor(ast/estree): remove dead code from generated raw transfer deserializer (#11579)
Remove dead code for deserializing `Option`s, `Box`es and `Vec`s of types which are not included in ESTree AST (e.g. `oxc_regular_expression` types).
2025-06-09 18:44:38 +00:00
renovate[bot] 888b9c8d43 chore(deps): lock file maintenance npm packages (#11557) 2025-06-09 14:34:46 +08:00
overlookmotel f3eaefbf1b feat(ast)!: add value field to BigIntLiteral (#11564)
Add `value` field to `BigIntLiteral`, same as the other literal types.

Once upon a time, we stored the value as a `BigInt` which normalized the representation (removing `_`s, and converting e.g. `0xFF` to `255`). But we had to remove it because `BigInt` owns a heap allocation, and this caused a memory leak.

https://github.com/oxc-project/oxc/commit/50fe0fef73027f10740e68a65a78216933b5d8a0

This PR brings back the `value` field, but avoids memory leak by storing the normalized value as a string (`Atom`).

This has effects in various places in the codebase:

* Brings our JS-side AST into line with ESTree (fixing the test cases broken by #11563).
* Fixes edge cases in a couple of lint rules.
* Codegen now prints bigints in normalized form e.g. `0xFFn` is printed as `255n`.
* Changes behavior of 1 function in `oxc_ecmascript`.

I've made comments below on the parts I'm not so sure about. Review would be very welcome!
2025-06-09 02:28:46 +00:00