Files
oxc/packages/codegen
oxc-guard f799f174b5 release(crates): oxc v0.157.0 (#28719)
### 🚀 Features

- 8dd67a6 transform-react: Expose TypeScript transform options (Tomas Särnhammar)
- deed7dc parser: More friendly error for duplicate import attribute key (#28262) (sapphi-red)

### 🐛 Bug Fixes

- eaa8e90 ecmascript: Avoid numeric `+` folding when an operand may be a string (#28544) (camc314)
- b03c7b8 regular_expression: Allow incomplete oversized legacy quantifiers (#28449) (Boshen)
- 128c67d semantic: Check strict eval and arguments writes by reference flags (#28445) (Boshen)
- c97c43c parser: Reject TypeScript default exports in JavaScript (#28440) (Boshen)
- fdd119f span: Count Unicode characters when filtering typo suggestions (#28452) (Boshen)
- cb64638 regular_expression: Reject incomplete Unicode atom escapes (#28448) (Boshen)
- fc0eed3 semantic: Stop let-binding scans at arrow functions (#28444) (Boshen)
- 3421516 parser: Preserve default import names in reexports (#28442) (Boshen)
- a1e7e5f parser: Reject optional class members in JavaScript (#28439) (Boshen)
- 5b9a7bc parser: Parse sloppy let expressions and labels (#28438) (Boshen)
- 8e61652 regex: Reject templates without cooked values (#28345) (Boshen)
- 3b36543 parser: Preserve in-context after TypeScript type arguments (#28300) (Boshen)
- 2e3126c regex: Decode constructor patterns and flags consistently (#28298) (Boshen)
- 8a90be2 regex: Track capture groups and disjunction identity (#28297) (Boshen)
- 3dc2cb0 regex: Preserve escape values and boundaries (#28296) (Boshen)
- fc8acbc parser: Handle leading-zero numeric exponents (#28295) (Boshen)
- 91a638d parser: Normalize raw template line endings with invalid escapes (#28285) (Boshen)
- 2ac9a42 parser: Allow parenthesized private-in expressions (#28284) (Boshen)
- 052bca9 ast: Prevent greyed out fields in AST types in IDEs (#28335) (overlookmotel)
- ed7df7d ast/estree: Include comments in TS Program span (#28326) (camc314)

### ⚡ Performance

- 9b6b7bf regular_expression: Advance validated Unicode escapes directly (#28514) (Boshen)
- 82e1982 regular_expression: Share Unicode property name prefixes (#28513) (Boshen)
- 5395a40 regular_expression: Parse class set character prefixes once (#28512) (Boshen)
- 3708934 regular_expression: Defer literal range dash allocation (#28511) (Boshen)
- d85ee3d semantic: Skip arguments ancestry checks outside classes (#28510) (Boshen)
- cf81d07 semantic: Reuse private reference resolution (#28509) (Boshen)
- a79eebc semantic: Avoid duplicate maps for public JavaScript members (#28508) (Boshen)
- 235ca3b semantic: Skip escape checks for unescaped strings (#28507) (Boshen)
- babf44c parser: Reuse shorthand assignment target identifiers (#28504) (Boshen)
- 444f24a ecmascript: Short-circuit simple parameter checks for rest (#28503) (Boshen)
- 04b20c0 semantic: Compute duplicate parameter policy once per list (#28446) (Boshen)
- dbf8482 parser: Use token lookahead for simple function types (#28489) (Boshen)
- bca1275 parser: Avoid unused destructuring rest capacity (#28499) (Boshen)
- 691be5c parser: Compact cover initialized name storage (#28495) (Boshen)
- b3b5444 parser: Build simple arrow bindings directly (#28493) (Boshen)
- e1c9baf parser: Disambiguate single-identifier arrow heads (#28491) (Boshen)
- 550e98a regular_expression: Avoid rescanning unique capture names (#28450) (Boshen)
- 10e9fc7 parser: Skip duplicate lookup for singleton import attributes (#28441) (Boshen)
- 5238839 parser: Use a stack buffer for float separators (#28435) (Boshen)
- 6e35e3c parser: Fast-path leaf expressions before delimiters (#28432) (Boshen)
- 3d7512c parser: Decode Unicode identifiers once (#28414) (Boshen)
- 30f59f4 parser: Factor object type opening brace (#28430) (Boshen)
- 028a267 parser: Always inline postfix update parsing (#28429) (Boshen)
- 1b5a171 parser: Reuse export kind classification (#28424) (Boshen)
- 179a432 parser: Factor return type identifier parsing (#28416) (Boshen)
- 553dd1d parser: Inline hot paths and fold function dispatch (#28404) (Boshen)
- de75d56 parser: Combine parenthesized arrow lookahead (#28412) (Boshen)
- a768a0c parser: Reuse comment annotations after rewind (#28408) (Boshen)
- 563d92a parser: Skip redundant source cursor updates (#28409) (Boshen)
- 7941ca9 parser: Factor tuple identifier parsing (#28398) (Boshen)
- 426c151 parser: Construct completed tokens without intermediate writes (#28291) (Boshen)
- df42953 minifier: Don't request another pass for block unwrapping (#28315) (Dunqing)
- c2d663d parser: Avoid vectors for single parenthesized expressions (#28374) (Boshen)
- 50bd0a9 parser: Size delimited lists after the first element (#28373) (Boshen)
- bd869b5 parser: Bypass redundant operand parsing (#28372) (Boshen)
- 455fc09 parser: Skip keyword checks for plain identifier expressions (#28371) (Boshen)
- 61303fb parser: Fast-path identifier operands (#28306) (Boshen)
- 6cf5b1a parser: Guard arrow and conditional parsing (#28305) (Boshen)
- 3666939 parser: Specialize identifier reference parsing (#28303) (Boshen)
- 0d6641a parser: Skip inapplicable expression parsing paths (#28294) (Boshen)
- 3be7997 parser: Reduce lexer search batch size (#28292) (Boshen)
- ab5655a regex: Remove redundant character-class and quantifier checks (#28288) (Boshen)
- ec8e8d4 parser: Remove redundant grammar and lexer checks (#28287) (Boshen)
- c903f5c parser: Specialize known-token parsing (#28286) (Boshen)
- 2683225 str: `static_ident!` and `static_str!` macros guarantee const evaluation (#28340) (overlookmotel)
- df90836 ast: Reduce compile time of `#[ast]` macro (#28336) (overlookmotel)
- 8239dac parser: Replace dragonbox_ecma with zmij_ecma (#28282) (Boshen)
2026-11-02 19:40:44 +00:00
..

oxc-codegen

Fast, synchronous code generation for JavaScript and TypeScript ASTs.

oxc-codegen turns an ESTree or TS-ESTree AST into formatted source code. It supports JavaScript, JSX, TypeScript, and TSX.

The printer is a port of Oxc's Rust oxc_codegen crate. With the default options, both printers produce byte-identical output: tab indentation, double-quoted strings, and no comments.

Installation

npm install oxc-codegen

oxc-codegen is ESM-only and requires Node.js ^20.19.0 or >=22.12.0.

Quick start

Pair it with oxc-parser to parse and print source code:

import { printSync } from "oxc-codegen";
import { parseSync } from "oxc-parser";

const { program } = parseSync("input.js", "const answer=6*7");
const { code } = printSync(program);

console.log(code);
// const answer = 6 * 7;

You can also print a manually constructed AST:

const program = {
  type: "Program",
  sourceType: "script",
  body: [
    {
      type: "ExpressionStatement",
      expression: {
        type: "CallExpression",
        callee: {
          type: "MemberExpression",
          object: { type: "Identifier", name: "console" },
          property: { type: "Identifier", name: "log" },
          computed: false,
          optional: false,
        },
        arguments: [{ type: "Literal", value: "Hello!" }],
        optional: false,
      },
    },
  ],
};

console.log(printSync(program).code);
// console.log("Hello!");

TypeScript and TSX

Set ts when the AST can contain TypeScript nodes. For TSX, set both ts and jsx:

const { program } = parseSync("component.tsx", "const Box = <T,>(value: T) => <div>{value}</div>");

const { code } = printSync(program, {
  ts: true,
  jsx: true,
});

API

printSync(node, options?)

function printSync(
  node: ESTree.Program | ESTree.Statement,
  options?: Options,
): {
  code: string;
  map: SourceMap | null;
};

Prints a complete Program or a single statement and returns the generated source code, and (when requested) a standard Source Map v3 object.

import { printSync } from "oxc-codegen";
import { parseSync } from "oxc-parser";

const sourceText = "const answer=6*7";
const { program } = parseSync("input.js", sourceText);
const { code, map } = printSync(program, {
  sourcemap: true,
  sourceFilename: "input.js",
  sourceText,
});

Source-map mappings require sourceText and nodes with valid Oxc start / end offsets. A manually constructed AST without offsets can still be printed, but its source map has an empty mappings string.

Options

Option Type Default Description
indent string "\t" Non-empty string of spaces and/or tabs used for one indent level
startingIndentLevel number 0 Starting indent level, from 0 to 1000
jsx boolean false Enable TSX-safe printing for ambiguous TypeScript syntax
ts boolean false Select the printer that supports TypeScript nodes
sourcemap boolean false Return a Source Map v3 object in map
sourceFilename string "" Original source filename recorded in the source map
sourceText string - Original text required for source-map mappings and content

Why pure JavaScript?

Most Oxc packages use native bindings. This package deliberately does not: when an AST already lives in JavaScript, passing the entire object graph across a JS/native boundary can cost more than printing it in place. oxc-codegen avoids that serialization and uses specialized printer builds for JavaScript and TypeScript workloads.

See DESIGN.md for the implementation details and performance constraints.

Current limitations

  • Comments are not printed.
  • Minified output is not supported.

Benchmarks

Representative time per printSync call:

Fixture Bytes Time
tiny.js 26 0.0001 ms
RadixUIAdoptionSection.jsx 2,518 0.0070 ms
react.development.js 72,141 0.1518 ms
binder.ts 193,077 0.3364 ms
App.tsx 415,340 1.2912 ms
lodash.js 544,096 0.7977 ms
kitchen-sink.tsx 732,222 4.2924 ms
antd.js 6,683,633 16.9652 ms

These figures come from one machine and are illustrative, not a regression baseline. Results vary between runs, most noticeably for large fixtures such as antd.js.