Skip to main content

Library/Fn/OXC/
Compile.rs

1//! OXC-based compilation module
2//!
3//! This module provides the compilation functionality using the OXC compiler.
4//!
5//! DIAGNOSTIC LOGGING:
6//! - Full lifecycle tracking of file compilation
7//! - Memory allocation tracking for each file
8//! - File path and nesting level analysis
9
10use std::{
11	io::Write,
12	sync::atomic::{AtomicUsize, Ordering},
13};
14
15use tracing::{debug, error, info, trace};
16
17static FILE_PROCESS_COUNT:AtomicUsize = AtomicUsize::new(0);
18
19/// Calculate directory nesting depth for a path
20fn get_nesting_depth(path:&str) -> usize {
21	path.chars().filter(|&c| c == std::path::MAIN_SEPARATOR || c == '/').count()
22}
23
24#[tracing::instrument(skip(options))]
25/// Compiles TypeScript files from input directory to output directory
26///
27/// # Arguments
28///
29/// * `options` - Compilation options including entry, pattern, config, output
30///   directory
31/// * `_parallel` - Whether to use parallel compilation (currently unused - runs
32///   sequentially)
33pub async fn Fn(options:crate::Struct::SWC::Option, _parallel:bool) -> anyhow::Result<()> {
34	info!("=== OXC Compilation START ===");
35
36	tracing_subscriber::fmt::init();
37
38	let compiler = std::sync::Arc::new(crate::Fn::OXC::Compiler::Compiler::new(options.config.clone()));
39
40	// Get the input base path
41	let input_base = options.entry[0][0].clone();
42
43	let output_base = options.output.clone();
44
45	let pattern = options.pattern.clone();
46
47	info!("Compilation from {} to {}", input_base, output_base);
48
49	debug!("Pattern: {}, Parallel: {}", pattern, _parallel);
50
51	// Use walkdir to find all TypeScript files in the input directory
52	let walk_start = std::time::Instant::now();
53
54	let ts_files:Vec<String> = walkdir::WalkDir::new(&input_base)
55		.follow_links(true)
56		.into_iter()
57		.filter_map(|e| {
58			let entry = e.ok()?;
59
60			let path = entry.path();
61
62			if path.is_file() && path.to_string_lossy().ends_with(&pattern) {
63				Some(path.to_string_lossy().to_string())
64			} else {
65				None
66			}
67		})
68		.collect();
69
70	info!(
71		"File discovery completed in {:?}, found {} TypeScript files",
72		walk_start.elapsed(),
73		ts_files.len()
74	);
75
76	// Analyze file distribution by nesting depth
77	let mut depth_dist = std::collections::HashMap::new();
78
79	for f in &ts_files {
80		let depth = get_nesting_depth(f);
81
82		*depth_dist.entry(depth).or_insert(0) += 1;
83	}
84
85	debug!("File distribution by depth: {:?}", depth_dist);
86
87	// Sort files by nesting depth to process nested files last (diagnostic)
88	let mut sorted_files = ts_files.clone();
89
90	sorted_files.sort_by_key(|f| get_nesting_depth(f));
91
92	trace!("File list (sorted by depth):");
93
94	for (i, f) in sorted_files.iter().enumerate() {
95		trace!("  [{}] {} (depth={})", i, f, get_nesting_depth(f));
96	}
97
98	// Process files sequentially to avoid OXC globals issues
99	let mut count = 0;
100
101	let mut error = 0;
102
103	let mut current_file = 0;
104
105	let total_files = sorted_files.len();
106
107	info!("Starting sequential file processing ({} files)...", total_files);
108
109	for file_path in sorted_files {
110		current_file += 1;
111
112		let file_id = FILE_PROCESS_COUNT.fetch_add(1, Ordering::SeqCst);
113
114		let depth = get_nesting_depth(&file_path);
115
116		print!(".");
117
118		std::io::stdout().flush().unwrap();
119
120		info!(
121			"[File #{file_id}] Processing [{}/{}]: {} (depth={})",
122			current_file, total_files, file_path, depth
123		);
124
125		match tokio::fs::read_to_string(&file_path).await {
126			Ok(input) => {
127				trace!("[File #{file_id}] Read {} bytes", input.len());
128
129				// Calculate relative path from input base
130				let input_path = std::path::Path::new(&file_path);
131
132				let base_path = std::path::Path::new(&input_base);
133
134				let relative_path = input_path.strip_prefix(base_path).unwrap_or(input_path);
135
136				// Create output path preserving directory structure
137				let output_path = std::path::Path::new(&output_base).join(relative_path).with_extension("js");
138
139				debug!("[File #{file_id}] Output path: {}", output_path.display());
140
141				let compile_start = std::time::Instant::now();
142
143				match compiler.compile_file_to(&file_path, input, &output_path, options.use_define_for_class_fields) {
144					Ok(output) => {
145						info!(
146							"[File #{file_id}] SUCCESS in {:?}: {} -> {}",
147							compile_start.elapsed(),
148							file_path,
149							output
150						);
151
152						count += 1;
153					},
154
155					Err(e) => {
156						error!(
157							"[File #{file_id}] FAILED in {:?}: {} - Error: {}",
158							compile_start.elapsed(),
159							file_path,
160							e
161						);
162
163						error += 1;
164					},
165				}
166			},
167
168			Err(e) => {
169				error!("[File #{file_id}] READ FAILED: {} - Error: {}", file_path, e);
170
171				error += 1;
172			},
173		}
174	}
175
176	println!();
177
178	let outlook = compiler.outlook.lock().unwrap();
179
180	info!("=== OXC Compilation COMPLETE ===");
181
182	info!(
183		"Total: {} files, Successful: {}, Failed: {}, Time: {:?}",
184		outlook.count, count, error, outlook.elapsed
185	);
186
187	// Print summary
188	println!("\n=== Compilation Summary ===");
189
190	println!("Total files processed: {}", outlook.count);
191
192	println!("Successful: {}", count);
193
194	println!("Failed: {}", error);
195
196	println!("Time elapsed: {:?}\n", outlook.elapsed);
197
198	Ok(())
199}