Rest/Struct/
SWC.rs

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		// Convert module to program to apply passes
75		let mut program = swc_ecma_ast::Program::Module(module);
76
77		// Apply transforms using process() or visit_mut_with()
78
79		// 1. Resolver
80		{
81			let mut pass = swc_ecma_transforms_base::resolver(Unresolved, Top, true);
82			pass.process(&mut program);
83		}
84
85		// 2. Strip TypeScript
86		{
87			let mut pass = swc_ecma_transforms_typescript::strip(Unresolved, Top);
88			pass.process(&mut program);
89		}
90
91		// 3. Decorators
92		{
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		// 4. Inject Helpers
103		{
104			let mut pass = inject_helpers(Unresolved);
105			pass.process(&mut program);
106		}
107
108		// Convert back to module for emitting
109		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;