Library/Fn/OXC/
Codegen.rs1use std::sync::atomic::{AtomicUsize, Ordering};
10
11use oxc_allocator::Allocator;
12use oxc_ast::ast::Program;
13use oxc_codegen::{Codegen, CodegenOptions, CodegenReturn, CommentOptions};
14use oxc_span::SourceType;
15use tracing::{debug, error, info, trace, warn};
16
17#[derive(Debug, Clone)]
19pub struct CodegenConfig {
20 pub minify:bool,
22
23 pub source_map:bool,
25
26 pub source_map_name:String,
28
29 pub comments:bool,
31}
32
33impl Default for CodegenConfig {
34 fn default() -> Self { Self { minify:false, source_map:false, source_map_name:String::new(), comments:false } }
35}
36
37impl CodegenConfig {
38 pub fn new(minify:bool, _source_map:bool, _source_map_name:String, comments:bool) -> Self {
40 Self { minify, source_map:_source_map, source_map_name:_source_map_name, comments }
41 }
42}
43
44pub struct CodegenResult {
46 pub code:String,
48
49 pub code_len:usize,
51}
52
53fn transform_static_class_properties(code:&str) -> String {
58 let re = match regex::Regex::new(r"(?m)^\s*static\s+([a-zA-Z_$][\w$]*)\s*=\s*([^;]+);") {
61 Ok(re) => re,
62
63 Err(e) => {
64 error!("transform_static_class_properties: regex compile error: {}", e);
66
67 return code.to_string();
68 },
69 };
70
71 re.replace_all(code, "static { this.$1 = $2; }").into_owned()
72}
73
74static CODEGEN_COUNT:AtomicUsize = AtomicUsize::new(0);
85
86#[tracing::instrument(skip(_allocator, program, config))]
87pub fn codegen<'a>(
88 _allocator:&Allocator,
89
90 program:&Program<'a>,
91
92 _source_type:SourceType,
93
94 config:&CodegenConfig,
95) -> Result<CodegenResult, String> {
96 let codegen_id = CODEGEN_COUNT.fetch_add(1, Ordering::SeqCst);
97
98 info!("[Codegen #{codegen_id}] Starting code generation");
99
100 trace!("[Codegen #{codegen_id}] Program address: {:p}", program);
101
102 trace!(
103 "[Codegen #{codegen_id}] Program body ptr: {:p}, len: {}",
104 program.body.as_ptr(),
105 program.body.len()
106 );
107
108 debug!(
109 "[Codegen #{codegen_id}] Config: minify={}, comments={}",
110 config.minify, config.comments
111 );
112
113 let comment_options = if config.comments {
120 CommentOptions::default()
121 } else {
122 CommentOptions::disabled()
123 };
124
125 let options = CodegenOptions { minify:config.minify, comments:comment_options, ..Default::default() };
126
127 trace!("[Codegen #{codegen_id}] CodegenOptions configured");
128
129 let codegen_start = std::time::Instant::now();
131
132 let CodegenReturn { code, .. } = Codegen::new().with_options(options).build(program);
133
134 info!(
135 "[Codegen #{codegen_id}] Code generation completed in {:?}",
136 codegen_start.elapsed()
137 );
138
139 let code_len = code.len();
140
141 debug!("[Codegen #{codegen_id}] Generated {} bytes of code", code_len);
142
143 trace!(
144 "[Codegen #{codegen_id}] First 100 chars of output: {:?}",
145 code.chars().take(100).collect::<String>()
146 );
147
148 info!("[Codegen #{codegen_id}] SUCCESS: Generated {} bytes", code_len);
149
150 let transformed_code = transform_static_class_properties(&code);
152
153 Ok(CodegenResult { code:transformed_code, code_len })
154}
155
156pub fn write_output(output_path:&std::path::Path, result:&CodegenResult) -> Result<(), std::io::Error> {
162 if let Some(parent) = output_path.parent() {
164 std::fs::create_dir_all(parent)?;
165 }
166
167 std::fs::write(output_path, &result.code)?;
169
170 debug!("Written output to {}", output_path.display());
171
172 Ok(())
173}