1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//! Transformation engine for AST manipulation
//!
//! Provides a pipeline for applying multiple transformations to code.
#[cfg(feature = "transform-engine")]
mod transform_impl {
use crate::error::Result;
use crate::format::FormatOptions;
use crate::parser::{ParseOptions, ParsedProgram};
use oxc_allocator::Allocator;
/// Result of a transformation pass
#[derive(Debug)]
pub struct TransformResult {
/// Whether the transformation modified the AST
pub modified: bool,
/// Diagnostics from the transformation
pub diagnostics: Vec<String>,
}
impl TransformResult {
pub fn success() -> Self {
Self {
modified: false,
diagnostics: Vec::new(),
}
}
pub fn modified() -> Self {
Self {
modified: true,
diagnostics: Vec::new(),
}
}
pub fn with_diagnostics(mut self, diag: String) -> Self {
self.diagnostics.push(diag);
self
}
}
/// Trait for transformation passes
pub trait TransformPass {
/// Name of the transformation pass
fn name(&self) -> &'static str;
/// Run the transformation on a parsed program
fn run(&self, program: &mut ParsedProgram) -> Result<TransformResult>;
}
/// Transformation engine that applies multiple passes
pub struct TransformEngine<'a> {
allocator: &'a Allocator,
passes: Vec<Box<dyn TransformPass + 'a>>,
parse_options: ParseOptions,
format_options: FormatOptions,
}
impl<'a> TransformEngine<'a> {
/// Create a new transformation engine
pub fn new(allocator: &'a Allocator) -> Self {
Self {
allocator,
passes: Vec::new(),
parse_options: ParseOptions::default(),
format_options: FormatOptions::default(),
}
}
/// Set parse options
pub fn with_parse_options(mut self, opts: ParseOptions) -> Self {
self.parse_options = opts;
self
}
/// Set format options
pub fn with_format_options(mut self, opts: FormatOptions) -> Self {
self.format_options = opts;
self
}
/// Add a transformation pass
pub fn add_pass<P: TransformPass + 'a>(mut self, pass: P) -> Self {
self.passes.push(Box::new(pass));
self
}
/// Transform source code
pub fn transform(&self, source: &'a str) -> Result<TransformOutput> {
use crate::parser::parse;
// Parse the source
let mut parsed = parse(self.allocator, source, self.parse_options.clone())?;
// Apply all passes
let mut all_diagnostics = Vec::new();
let mut any_modified = false;
for pass in &self.passes {
let result = pass.run(&mut parsed)?;
any_modified |= result.modified;
all_diagnostics.extend(result.diagnostics);
}
// Generate code
use oxc_codegen::Codegen;
let codegen = Codegen::new();
let result = codegen.build(&parsed.program);
let code = result.code;
Ok(TransformOutput {
code,
modified: any_modified,
diagnostics: all_diagnostics,
})
}
}
/// Output from transformation engine
#[derive(Debug)]
pub struct TransformOutput {
/// Generated code
pub code: String,
/// Whether the code was modified
pub modified: bool,
/// Diagnostics from transformations
pub diagnostics: Vec<String>,
}
}
#[cfg(feature = "transform-engine")]
pub use transform_impl::*;