Files
oxc-project__oxc/crates/oxc_codegen/examples/codegen.rs
camc314 8db105342f fix(codegen): require sourcemap for example (#26047)
## Summary

- require the sourcemap feature when building the codegen example
- document the example's sourcemap option
- allow oxc_codegen to test cleanly without default features
2026-08-24 10:02:59 +00:00

110 lines
3.4 KiB
Rust

#![expect(clippy::print_stdout)]
//! # Code Generation Example
//!
//! This example demonstrates how to use the Oxc code generator to convert an AST
//! back into JavaScript code. It supports minification and idempotency testing.
//!
//! ## Usage
//!
//! Create a `test.js` file and run:
//! ```bash
//! cargo run -p oxc_codegen --example codegen [filename] [--minify] [--twice]
//! ```
//!
//! ## Options
//!
//! - `--minify`: Generate minified output
//! - `--twice`: Test idempotency by parsing and generating twice
//! - `--sourcemap`: Print the generated source map (requires the `sourcemap` feature)
use std::path::Path;
use pico_args::Arguments;
use oxc_allocator::Allocator;
use oxc_ast::ast::Program;
use oxc_codegen::{Codegen, CodegenOptions, CodegenReturn};
use oxc_parser::{ParseOptions, Parser};
use oxc_sourcemap::SourcemapVisualizer;
use oxc_span::SourceType;
// Instruction:
// create a `test.js`,
// run `cargo run -p oxc_codegen --example codegen`
// or `cargo watch -x "run -p oxc_codegen --example codegen"`
/// Demonstrate code generation with optional minification and idempotency testing
fn main() -> std::io::Result<()> {
let mut args = Arguments::from_env();
let twice = args.contains("--twice");
let minify = args.contains("--minify");
let sourcemap = args.contains("--sourcemap");
let name = args.free_from_str().unwrap_or_else(|_| "test.js".to_string());
let path = Path::new(&name);
let sourcemap = sourcemap.then_some(path);
let source_text = std::fs::read_to_string(path)?;
let source_type = SourceType::from_path(path).unwrap();
let mut allocator = Allocator::default();
// First round: parse and generate
let printed = {
let program = parse(&allocator, &source_text, source_type);
codegen(&program, minify, sourcemap)
};
println!("First time:");
println!("{printed}");
// Optional second round to test idempotency
if twice {
// Reset the allocator as we don't need the first AST any more
allocator.reset();
let program = parse(&allocator, &printed, source_type);
println!("Second time:");
let printed2 = codegen(&program, minify, None);
println!("{printed2}");
// Check syntax error
parse(&allocator, &printed2, source_type);
println!("same = {}", printed == printed2);
}
Ok(())
}
/// Parse JavaScript/TypeScript source code into an AST
fn parse<'a>(
allocator: &'a Allocator,
source_text: &'a str,
source_type: SourceType,
) -> Program<'a> {
let ret = Parser::new(allocator, source_text, source_type)
.with_options(ParseOptions {
allow_return_outside_function: true,
..ParseOptions::default()
})
.parse();
for error in ret.diagnostics {
println!("{}", error.render_with_source_code(source_text.to_string()));
}
ret.program
}
/// Generate JavaScript code from an AST
fn codegen(program: &Program<'_>, minify: bool, source_map_path: Option<&Path>) -> String {
let mut options = if minify { CodegenOptions::minify() } else { CodegenOptions::default() };
options.source_map_path = source_map_path.map(Path::to_path_buf);
let CodegenReturn { code, map, .. } = Codegen::new().with_options(options).build(program);
if let Some(map) = map {
let visualizer = SourcemapVisualizer::new(&code, &map);
println!("{}", visualizer.get_url());
println!("{}", visualizer.get_text());
}
code
}