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
68 .parse_module()
69 .map_err(|e| anyhow::anyhow!("Failed to parse TypeScript module: {:?}", e))?;
70
71 let Unresolved = Mark::new();
72 let Top = Mark::new();
73
74 let mut program = swc_ecma_ast::Program::Module(module);
76
77 {
81 let mut pass = swc_ecma_transforms_base::resolver(Unresolved, Top, true);
82 pass.process(&mut program);
83 }
84
85 {
87 let mut pass = swc_ecma_transforms_typescript::strip(Unresolved, Top);
88 pass.process(&mut program);
89 }
90
91 {
93 let mut pass = decorators::decorators(decorators::Config {
94 legacy:false,
95 emit_metadata:self.config.EmitDecoratorsMetadata,
96 use_define_for_class_fields:true,
97 ..Default::default()
98 });
99 pass.process(&mut program);
100 }
101
102 {
104 let mut pass = inject_helpers(Unresolved);
105 pass.process(&mut program);
106 }
107
108 let module = match program {
110 swc_ecma_ast::Program::Module(m) => m,
111 _ => return Err(anyhow::anyhow!("Unexpected script")),
112 };
113
114 let mut Output = vec![];
115
116 let mut Emitter = Emitter {
117 cfg:swc_ecma_codegen::Config::default(),
118 cm:cm.clone(),
119 comments:None,
120 wr:JsWriter::new(cm.clone(), "\n", &mut Output, None),
121 };
122
123 Emitter
124 .emit_module(&module)
125 .map_err(|e| anyhow::anyhow!("Failed to emit JavaScript: {:?}", e))?;
126
127 let Path = Path::new(File).with_extension("js");
128
129 std::fs::write(&Path, &Output)?;
130
131 let Elapsed = Begin.elapsed();
132
133 {
134 let mut Outlook = self.Outlook.lock().unwrap();
135 Outlook.Count += 1;
136 Outlook.Elapsed += Elapsed;
137 }
138
139 debug!("Compiled {} in {:?}", File, Elapsed);
140
141 Ok(Path.to_string_lossy().to_string())
142 }
143}
144
145use std::{
146 path::{Path, PathBuf},
147 sync::{Arc, Mutex},
148 time::{Duration, Instant, SystemTime},
149};
150
151use serde::{Deserialize, Serialize};
152use tracing::debug;
153use swc_common::{FileName, FilePathMapping, Mark, SourceMap};
154use swc_ecma_ast::{EsVersion, Pass};
155use swc_ecma_parser::{Parser, StringInput, Syntax, lexer::Lexer};
156use swc_ecma_codegen::{Emitter, text_writer::JsWriter};
157use swc_ecma_transforms_base::helpers::inject_helpers;
158use swc_ecma_transforms_proposal::decorators;