Oxc’s code generator converts an Abstract Syntax Tree (AST) back into JavaScript or TypeScript source code with support for minification and source maps.
Features
- High-performance code generation
- Minification support
- Source map generation
- Comment preservation
- Configurable formatting (indentation, quotes, etc.)
- TypeScript output support
Installation
Add to your Cargo.toml:
[dependencies]
oxc_codegen = "0.116.0"
oxc_ast = "0.116.0"
oxc_allocator = "0.116.0"
Basic Usage
use oxc_allocator::Allocator;
use oxc_codegen::Codegen;
use oxc_parser::Parser;
use oxc_span::SourceType;
let allocator = Allocator::default();
let source = "const x = 1 + 2;";
let source_type = SourceType::default();
// Parse source code
let ret = Parser::new(&allocator, source, source_type).parse();
let program = ret.program;
// Generate code
let output = Codegen::new().build(&program);
println!("{}", output.code); // const x = 1 + 2;\n
Core Types
Codegen
Main code generator. Create with Codegen::new() and configure with builder methods.
Constructor:
impl Codegen {
pub fn new() -> Self;
}
Configuration Methods:
impl<'a> Codegen<'a> {
// Set options
pub fn with_options(mut self, options: CodegenOptions) -> Self;
// Set source text for comments and source maps
pub fn with_source_text(mut self, source_text: &'a str) -> Self;
// Set symbol table for identifier renaming
pub fn with_scoping(mut self, scoping: Option<Scoping>) -> Self;
// Set private member name mappings from minifier
pub fn with_private_member_mappings(
mut self,
mappings: Option<IndexVec<ClassId, FxHashMap<String, CompactStr>>>
) -> Self;
// Generate code from AST
pub fn build(mut self, program: &Program<'a>) -> CodegenReturn;
}
CodegenOptions
Configuration for code generation.
pub struct CodegenOptions {
pub minify: bool,
pub single_quote: bool,
pub indent_char: IndentChar,
pub indent_width: u8,
pub initial_indent: u32,
pub source_map_path: Option<PathBuf>,
pub comments: CommentOptions,
}
Enable minified output (removes whitespace, shortens identifiers with scoping).
Use single quotes for strings. Default is double quotes.
Character to use for indentation: Tab or Space.
Number of spaces per indentation level (only used with IndentChar::Space).
Initial indentation level. Useful for embedding generated code.
Path for source map generation. If None, no source map is generated.
How to handle comments in output.
Presets:
impl CodegenOptions {
// Default formatting
pub fn default() -> Self;
// Minified output
pub fn minify() -> Self;
}
CodegenReturn
Result of code generation.
pub struct CodegenReturn {
pub code: String,
pub map: Option<SourceMap>,
pub legal_comments: Vec<Comment>,
}
The generated source code.
Generated source map. Only present if source_map_path was set in options.
Legal comments (license headers) extracted from source.
Controls comment output behavior.
pub enum CommentOptions {
None, // Omit all comments
Preserve, // Keep all comments
PreserveLegal, // Keep only legal comments (/*! ... */)
}
impl CommentOptions {
pub fn disabled() -> Self { Self::None }
}
Examples
Basic Code Generation
use oxc_allocator::Allocator;
use oxc_codegen::Codegen;
use oxc_parser::Parser;
use oxc_span::SourceType;
let allocator = Allocator::default();
let source = "const x = 1 + 2;";
let source_type = SourceType::default();
let ret = Parser::new(&allocator, source, source_type).parse();
let code = Codegen::new().build(&ret.program).code;
println!("{}", code);
Minified Output
use oxc_codegen::CodegenOptions;
let ret = Parser::new(&allocator, source, source_type).parse();
let minified = Codegen::new()
.with_options(CodegenOptions::minify())
.build(&ret.program)
.code;
println!("{}", minified); // const x=1+2;
use oxc_codegen::{CodegenOptions, IndentChar};
let options = CodegenOptions {
minify: false,
single_quote: true,
indent_char: IndentChar::Space,
indent_width: 2,
..Default::default()
};
let code = Codegen::new()
.with_options(options)
.build(&program)
.code;
With Source Maps
use oxc_codegen::CodegenOptions;
use std::path::PathBuf;
let options = CodegenOptions {
source_map_path: Some(PathBuf::from("output.js.map")),
..Default::default()
};
let output = Codegen::new()
.with_source_text(source) // Required for source maps
.with_options(options)
.build(&program);
// Write files
std::fs::write("output.js", output.code)?;
if let Some(map) = output.map {
std::fs::write("output.js.map", map.to_json_string())?;
}
With Identifier Renaming
Use scoping from semantic analysis or minifier:
use oxc_semantic::SemanticBuilder;
// From semantic analysis
let semantic = SemanticBuilder::new().build(&program).semantic;
let scoping = semantic.into_scoping();
let code = Codegen::new()
.with_scoping(Some(scoping))
.build(&program)
.code;
// Or from minifier
let minifier_ret = Minifier::new(options).minify(&allocator, &mut program);
let code = Codegen::new()
.with_scoping(minifier_ret.scoping)
.build(&program)
.code;
Generating TypeScript
let allocator = Allocator::default();
let source = "const x: number = 42;";
let source_type = SourceType::ts();
let ret = Parser::new(&allocator, source, source_type).parse();
let code = Codegen::new().build(&ret.program).code;
println!("{}", code); // const x: number = 42;
use oxc_codegen::{CodegenOptions, CommentOptions};
let options = CodegenOptions {
comments: CommentOptions::Preserve,
..Default::default()
};
let code = Codegen::new()
.with_source_text(source)
.with_options(options)
.build(&program)
.code;
let options = CodegenOptions {
comments: CommentOptions::PreserveLegal,
minify: true,
..Default::default()
};
let output = Codegen::new()
.with_source_text(source)
.with_options(options)
.build(&program);
// Legal comments are also returned separately
for comment in output.legal_comments {
println!("Legal comment: {:?}", comment);
}
Progressive Code Building
use oxc_codegen::Codegen;
use oxc_ast::ast::*;
let mut codegen = Codegen::new();
// Print individual expressions
codegen.print_expression(&expression1);
codegen.print_str("; ");
codegen.print_expression(&expression2);
let code = codegen.into_source_text();
Advanced Usage
With All Options
use oxc_codegen::{CodegenOptions, CommentOptions, IndentChar};
use std::path::PathBuf;
let options = CodegenOptions {
minify: false,
single_quote: true,
indent_char: IndentChar::Space,
indent_width: 2,
initial_indent: 0,
source_map_path: Some(PathBuf::from("output.js.map")),
comments: CommentOptions::PreserveLegal,
};
let output = Codegen::new()
.with_source_text(source)
.with_options(options)
.with_scoping(Some(scoping))
.with_private_member_mappings(Some(mappings))
.build(&program);
std::fs::write("output.js", output.code)?;
if let Some(map) = output.map {
std::fs::write("output.js.map", map.to_json_string())?;
}
Idempotency Testing
fn test_print_parse_print(source: &str) {
let allocator = Allocator::default();
let source_type = SourceType::default();
// First: parse and print
let ret1 = Parser::new(&allocator, source, source_type).parse();
let code1 = Codegen::new().build(&ret1.program).code;
// Second: parse printed output and print again
let ret2 = Parser::new(&allocator, &code1, source_type).parse();
let code2 = Codegen::new().build(&ret2.program).code;
// Output should be stable
assert_eq!(code1, code2);
}
The code generator is optimized for speed:
- Efficient buffer: Uses a specialized
CodeBuffer for fast string building
- Minimal allocations: Reuses buffers where possible
- Compact output: Minified mode removes all unnecessary whitespace
- Fast number printing: Uses
dragonbox algorithm for floating point
Indentation
use oxc_codegen::{CodegenOptions, IndentChar};
// Tabs (default)
let tabs = CodegenOptions {
indent_char: IndentChar::Tab,
..Default::default()
};
// 2 spaces
let spaces = CodegenOptions {
indent_char: IndentChar::Space,
indent_width: 2,
..Default::default()
};
Quote Style
let options = CodegenOptions {
single_quote: true, // Use 'string' instead of "string"
..Default::default()
};
Semicolons
The codegen always emits semicolons for safety, even in minified mode.
API Documentation
For complete API documentation, see docs.rs/oxc_codegen.