Commit Graph

51 Commits

Author SHA1 Message Date
Boshen 030857b509 refactor(diagnostics): update oxc-miette to v4 (#25395)
Remove the miette `Report` wrapper and update oxc-miette to v4's narrowed diagnostic and source protocol.

AI-assisted by OpenAI Codex.
2026-08-10 07:48:02 +00:00
camc314 2ab679af2b chore(napi/parser): enable noImplicitAny (#23830)
follow on from my other changes to this code earlier today
2026-06-26 16:23:41 +00:00
overlookmotel 6e8fa809f5 feat(napi/parser, napi/transform): accept sourceType: "commonjs" (#18197)
#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`.
2026-01-19 04:39:04 +00:00
overlookmotel 2fbc39e501 test(napi/parser): correct nesting of tests (#18193)
Refactor tests. The tests for `ImportDeclaration` and `ImportExpression` had somehow got nested within the tests for `TemplateExpression`. Move them to a better place.
2026-01-18 21:14:16 +00:00
Boshen 66b8c022ab feat(parser): implement unambiguous module parsing for JS/TS files (#18124)
## Summary

- Implements speculative/unambiguous parsing for `.js`, `.jsx`, `.ts`, and `.tsx` files
- Instead of assuming module or script upfront, parses with `ModuleKind::Unambiguous` and upgrades to module mode when ESM syntax is detected
- ESM indicators: `import`, `export`, `import.meta` (NOT top-level await alone)
- Defers top-level await errors until module type is resolved
- Vue loader upgrades unambiguous scripts to module mode
- Updates linter tests to use explicit ESM extensions (`.mjs`/`.mts`) where needed

## Test plan

- [x] All parser tests pass
- [x] All linter tests pass
- [x] All semantic tests pass
- [x] Coverage conformance tests updated

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-01-17 13:40:28 +00:00
camc314 af0f2af93f chore(lint): enable ban-ts-comment rule and fix ts-ignore usages (#16799)
follow on from https://github.com/oxc-project/oxc/pull/16796
2025-12-13 16:19:48 +00:00
overlookmotel 083fea9fa6 feat(napi/parser)!: represent empty optional fields on JS side as null (#16411)
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.
2025-12-02 23:30:56 +00:00
overlookmotel 3068658c30 style(napi/parser): prefer const to let (#16386)
Use `const` where variables are not reassigned instead of `let`. Preparation for enabling ESLint's `prefer-const` rule (running as an Oxlint JS plugin) in our linting setup.
2025-12-02 10:27:27 +00:00
Boshen 523a30a016 style(all): apply oxfmt default options (#16091)
Embrace the defaults!

---------

Co-authored-by: Yuji Sugiura <y.sugiura.0316@gmail.com>
2025-11-25 15:56:24 +09:00
Boshen ea51b0b5c8 feat(napi)!: standardize function naming with sync suffixes (#15661)
closes #15576

## Summary

Standardizes function naming across all NAPI packages (parser, transform, minify) with a consistent pattern:
- Async functions: `verb` (no suffix)
- Sync functions: `verbSync` (with Sync suffix)

## Changes

### Breaking Changes

**napi/parser:**
- `parseAsync` → `parse` (async)
- `parseSync` remains unchanged (sync)

**napi/transform:**
- `transformAsync` → `transform` (async)
- `transform` → `transformSync` (sync)
- `isolatedDeclaration` → `isolatedDeclarationSync` (sync)
- Added new `isolatedDeclaration` function (async)
- `moduleRunnerTransform` → `moduleRunnerTransformSync` (sync)
- Added new `moduleRunnerTransform` function (async)

**napi/minify:**
- `minify` → `minifySync` (sync)
- Added new `minify` function (async)

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2025-11-13 12:28:23 +00:00
sapphi-red 682dca2ea7 feat(parser): add more helps to parser errors (#15186)
Added more helps to parser errors to make it easier to understand how the error can be resolved.
2025-10-31 07:10:45 +00:00
leaysgur a8e5181ab7 chore(infra): dogfooding oxfmt (#14979)
Fixes #14803

- Added `oxfmt` and `oxfmtrc.jsonc`
- Remove `dprint` plugin and useless ignore paths
- Apply `dprint` again
- Apply `oxfmt`
2025-10-28 01:16:46 +00:00
overlookmotel bb040bc2d5 refactor(parser, linter): replace .mjs files with .js (#14045)
Now that `apps/oxlint` and `napi/parser` are both ESM packages (#13723 and #14042), we can use `.js` file extensions for all ESM files, rather than the mix of `.js` and `.mjs` file we had previously.

It's less confusing having to remember what's `.js` and what's `.mjs`, and avoids ugly workarounds like #14038 (`.d.mts`??).
2025-09-23 14:47:40 +00:00
overlookmotel 55cd2f3058 test(parser): remove unused import (#14043) 2025-09-23 13:15:33 +00:00
overlookmotel 56a385fe94 feat(napi/parser): add AST walker (#13930)
Add an AST visitor to `oxc-parser`.

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

const { program } = parseSync('test.js', 'let x = { y: z };');

const idents = [];
const visitor = new Visitor({
  Identifier(node) {
    idents.push(node.name);
  }
});

visitor.visit(program);

// Logs [ 'x', 'y', 'z' ]
console.log(idents);
```

Primarily we need a visitor for Oxlint plugins, but it's easier to develop and test in `oxc-parser`, so I thought I'd add it there first. Oxlint build process will copy the generated files for tree-walking from `napi/parser` dir, as it does with other files.

Notes:

* The `walk.mjs` file is large, so it's lazy-loaded only when user first constructs a `Visitor`. Adding `Visitor` to the package will not affect start-up time where user only uses `parseSync` etc.
* TS type definition for `Visitor` and the visitor object it takes are provided.
* Visitor supports enter and exit visitors e.g. `Program` and `Program:exit`.
* `src-js/visit/visitor.mjs` is copied from `apps/oxlint` with only minor modifications, and conversion from TS to JS. It'd be better if we only had this impl in one place, but that would require converting `oxc-parser` to TS and building with TSDown, like `oxlint` is. Leaving that for later - #13935.
2025-09-22 11:08:46 +00:00
overlookmotel 4ee94a3308 feat(napi/parser): export visitor keys (#13927)
Add visitor keys export to `oxc-parser` NPM package. This is useful in itself, but also the first step towards an ESTree walker.

Visitor keys are based on `@typescript-eslint/visitor-keys`.

It'd be ideal to generate visitor keys direct from Oxc's own types, but that's proving difficult due to all the custom serializers we use to translate to ESTree. So using the shortcut of borrowing from TS-ESLint for now.

Oxc's AST is slightly different from TS-ESTree (notably Oxc's AST adds `ParenthesizedExpression`). But apart from those few differences, TS-ESLint's AST and Oxc's are identical, and I made a PR to TS-ESLint earlier this year (https://github.com/typescript-eslint/typescript-eslint/pull/11279) to ensure visitor key order is correct, and matches Oxc.

To avoid adding a runtime dependency on `@typescript-eslint/visitor-keys`, extract the data from TS-ESLint in `oxc_ast_tools`, amend for Oxc/TS-ESTree differences, and re-output it as a simple object literal.

This approach will be faster at runtime, as the object's shape is consistent, and also avoids a dependency.
2025-09-22 11:08:46 +00:00
overlookmotel ac3e9e966a refactor(napi/parser): move JS code into src-js directory (#13899)
Pure refactor. Root of `napi/parser` was getting really crowded with tons of files, and I'm about to add a load more for the ESTree walker.

Move JS source files into a `src-js` directory, like in `apps/oxlint`, so that the root of the package is just config files and scripts.
2025-09-19 08:46:42 +00:00
Boshen 4577b71ec8 feat(napi/parser)!: change oxc-parser to ESM (#13432)
closes #13329
2025-09-08 10:53:05 +00:00
Boshen 407429a09c feat(napi/parser,napi/transform): accept lang=dts (#12154) 2025-07-09 09:13:18 +00:00
Bacary Bruno Bodian 9a2548ae9d feat(napi/parser)!: add range option (#11728)
Part of #10307. Add `range` option to `oxc-parser`, to add `range` property to nodes in ESTree AST.

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: overlookmotel <theoverlookmotel@gmail.com>
2025-06-24 02:23:27 +01:00
overlookmotel 23182b811a feat(ast/estree): add phase field to ImportExpression in TS-ESTree AST (#11193)
Related to #10978. Add `phase` property to `ImportExpression` in TS-ESTree AST.

This aligns with ESTree spec, but does *not* align with TS-ESLint - TS-ESLint outputs a `CallExpression` with a `MetaProperty` as its `callee` instead.

We don't have the necessary information in our AST to match TS-ESLint, because we don't have the spans of `import`, `defer`, or `import.defer`, to use for the `MetaProperty`, or the `IdentifierName`s it contains.

This is not completely ideal, but I figure it's preferable to represent this syntax *somehow* in the AST, rather than completely ignoring it, in which case there's no way to distinguish between `import("x")`, `import.defer("x")`, and `import.source("x")`.

Presumably TS-ESLint will change their AST shape to conform to ESTree spec once these reach stage 4, so I don't think we should expend effort changing our AST to align with them in the meantime. TypeScript doesn't even have test cases for these (we'd know if they did, as we'd be failing them) - so I doubt these are popular constructs in TS.

`acorn-test262` submodule is bumped to include https://github.com/oxc-project/acorn-test262/pull/36 which adds the `phase` field to `ImportExpression`s in test snapshots.
2025-05-21 01:39:07 +00:00
overlookmotel d47b3057e8 feat(ast/estree): add phase field to ImportExpression in ESTree AST (#11165)
Related to #10978. Add `phase` property to `ImportExpression` in ESTree AST.

This property is *not* added in TS-ESTree, because TS-ESLint supports `import.defer(...)` and `import.source(...)`, but does not align with ESTree - it outputs a `CallExpression` with a `MetaProperty` as its `callee` instead.

We don't have the necessary information in our AST to match TS-ESLint, because we don't have the spans of `import`, `defer`, or `import.defer`, to use for the `MetaProperty`, or the `IdentifierName`s it contains.

Presumably TS-ESLint will change their AST shape to conform to ESTree spec once these reach stage 4, so I don't think we should expend and changing our AST to align with them in the meantime. TypeScript doesn't even have test cases for these (we'd know if they did, as we'd be failing them) - so I doubt these are popular constructs in TS.

`acorn-test262` submodule is bumped to include https://github.com/oxc-project/acorn-test262/pull/31.
2025-05-20 02:55:03 +00:00
overlookmotel 1bc8d29209 feat(ast/estree): add phase field to ImportDeclaration in ESTree AST (#11157)
Fixes #10978. Add `phase` property to `ImportDeclaration` in ESTree and TS-ESTree ASTs.

`ImportExpression` is not covered by this PR. That's more tricky as TS-ESLint already supports `import.defer(...)` and `import.source(...)`, but does not align with ESTree - it outputs a `MetaProperty` instead.

`acorn-test262` submodule is bumped to include https://github.com/oxc-project/acorn-test262/pull/30.
2025-05-19 15:13:31 +00:00
Boshen 635aa96219 fix(napi): computed final source type from lang then sourceType (#11060)
closes #10980

Previously final source type was only computed when `lang` is not set.

It is changed to:

* compute source type from `lang`, use filename extension if `lang` is
not set
* reset the computed source type with 'script` or `module` if provided
2025-05-15 21:41:42 +08:00
overlookmotel c8005adae1 fix(ast/estree): add line comment for hashbang in ESTree AST (#10669)
In ESTree (plain ESTree for JS i.e. Acorn), a hashbang is recorded as a line comment. Follow that behavior in our ESTree AST.

In TS-ESTree, hashbangs are ignored. That's not how it looks in AST explorer, because there's some post-processing going on, but `@typescript-eslint/parser` itself ignores hashbangs. So only add the comment in ESTree AST (not TS-ESTree AST).

More info on this rather confusing subtlety: https://github.com/typescript-eslint/typescript-eslint/issues/6500
2025-04-28 14:33:49 +00:00
Ulrich Stark 4f1343b235 fix(parser): fix missing type export in module information (#10516)
Closes #10505

---------

Co-authored-by: Boshen <boshenc@gmail.com>
2025-04-21 17:18:50 +08:00
overlookmotel 27768a5f19 fix(parser): store lone surrogates in TemplateElementValue as escape sequence (#10182)
Encode lone surrogates in `cooked` property of `TemplateElementValue` using same encoding scheme as for `StringLiteral`s.

In fact, they were already being encoded like this after #10041, but add a `lone_surrogates` flag to `TemplateLiteral` to decode them correctly in ESTree AST.

`oxc_codegen` ignores `cooked` and just prints `raw`, so needs no alteration.
2025-04-02 12:57:52 +00:00
overlookmotel 38d2beaf60 fix(parser): fix parsing lone surrogates in StringLiterals (#10180)
Fix 2 edge cases when parsing lone surrogates in `StringLiteral`s:

* Lone surrogate followed by `\u{...}` escape e.g. `"\uD800\u{41}"`.
* Escaped lossy replacement character after lone surrogate e.g. `"\uD800 \u{FFFD}"`.
2025-04-02 12:57:52 +00:00
hi-ogawa d69cc34e39 fix(ast/estree): fix BindingIdentifier (#9822)
spec: https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/ast-spec/src/expression/Identifier/spec.ts

I'm not sure whether this can be fixed on struct side `BindingIdentifier` instead of field side `Class.id`. `BindingIdentifier` is used inside flatten `BindingPatternKind` enum, so changing it might be complicated.

There are probably many instances like this, so I'm just trying to see the pattern first.
2025-03-21 05:47:40 +00:00
Boshen 2cedfe4148 feat(napi): add codeframe to napi error (#9893)
closes #8684
2025-03-19 08:41:31 +00:00
Boshen 638007b181 feat(parser): apply preserveParens to TSParenthesizedType (#9653)
closes #9616
2025-03-10 15:39:24 +00:00
overlookmotel 40565600a5 feat(ast/estree)!: option to return JS-only AST (#9520)
Add an `astType` option to `parseSync` and `parseAsync`.

When set to `'js'`, the returned AST does not include TypeScript-related properties. When set to `'ts'`, it does.

If not specified, the option defaults to same as source type. So when parsing JS / JSX files, the AST returned does not include TS properties by default.

The motivation for allowing the user to override that behavior, is in case someone is parsing a mix of JS and TS files, and want all the ASTs in the same format. In that case they'd set `astType: 'ts'` for all files.

This is a breaking change as it alters what properties appear in the AST on JS side.
2025-03-04 14:40:36 +00:00
Boshen 68c77c8996 feat(napi/parser): return semantic errors (#9460)
closes #9395
2025-03-01 09:50:23 +00:00
Boshen d129055dc6 test(napi): add tests for worker threads (#9408)
There are user code which may crash under some random circumstances
that we don't understand. Prevent these crashes with a test.
2025-02-27 07:19:11 +00:00
overlookmotel 48d51e31bc test(napi): add tests for hashbang field (#9386)
ESTree conformance tester does not test `hashbang` field, so add tests to `napi/parser` instead.
2025-02-26 13:07:35 +00:00
Boshen 4a5a7cf921 feat(napi/parser)!: remove magic string; enable utf16 span converter by default (#9291)
Benchmark reveals utf16 span converter is not that slow:

```
 ✓ bench.bench.mjs 1491ms
     name                                                  hz      min      max     mean      p75      p99     p995     p999     rme  samples
   · parser_napi[checker.ts] convertSpanUtf16: true   31.3194  30.8477  34.4288  31.9291  32.3740  34.4288  34.4288  34.4288  ±1.61%       16
   · parser_napi[checker.ts] convertSpanUtf16: false  34.1307  28.6449  29.9385  29.2991  29.6852  29.9385  29.9385  29.9385  ±0.70%       18   fastest

 BENCH  Summary

  parser_napi[checker.ts] convertSpanUtf16: false - bench.bench.mjs
    1.09x faster than parser_napi[checker.ts] convertSpanUtf16: true
```

```
 ✓ bench.bench.mjs 2127ms
     name                                               hz      min      max     mean      p75      p99     p995     p999     rme  samples
   · parser_napi[antd.js] convertSpanUtf16: true   15.1191  65.1335  67.4651  66.1414  66.6032  67.4651  67.4651  67.4651  ±0.70%       10
   · parser_napi[antd.js] convertSpanUtf16: false  17.3037  57.0110  58.6842  57.7911  58.1348  58.6842  58.6842  58.6842  ±0.69%       10   fastest

 BENCH  Summary

  parser_napi[antd.js] convertSpanUtf16: false - bench.bench.mjs
    1.14x faster than parser_napi[antd.js] convertSpanUtf16: true
```

Remove the option and enable the conversion by default.

Magic string API becomes useless at this point. 

This is a trade off between dx, maintenance and performance. dx and
maintainance wins this time.

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-02-22 14:27:35 +08:00
overlookmotel 216b33fd2a feat(ast/estree)!: replace serde with custom ESTree serializer (#9256)
Replace `serde` with a custom serializer specialized for writing JSON.

`impl Serialize` -> `impl ESTree`. I've called it `ESTree` in case we
want to add e.g. `impl Babel` later on.

The main motivation is that with control of the serializer, we can make
it stateful, so we can extend it to, for example, omit TS fields based
on a flag. This is pretty much impossible with `serde`'s interface.

But a side-effect of the simpler implementation is that it's also more
performant.

The usage of `ESTree` trait is very similar to `serde::Serialize`. Main
differences:

* `serialize` method is infallible. Does not return a `Result`.
* `state = serializer.serialize_struct();` instead of `map =
serializer.serialize_map();`.
* `state.serialize_field(...)` instead of `map.serialize_entry(...)`.
* Struct keys must be strings, and JSON-safe (not including `"` or other
characters that require escaping in JSON).

This is a breaking change, as it's possible downstream consumers are
using `serde` to serialize our AST to other formats. I'd guess unlikely,
but possible. We can always implement `serde::Serialize` as well as
`ESTree` further down the line if there's a demand.
2025-02-21 12:20:26 +08:00
hi-ogawa eaff3d985f test(napi/parser): split tests for convertSpanUtf16 (#9113)
Minor cleanup. I was smashing all assertions in a single `it`, but I've wanted to split them.
2025-02-14 12:58:58 +00:00
hi-ogawa 0937a55b3b fix(napi/parser): utf16 span for errors (#9112) 2025-02-14 12:58:58 +00:00
hi-ogawa 15f23f1556 fix(napi/parser): utf16 span for module record (#9093)
I (and mostly copilot) wrote `VisitMutModuleRecord` to visit all spans as I wasn't sure how `VisitMut` is generated. I'm looking into visit generator now if it's something I can do. Please let me know if manually writing it down is fine for now or I should try macro (or maybe a completely different approach).
2025-02-14 08:00:57 +00:00
hi-ogawa 9edfb1d330 fix(napi/parser): fix unicode comment panic (#9084)
- closes https://github.com/oxc-project/oxc/issues/9079

I'm still leaving an existing TODO for `module_record` and `errors` span not being converted as they won't cause an immediate issue, but I'll work on that shortly.
2025-02-13 10:02:37 +00:00
overlookmotel 41dba62780 fix(ast/estree): set value for BigIntLiterals and RegExpLiterals on JS side (#9044)
Add a "reviver" function to `JSON.parse` in NAPI parser module, to correctly set `value` field of `Literal`s for `RegExp`s and `BigInt`s.

Surprisingly, judging by a local run of NAPI parser benchmarks (added in #9045), this does not seem to hurt performance. In fact the benchmarks were showing a ~2% speed-up. That's clearly nonsense - just noise - but it does suggest at least that this isn't hurting performance significantly.
2025-02-11 14:48:43 +00:00
hi-ogawa 81c81a7cb5 feat(napi/parser): add convert_span_utf16 option (#8983)
For starter, I added opt-in `convert_span_utf16` for `napi/parser` level option, so rolldown-vite can start to battle test estree output.
2025-02-11 06:21:54 +00:00
hi-ogawa 4803059925 test(ast): remove old ast snapshot tests (#8976) 2025-02-09 04:14:36 +00:00
Hiroshi Ogawa a520986e1a fix(ast): estree compat Program.sourceType (#8919)
part of https://github.com/oxc-project/oxc/issues/2854
ref: https://github.com/estree/estree/blob/master/es2015.md#programs

I tried to move `via` customization on `struct SourceType`, but couldn't
find a way maybe because struct is defined in `oxc_span`. For now, I
made this as `via` on `Program::source_type` field.
2025-02-06 13:18:32 +00:00
Hiroshi Ogawa e30cf6aeb1 fix(ast): estree compat MemberExpression (#8921)
Part of https://github.com/oxc-project/oxc/issues/2854

I added a bit weird macro `add_entry(computed = true)` to add constant.
Likely this is not the best way. I would appreciate any suggestion for a
better approach 🙏

---------

Co-authored-by: overlookmotel <theoverlookmotel@gmail.com>
2025-02-06 11:50:31 +00:00
Hiroshi Ogawa 0c55dd684e fix(ast): serialize Function.params like estree (#8772)
- part of https://github.com/oxc-project/oxc/issues/2854

This PR attempts to handle estree ast incompatibility of
`Function.params: FormalParameters` as mentioned in the above issue:

> `FormalParameters` is closer to ESTree now, but should be inlined
directly into `<node>.params` in multiple nodes.

Estree spec has `Function.params: Pattern[]`
https://github.com/estree/estree/blob/master/es5.md#functions, but oxc
already has `interface Pattern`, so I named it to `Function.params:
ParamPattern[]` for now.

Also I'm not sure about the testing (I suppose that's a part of
https://github.com/oxc-project/oxc/issues/8630), so I snapshoted one
example code. For comparison, here is acorn's output
https://astexplorer.net/#/gist/25138c0605f82dcfc1a8fd363dc2a681/5ad30d36c9f276519063e6fd2e340c113d8c85b0

---------

Co-authored-by: overlookmotel <theoverlookmotel@gmail.com>
2025-02-05 02:40:02 +00:00
Boshen 1bef911e59 feat(napi/parser): add source map API (#8584) 2025-01-18 23:06:42 +08:00
Boshen 85eec3c82e feat(napi/transform,napi/parser): return structured error object (#7724)
closes #7261
2024-12-08 14:11:56 +00:00
Boshen 40792b4440 feat(napi/parser): change parse API to accept mandatory filename and optional lang (#7605) 2024-12-03 12:09:48 +00:00