vue_compiler_core/transformer/
mod.rs1pub mod collect_entities;
25pub mod mark_patch_flag;
26pub mod mark_slot_flag;
27pub mod optimize_text;
28pub mod pass;
29pub mod process_expression;
30
31use super::converter::{
32 self as C, BaseConvertInfo as BaseInfo, BaseRoot, ConvertInfo, IRNode, IRRoot, JsExpr as Js,
33 RuntimeDir,
34};
35pub use pass::{CorePass, CorePassExt, MergedPass, Scope};
36use std::marker::PhantomData;
37
38pub trait Transformer {
39 type IR;
40 fn transform(&mut self, root: &mut Self::IR);
43}
44
45#[derive(Default)]
46pub struct TransformOption {
47 is_ts: bool,
48 inline: bool,
49 prefix_identifier: bool,
50 is_dev: bool,
51}
52
53pub type BaseText<'a> = C::TextIR<BaseInfo<'a>>;
54pub type BaseIf<'a> = C::IfNodeIR<BaseInfo<'a>>;
55pub type BaseFor<'a> = C::ForNodeIR<BaseInfo<'a>>;
56pub type BaseVNode<'a> = C::VNodeIR<BaseInfo<'a>>;
57pub type BaseRenderSlot<'a> = C::RenderSlotIR<BaseInfo<'a>>;
58pub type BaseVSlot<'a> = C::VSlotIR<BaseInfo<'a>>;
59pub type BaseSlotFn<'a> = C::Slot<BaseInfo<'a>>;
60
61struct NoopTransformer<T>(PhantomData<T>);
62
63impl<T> Transformer for NoopTransformer<T> {
64 type IR = T;
65 fn transform(&mut self, _root: &mut Self::IR) {
66 }
68}
69
70trait CoreTransformer<T: ConvertInfo, P: CorePass<T>>: Transformer {
71 fn transform_root(root: &mut IRRoot<T>, ps: &mut P);
72 fn transform_js_expr(e: &mut T::JsExpression, ps: &mut P);
73
74 fn transform_ir(ir: &mut IRNode<T>, ps: &mut P) {
75 use IRNode as I;
76 match ir {
77 I::TextCall(t) => Self::transform_text(t, ps),
78 I::If(i) => Self::transform_if(i, ps),
79 I::For(f) => Self::transform_for(f, ps),
80 I::VNodeCall(v) => Self::transform_vnode(v, ps),
81 I::RenderSlotCall(r) => Self::transform_slot_outlet(r, ps),
82 I::CommentCall(c) => Self::transform_comment(c, ps),
83 I::VSlotUse(s) => Self::transform_v_slot(s, ps),
84 I::AlterableSlot(a) => Self::transform_slot_fn(a, ps),
85 }
86 }
87 fn transform_children(children: &mut Vec<IRNode<T>>, ps: &mut P) {
88 for child in children.iter_mut() {
89 Self::transform_ir(child, ps);
90 }
91 }
92 fn transform_text(t: &mut C::TextIR<T>, ps: &mut P) {
93 ps.enter_text(t);
94 for text in t.texts.as_mut().iter_mut() {
95 Self::transform_js_expr(text, ps);
96 }
97 ps.exit_text(t);
98 }
99 fn transform_if(i: &mut C::IfNodeIR<T>, ps: &mut P) {
100 ps.enter_if(i);
101 for branch in i.branches.iter_mut() {
102 if let Some(c) = branch.condition.as_mut() {
103 Self::transform_js_expr(c, ps);
104 }
105 Self::transform_ir(&mut branch.child, ps);
106 }
107 ps.exit_if(i);
108 }
109 fn transform_for(f: &mut C::ForNodeIR<T>, ps: &mut P) {
110 Self::transform_js_expr(&mut f.source, ps);
112 use crate::converter::ForParseResult;
113 let ForParseResult { value, key, index } = &mut f.parse_result;
116 ps.enter_fn_param(value);
117 if let Some(k) = key {
118 ps.enter_fn_param(k);
119 }
120 if let Some(i) = index {
121 ps.enter_fn_param(i);
122 }
123
124 ps.enter_for(f);
126 Self::transform_ir(&mut f.child, ps);
127 ps.exit_for(f);
128
129 let ForParseResult { value, key, index } = &mut f.parse_result;
130 if let Some(i) = index {
131 Self::transform_js_expr(i, ps);
132 ps.exit_fn_param(i);
133 }
134 if let Some(k) = key {
135 Self::transform_js_expr(k, ps);
136 ps.exit_fn_param(k);
137 }
138 Self::transform_js_expr(value, ps);
139 ps.exit_fn_param(value);
140 }
141 fn transform_vnode(v: &mut C::VNodeIR<T>, ps: &mut P) {
142 ps.enter_vnode(v);
143 Self::transform_js_expr(&mut v.tag, ps);
144 if let Some(props) = v.props.as_mut() {
145 Self::transform_js_expr(props, ps);
146 }
147 Self::transform_children(&mut v.children, ps);
148 for dir in v.directives.iter_mut() {
149 Self::transform_runtime_dir(dir, ps);
150 }
151 ps.exit_vnode(v);
152 }
153 fn transform_runtime_dir(dir: &mut RuntimeDir<T>, ps: &mut P) {
154 Self::transform_js_expr(&mut dir.name, ps);
155 if let Some(expr) = dir.expr.as_mut() {
156 Self::transform_js_expr(expr, ps);
157 }
158 if let Some(arg) = dir.arg.as_mut() {
159 Self::transform_js_expr(arg, ps);
160 }
161 if let Some(mods) = dir.mods.as_mut() {
162 Self::transform_js_expr(mods, ps);
163 }
164 }
165 fn transform_slot_outlet(r: &mut C::RenderSlotIR<T>, ps: &mut P) {
166 ps.enter_slot_outlet(r);
167 Self::transform_js_expr(&mut r.slot_name, ps);
168 if let Some(props) = r.slot_props.as_mut() {
169 Self::transform_js_expr(props, ps);
170 }
171 Self::transform_children(&mut r.fallbacks, ps);
172 ps.exit_slot_outlet(r);
173 }
174 fn transform_v_slot(s: &mut C::VSlotIR<T>, ps: &mut P) {
175 ps.enter_v_slot(s);
176 for slot in s.stable_slots.iter_mut() {
177 Self::transform_slot_fn(slot, ps);
178 }
179 for slot in s.alterable_slots.iter_mut() {
180 Self::transform_ir(slot, ps);
181 }
182 ps.exit_v_slot(s);
183 }
184 fn transform_slot_fn(slot: &mut C::Slot<T>, ps: &mut P) {
185 ps.enter_slot_fn(slot);
186 Self::transform_js_expr(&mut slot.name, ps);
187 if let Some(p) = &mut slot.param {
190 ps.enter_fn_param(p);
191 }
192 Self::transform_children(&mut slot.body, ps);
193 if let Some(p) = &mut slot.param {
194 Self::transform_js_expr(p, ps);
195 ps.exit_fn_param(p);
196 }
197 ps.exit_slot_fn(slot);
198 }
199 fn transform_comment(c: &mut T::CommentType, ps: &mut P) {
200 ps.enter_comment(c);
201 ps.exit_comment(c);
202 }
203}
204
205pub struct BaseTransformer<'a, P: CorePass<BaseInfo<'a>>> {
206 pass: P,
207 pd: PhantomData<&'a ()>,
208}
209impl<'a, P: CorePass<BaseInfo<'a>>> BaseTransformer<'a, P> {
210 pub fn new(pass: P) -> Self {
211 Self {
212 pass,
213 pd: PhantomData,
214 }
215 }
216}
217
218impl<'a, P: CorePass<BaseInfo<'a>>> Transformer for BaseTransformer<'a, P> {
219 type IR = BaseRoot<'a>;
220 fn transform(&mut self, node: &mut Self::IR) {
221 Self::transform_root(node, &mut self.pass);
222 }
223}
224
225impl<'a, P> CoreTransformer<BaseInfo<'a>, P> for BaseTransformer<'a, P>
226where
227 P: CorePass<BaseInfo<'a>>,
228{
229 fn transform_root(r: &mut IRRoot<BaseInfo<'a>>, ps: &mut P) {
230 ps.enter_root(r);
231 Self::transform_children(&mut r.body, ps);
232 ps.exit_root(r);
233 }
234
235 fn transform_js_expr(e: &mut Js<'a>, ps: &mut P) {
236 ps.enter_js_expr(e);
237 match e {
238 Js::Call(_, args) => {
239 for arg in args.iter_mut() {
240 Self::transform_js_expr(arg, ps);
241 }
242 }
243 Js::Compound(exprs) => {
244 for expr in exprs.iter_mut() {
245 Self::transform_js_expr(expr, ps);
246 }
247 }
248 Js::Array(arr) => {
249 for item in arr.iter_mut() {
250 Self::transform_js_expr(item, ps);
251 }
252 }
253 Js::Props(props) => {
254 for (key, val) in props.iter_mut() {
255 Self::transform_js_expr(key, ps);
256 Self::transform_js_expr(val, ps);
257 }
258 }
259 Js::Src(_)
260 | Js::Num(_)
261 | Js::Simple(..)
262 | Js::Param(_)
263 | Js::StrLit(_)
264 | Js::Symbol(_) => {
265 }
267 }
268 ps.exit_js_expr(e);
269 }
270}
271
272#[cfg(test)]
273mod test {
274 use super::pass::{MergedPass, Scope, SharedInfoPasses};
275 use super::*;
276 pub use crate::converter::test::base_convert;
277 use rustc_hash::FxHashMap;
278 pub fn get_transformer<'a, P>(pass: P) -> BaseTransformer<'a, P>
279 where
280 P: CorePass<BaseInfo<'a>> + 'static,
281 {
282 BaseTransformer {
283 pass,
284 pd: PhantomData,
285 }
286 }
287
288 pub fn transformer_ext<'a, 'b>(
289 passes: &'b mut [&'b mut dyn CorePassExt<BaseInfo<'a>, Scope<'a>>],
290 ) -> BaseTransformer<
291 'a,
292 SharedInfoPasses<'b, &'b mut dyn CorePassExt<BaseInfo<'a>, Scope<'a>>, Scope<'a>>,
293 > {
294 let pass = SharedInfoPasses {
295 passes: MergedPass::new(passes),
296 shared_info: Scope {
297 identifiers: FxHashMap::default(),
298 },
299 };
300 BaseTransformer {
301 pass,
302 pd: PhantomData,
303 }
304 }
305}