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