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
13 detector:WorkerDetector,
14
15 bootstrap:WorkerBootstrap,
16
17 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 pub fn compile_workers(&mut self, root_dir:&Path) -> anyhow::Result<Vec<WorkerInfo>> {
36 std::fs::create_dir_all(&self.config.output_dir)?;
38
39 let workers = self.detector.detect_workers(root_dir);
41
42 for mut worker_info in workers.clone() {
44 self.compile_worker(&mut worker_info)?;
45 }
46
47 Ok(workers)
48 }
49
50 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 let source = std::fs::read_to_string(source_path)?;
60
61 worker_info.dependencies = self.detector.extract_dependencies(source_path);
63
64 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 let output_path = Path::new(&worker_info.output_path);
73
74 std::fs::write(output_path, &output)?;
75
76 self.compiled.insert(worker_info.name.clone(), output);
78
79 Ok(())
80 }
81
82 fn compile_module_worker(&self, source:&str, worker_info:&WorkerInfo) -> anyhow::Result<String> {
84 let bootstrap = self.bootstrap.generate_module_worker(&worker_info.source_path);
86
87 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 fn compile_classic_worker(&self, source:&str, worker_info:&WorkerInfo) -> anyhow::Result<String> {
99 let bootstrap = self.bootstrap.generate_classic_worker(&worker_info.source_path);
101
102 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 pub fn get_compiled(&self, name:&str) -> Option<&String> { self.compiled.get(name) }
114
115 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 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
150pub 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}