Library/Fn/Worker/
compile.rs1use std::{collections::HashMap, path::Path};
6
7use super::{WorkerBootstrap, WorkerConfig, WorkerDetector, WorkerInfo, WorkerType};
8
9pub struct WorkerCompiler {
11 config:WorkerConfig,
12 detector:WorkerDetector,
13 bootstrap:WorkerBootstrap,
14 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 pub fn compile_workers(&mut self, root_dir:&Path) -> anyhow::Result<Vec<WorkerInfo>> {
30 std::fs::create_dir_all(&self.config.output_dir)?;
32
33 let workers = self.detector.detect_workers(root_dir);
35
36 for mut worker_info in workers.clone() {
38 self.compile_worker(&mut worker_info)?;
39 }
40
41 Ok(workers)
42 }
43
44 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 let source = std::fs::read_to_string(source_path)?;
54
55 worker_info.dependencies = self.detector.extract_dependencies(source_path);
57
58 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 let output_path = Path::new(&worker_info.output_path);
66 std::fs::write(output_path, &output)?;
67
68 self.compiled.insert(worker_info.name.clone(), output);
70
71 Ok(())
72 }
73
74 fn compile_module_worker(&self, source:&str, worker_info:&WorkerInfo) -> anyhow::Result<String> {
76 let bootstrap = self.bootstrap.generate_module_worker(&worker_info.source_path);
78
79 let mut output = bootstrap;
81 output.push_str("\n// Worker source\n");
82 output.push_str(source);
83
84 Ok(output)
85 }
86
87 fn compile_classic_worker(&self, source:&str, worker_info:&WorkerInfo) -> anyhow::Result<String> {
89 let bootstrap = self.bootstrap.generate_classic_worker(&worker_info.source_path);
91
92 let mut output = bootstrap;
94 output.push_str("\n// Worker source\n");
95 output.push_str(source);
96
97 Ok(output)
98 }
99
100 pub fn get_compiled(&self, name:&str) -> Option<&String> { self.compiled.get(name) }
102
103 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 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
134pub 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}