1#[derive(Debug, Clone, Serialize, Deserialize)]
2pub struct FileInfo {
3 path: PathBuf,
4 last_modified: SystemTime,
5}
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct CompilerConfig {
9 pub Target: String,
10 pub Module: String,
11 pub Strict: bool,
12 pub EmitDecoratorsMetadata: bool,
13}
14
15#[derive(Debug, Clone)]
16pub struct Option {
17 pub entry: Vec<Vec<String>>,
18 pub separator: char,
19 pub pattern: String,
20 pub config: CompilerConfig,
21}
22
23#[derive(Debug, Default)]
24pub struct CompilerMetrics {
25 pub Count: usize,
26 pub Elapsed: Duration,
27 pub Error: usize,
28}
29
30impl Default for CompilerConfig {
31 fn default() -> Self {
32 Self {
33 Target: "es2022".to_string(),
34 Module: "commonjs".to_string(),
35 Strict: true,
36 EmitDecoratorsMetadata: true,
37 }
38 }
39}
40
41#[derive(Debug)]
42pub struct Compiler {
43 pub config: CompilerConfig,
44 pub Outlook: Arc<Mutex<CompilerMetrics>>,
45}
46
47impl Compiler {
48 pub fn new(config: CompilerConfig) -> Self {
49 Self { config, Outlook: Arc::new(Mutex::new(CompilerMetrics::default())) }
50 }
51
52 #[tracing::instrument(skip(self, input))]
53 pub fn compile_file(&self, File: &str, input: String) -> anyhow::Result<String> {
54 let Begin = Instant::now();
55
56 let cm = Arc::new(SourceMap::new(FilePathMapping::empty()));
57
58 let source_file = cm.new_source_file(FileName::Real(File.into()).into(), input);
59
60 let mut parser = Parser::new_from(Lexer::new(
61 Syntax::Typescript(Default::default()),
62 EsVersion::Es2022,
63 StringInput::from(&*source_file),
64 None,
65 ));
66
67 let module = parser.parse_module().map_err(|e| anyhow::anyhow!("Failed to parse TypeScript module: {:?}", e))?;
68
69 let Unresolved = Mark::new();
70 let Top = Mark::new();
71
72 let mut program = swc_ecma_ast::Program::Module(module);
74
75 {
79 let mut pass = swc_ecma_transforms_base::resolver(Unresolved, Top, true);
80 pass.process(&mut program);
81 }
82
83 {
85 let mut pass = swc_ecma_transforms_typescript::strip(Unresolved, Top);
86 pass.process(&mut program);
87 }
88
89 {
91 let mut pass = decorators::decorators(decorators::Config {
92 legacy: false,
93 emit_metadata: self.config.EmitDecoratorsMetadata,
94 use_define_for_class_fields: true,
95 ..Default::default()
96 });
97 pass.process(&mut program);
98 }
99
100 {
102 let mut pass = inject_helpers(Unresolved);
103 pass.process(&mut program);
104 }
105
106 let module = match program {
108 swc_ecma_ast::Program::Module(m) => m,
109 _ => return Err(anyhow::anyhow!("Unexpected script")),
110 };
111
112 let mut Output = vec![];
113
114 let mut Emitter = Emitter {
115 cfg: swc_ecma_codegen::Config::default(),
116 cm: cm.clone(),
117 comments: None,
118 wr: JsWriter::new(cm.clone(), "\n", &mut Output, None),
119 };
120
121 Emitter.emit_module(&module).map_err(|e| anyhow::anyhow!("Failed to emit JavaScript: {:?}", e))?;
122
123 let Path = Path::new(File).with_extension("js");
124
125 std::fs::write(&Path, &Output)?;
126
127 let Elapsed = Begin.elapsed();
128
129 {
130 let mut Outlook = self.Outlook.lock().unwrap();
131 Outlook.Count += 1;
132 Outlook.Elapsed += Elapsed;
133 }
134
135 debug!("Compiled {} in {:?}", File, Elapsed);
136
137 Ok(Path.to_string_lossy().to_string())
138 }
139}
140
141use std::path::{Path, PathBuf};
142use std::sync::{Arc, Mutex};
143use std::time::{Duration, Instant, SystemTime};
144use serde::{Deserialize, Serialize};
145use tracing::debug;
146use swc_common::{SourceMap, FilePathMapping, FileName, Mark};
147use swc_ecma_ast::{EsVersion, Pass};
148use swc_ecma_parser::{Parser, StringInput, Syntax, lexer::Lexer};
149use swc_ecma_codegen::{Emitter, text_writer::JsWriter};
150use swc_ecma_transforms_base::helpers::inject_helpers;
151use swc_ecma_transforms_proposal::decorators;