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
#![feature(box_syntax)]
#![feature(box_patterns)]
#![feature(is_some_and)]
#![feature(let_chains)]
#![feature(if_let_guard)]
#![allow(clippy::not_unsafe_ptr_arg_deref)]
use std::collections::HashMap;
pub use options::PluginOptions;
use swc_core::{
common::{comments::Comments, Mark},
ecma::{
ast::{Expr, Ident, Module, Program},
visit::{as_folder, noop_visit_mut_type, FoldWith, VisitMut, VisitMutWith},
},
plugin::{plugin_transform, proxies::TransformPluginProgramMetadata as Metadata},
};
use swc_helper_jsx_transform::shared::Transform;
use swc_helper_module_import::ImportHelper;
use crate::{
hoist::Hoist,
shared::{convert::Convert, expr::ExprExtend},
};
mod constant;
mod context;
mod element;
mod fragment;
mod hoist;
mod options;
mod patch_flag;
mod shared;
mod split_static;
mod text;
mod utils;
mod vnode;
#[plugin_transform]
pub fn process_transform(program: Program, metadata: Metadata) -> Program {
let opts = PluginOptions::from(&metadata);
let Metadata {
comments,
unresolved_mark,
..
} = metadata;
program.fold_with(&mut as_folder(VueJSX::new(opts, comments, unresolved_mark)))
}
#[allow(dead_code)]
pub struct VueJSX<'a, C: Comments> {
opts: PluginOptions,
comments: Option<C>,
unresolved_mark: Mark,
import_helper: ImportHelper<'a>,
ident_map: HashMap<&'a str, Ident>,
module_hoist: Hoist<'a>,
scope_hoist: Hoist<'a>,
}
impl<'a, C: Comments> VueJSX<'a, C> {
pub fn new(opts: PluginOptions, comments: Option<C>, unresolved_mark: Mark) -> Self {
Self {
opts,
comments,
unresolved_mark,
import_helper: ImportHelper::default(),
ident_map: HashMap::new(),
module_hoist: Hoist::new("_hoisted_"),
scope_hoist: Hoist::new("_v"),
}
}
pub fn store(&mut self, module: &mut Module) {
self.import_helper.store(module)
}
pub fn complete(&mut self, module: &mut Module) {
self.import_helper.add_to_module(module);
self.module_hoist.add_to_module(module)
}
}
impl<'a, 'b, C: Comments> VueJSX<'a, C> {
pub fn compile<T, U>(&mut self, target: &'b T) -> Expr
where
T: Transform<'b, U>,
U: Convert<'a, Expr>,
{
target
.transform()
.convert(self)
.with_hoist(&mut self.scope_hoist)
}
}
impl<'a, C: Comments> VisitMut for VueJSX<'a, C> {
noop_visit_mut_type!();
fn visit_mut_module(&mut self, module: &mut Module) {
self.store(module);
module.visit_mut_children_with(self);
self.complete(module)
}
fn visit_mut_expr(&mut self, expr: &mut Expr) {
match &expr {
Expr::JSXElement(box element) => {
*expr = self.compile(element);
},
Expr::JSXFragment(fragment) => {
*expr = self.compile(fragment);
},
_ => {},
}
expr.visit_mut_children_with(self);
}
}