Skip to main content

Library/Fn/Worker/
Compile.rs

1//! Worker compilation orchestration
2//!
3//! Coordinates the compilation of web workers.
4
5use std::{collections::HashMap, path::Path};
6
7use super::{WorkerBootstrap, WorkerConfig, WorkerDetector, WorkerInfo, WorkerType};
8
9/// Compiles web workers
10pub struct WorkerCompiler {
11	config:WorkerConfig,
12
13	detector:WorkerDetector,
14
15	bootstrap:WorkerBootstrap,
16
17	/// Cached compiled workers
18	compiled:HashMap<String, String>,
19}
20
21impl WorkerCompiler {
22	pub fn new(config:WorkerConfig) -> Self {
23		Self {
24			config:config.clone(),
25
26			detector:WorkerDetector::new(config.clone()),
27
28			bootstrap:WorkerBootstrap::new(config),
29
30			compiled:HashMap::new(),
31		}
32	}
33
34	/// Compile all workers in a directory
35	pub fn compile_workers(&mut self, root_dir:&Path) -> anyhow::Result<Vec<WorkerInfo>> {
36		// Ensure output directory exists
37		std::fs::create_dir_all(&self.config.output_dir)?;
38
39		// Detect all workers
40		let workers = self.detector.detect_workers(root_dir);
41
42		// Compile each worker
43		for mut worker_info in workers.clone() {
44			self.compile_worker(&mut worker_info)?;
45		}
46
47		Ok(workers)
48	}
49
50	/// Compile a single worker
51	pub fn compile_worker(&mut self, worker_info:&mut WorkerInfo) -> anyhow::Result<()> {
52		let source_path = Path::new(&worker_info.source_path);
53
54		if !source_path.exists() {
55			return Err(anyhow::anyhow!("Worker source file not found: {}", worker_info.source_path));
56		}
57
58		// Read the worker source
59		let source = std::fs::read_to_string(source_path)?;
60
61		// Extract dependencies
62		worker_info.dependencies = self.detector.extract_dependencies(source_path);
63
64		// Generate output based on worker type
65		let output = match worker_info.worker_type {
66			WorkerType::Module => self.compile_module_worker(&source, worker_info)?,
67
68			WorkerType::Classic => self.compile_classic_worker(&source, worker_info)?,
69		};
70
71		// Write output
72		let output_path = Path::new(&worker_info.output_path);
73
74		std::fs::write(output_path, &output)?;
75
76		// Cache the compiled output
77		self.compiled.insert(worker_info.name.clone(), output);
78
79		Ok(())
80	}
81
82	/// Compile a module worker
83	fn compile_module_worker(&self, source:&str, worker_info:&WorkerInfo) -> anyhow::Result<String> {
84		// Add bootstrap code for module workers
85		let bootstrap = self.bootstrap.generate_module_worker(&worker_info.source_path);
86
87		// Combine bootstrap and source
88		let mut output = bootstrap;
89
90		output.push_str("\n// Worker source\n");
91
92		output.push_str(source);
93
94		Ok(output)
95	}
96
97	/// Compile a classic worker
98	fn compile_classic_worker(&self, source:&str, worker_info:&WorkerInfo) -> anyhow::Result<String> {
99		// Add bootstrap code for classic workers
100		let bootstrap = self.bootstrap.generate_classic_worker(&worker_info.source_path);
101
102		// Combine bootstrap and source
103		let mut output = bootstrap;
104
105		output.push_str("\n// Worker source\n");
106
107		output.push_str(source);
108
109		Ok(output)
110	}
111
112	/// Get a compiled worker by name
113	pub fn get_compiled(&self, name:&str) -> Option<&String> { self.compiled.get(name) }
114
115	/// Generate worker type declarations
116	pub fn generate_declarations(&self, workers:&[WorkerInfo]) -> String {
117		let mut declarations = String::new();
118
119		declarations.push_str("// Worker type declarations\n");
120
121		declarations.push_str("// This file is auto-generated - do not edit\n\n");
122
123		for worker in workers {
124			declarations.push_str(&super::Bootstrap::generate_worker_declaration(&worker.name));
125		}
126
127		declarations
128	}
129
130	/// Create a worker entry point that lazy-loads workers
131	pub fn generate_worker_loader(&self, workers:&[WorkerInfo]) -> String {
132		let mut code = String::new();
133
134		code.push_str("// Worker loader - auto-generated\n");
135
136		code.push_str("// This file provides lazy-loading for web workers\n\n");
137
138		for worker in workers {
139			let worker_url = format!("./{}", worker.name);
140
141			code.push_str(&self.bootstrap.generate_worker_loader(&worker.name, &worker_url));
142
143			code.push('\n');
144		}
145
146		code
147	}
148}
149
150/// Simplified worker compilation function
151pub fn compile_worker_file(source_path:&Path, output_path:&Path, worker_type:WorkerType) -> anyhow::Result<()> {
152	let config = WorkerConfig::new();
153
154	let mut compiler = WorkerCompiler::new(config);
155
156	let mut worker_info = WorkerInfo::new(source_path.to_string_lossy().as_ref(), worker_type);
157
158	worker_info.output_path = output_path.to_string_lossy().to_string();
159
160	compiler.compile_worker(&mut worker_info)
161}
162
163#[cfg(test)]
164mod tests {
165
166	use tempfile::TempDir;
167
168	use super::*;
169
170	#[test]
171	fn test_worker_compiler_creation() {
172		let config = WorkerConfig::new();
173
174		let compiler = WorkerCompiler::new(config);
175
176		assert!(compiler.compiled.is_empty());
177	}
178
179	#[test]
180	fn test_worker_declaration_generation() {
181		let config = WorkerConfig::new();
182
183		let compiler = WorkerCompiler::new(config);
184
185		let workers = vec![WorkerInfo::new("test.worker.ts", WorkerType::Module)];
186
187		let declarations = compiler.generate_declarations(&workers);
188
189		assert!(declarations.contains("declare const test"));
190	}
191
192	#[test]
193	fn test_worker_loader_generation() {
194		let config = WorkerConfig::new();
195
196		let compiler = WorkerCompiler::new(config);
197
198		let workers = vec![WorkerInfo::new("test.worker.ts", WorkerType::Module)];
199
200		let loader = compiler.generate_worker_loader(&workers);
201
202		assert!(loader.contains("Worker"));
203	}
204}