camc314
db64852c4f
refactor(codegen): remove legacy module declaration support ( #25864 )
...
## Summary
- remove the legacy TSModuleDeclaration kind fallback
- require Oxc's explicit kind AST shape
- remove the completed compatibility documentation section
2026-08-18 14:36:30 +00:00
camc314
56a01b59c5
refactor(codegen): remove legacy enum declaration support ( #25863 )
...
## Summary
- remove the legacy TSEnumDeclaration members fallback
- require Oxc's enum body AST shape
- update compatibility documentation
2026-08-18 14:28:13 +00:00
camc314
90098e65b3
refactor(codegen): remove legacy import type support ( #25862 )
...
## Summary
- remove the legacy TSImportType argument fallback
- require Oxc's source AST shape
- update compatibility documentation
2026-08-18 14:18:15 +00:00
camc314
b564ec82f4
refactor(codegen): remove legacy mapped type support ( #25861 )
...
## Summary
- remove the pre-v6 TS-ESLint TSMappedType.typeParameter fallback
- require Oxc's key / constraint mapped-type AST shape
- update compatibility documentation
2026-08-18 14:07:15 +00:00
overlookmotel
58f7ab9c1d
docs(packages/codegen): reformat docs and comments ( #25848 )
...
Follow-on after #25585 .
Pure style change. I hate the way LLMs put line breaks in weird places like after "the" - it makes comments hard to read. And what's with all the colons and semicolons?
No substantive changes, just reformatting comments and docs to avoid this unreadable formatting.
2026-08-18 12:24:56 +00:00
camc314
300763f328
feat(packages/codegen): add full source map support ( #25585 )
...
## Summary
Align `oxc-codegen` source maps with Rust `oxc_codegen`, using the Rust implementation as the conformance oracle.
This PR:
- changes `printSync` to return `{ code, map? }`;
- returns a standard Source Map v3 object;
- exposes Rust’s generated source map through `codegen_conformance`;
- compares the complete JS and Rust source maps;
- supports Oxc `start`/`end` offsets and TS-ESTree `range` offsets;
- uses `sourceText` to convert UTF-16 offsets and recover original identifier spellings;
- validates both maps and no-maps builds in both `preserveParens` modes;
- aligns mapping placement across JavaScript, TypeScript, JSX, templates, imports, destructuring, delimiters, and postfix chains;
- handles astral characters and all ECMAScript line terminators.
`loc`-only ASTs are not supported for source maps.
## API change
```ts
const { code, map } = printSync(program, {
sourcemap: true,
sourceFileName: "input.js",
sourceText,
});
```
`map` is a Source Map v3 object:
```ts
interface SourceMap {
version: 3;
mappings: string;
names: string[];
sources: string[];
sourcesContent?: string[];
}
```
## Implementation
Mapped writes collect only:
- the generated UTF-16 offset;
- the original source offset;
- the optional original identifier name.
After printing, the generator builds line tables for the generated output and `sourceText`, converts the offsets to line/column positions, suppresses duplicate source positions, and encodes the result as base64 VLQ.
The no-maps builds continue to remove mapping-specific writes at build time.
## Validation flow
```mermaid
flowchart TB
fixture["Fixture<br/>filename + sourceText + parse options"]
fixture --> rustParse
fixture --> jsParse
subgraph rust["Rust oracle"]
direction TB
rustParse["Parse with oxc_parser"]
normalize["Normalize Rust-only AST information"]
rustPrint["Print with oxc_codegen<br/>source maps enabled"]
rustResult["Expected result<br/>{ code, map }"]
rustParse --> normalize
normalize --> rustPrint
rustPrint --> rustResult
end
subgraph js["JavaScript candidate"]
direction TB
jsParse["Parse ESTree with oxc-parser<br/>start/end or range offsets"]
plainPrint["Print with no-maps build"]
plainResult["Actual code"]
mappedPrint["Print with maps-enabled build"]
deferred["Record generated offsets,<br/>source offsets, and names"]
encode["Convert UTF-16 offsets to positions<br/>deduplicate and encode VLQ"]
mappedResult["Actual result<br/>{ code, map }"]
jsParse --> plainPrint
plainPrint --> plainResult
jsParse --> mappedPrint
mappedPrint --> deferred
deferred --> encode
encode --> mappedResult
end
rustParse --> parseGate
jsParse --> parseGate
rustResult --> codeGate
plainResult --> codeGate
mappedResult --> codeGate
rustResult --> mapGate
mappedResult --> mapGate
parseGate["Parse agreement<br/>Rust success requires no JS errors"]
codeGate["Code equality<br/>both JS builds equal Rust"]
mapGate["Source Map v3 equality<br/>mappings + names + sources + content"]
parseGate --> pass["Fixture passes"]
codeGate --> pass
mapGate --> pass
```
Each fixture runs with both `preserveParens: false` and `preserveParens: true`.
## AST normalization
Rust’s AST contains information that ESTree cannot represent. The Rust AST is normalized before printing so the comparison measures code generation rather than representation differences.
This includes:
- parenthesized function and arrow-expression flags;
- `import "m"` versus `import {} from "m"`;
- absent versus empty import-attribute clauses;
- `assert` versus `with` attribute keywords;
- the unavailable ESTree span for a complete `with` clause.
2026-08-18 11:41:34 +00:00
overlookmotel
f91b7739a3
refactor(packages/codegen): re-order write* functions ( #25719 )
...
Pure refactor. Re-order `write*` functions, so `*NoLast` versions are grouped together.
2026-08-15 16:04:00 +00:00
camc314
0c68b7ff8b
fix(estree): emit decorators on FormalParameterRest ( #25582 )
...
This PR adds support for emitting `decorators` when serializing an ast to ESTree (both with/without raw transfer).
Given the following code:
```
class C { method(@dec ...args) {} }
```
Before we emitted the following ESTree shape:
```json
"params": [
{
"type": "RestElement",
"decorators": [],
"argument": {
"type": "Identifier",
"decorators": [],
"name": "args",
"optional": false,
"typeAnnotation": null,
},
"optional": false,
"typeAnnotation": null,
"value": null,
}
],
```
Now we emit:
```json
"params": [
{
"type": "RestElement",
"decorators": [
{
"type": "Decorator",
"expression": { "type": "Identifier", "name": "dec" }
}
],
"argument": {
"type": "Identifier",
"decorators": [],
"name": "args",
"optional": false,
"typeAnnotation": null,
},
"optional": false,
"typeAnnotation": null,
"value": null,
},
],
```
fixes https://github.com/oxc-project/oxc/issues/18981
closes https://github.com/oxc-project/oxc/pull/24736
2026-08-13 10:43:14 +00:00
camc314
c5d406370d
docs(codegen): clarify binary walk allocations ( #25562 )
...
## Summary
- Correct the binary-walk allocation claim: the implementation creates an initial visitor object and one for each nested left level.
- Retain and document the actual optimization: pending levels use `parent` links instead of a separate stack array.
2026-08-12 17:23:14 +00:00
overlookmotel
a4478e960a
feat(codegen): add oxc-codegen package ( #25488 )
...
Add `oxc-codegen` package - a printer written in TS.
### Features
- Prints JS, JSX, TS, TSX.
- Matches `oxc_codegen` exactly on all Test262, TypeScript, Acorn-JSX fixtures.
- Very fast.
### Deficiencies
- Pretty-printing only (no compact/minified output).
- No support for printing comments.
- Source map support is semi-there, but largely untested, and poor API (design doc has some ideas on how to improve it).
### This PR adds
- The printer code.
- Conformance testing infra.
- Further tests for edge cases.
- README.
- Design doc - how it differs from `oxc_codegen` and why, what produces the perf.
### This PR doesn't add
- Not integrated into CI or release pipeline.
### Notes
This started as a slop port of `oxc_codegen`. I've iterated on that base, cleaned it up a lot, and at least skimmed through all of it. I think it's in fairly decent shape.
The design doc is I think worth a read. It explains the rationale for the choices, in particular the "1 codebase, 4 builds" approach.
I've put it in a new top-level directory called `packages`. It's not an app, so didn't seem to me to fit alongside `apps/oxlint` and `apps/oxfmt`. It's pure JS, so not like e.g. `napi/parser`. And it felt too heavyweight to put into `npm` dir. But maybe there's a better place for it.
Co-authored-by: Cameron <cameron.clark@hey.com >
2026-08-12 13:41:31 +00:00