swc_estree_compat/babelify/
jsx.rs1use copyless::BoxHelper;
2use swc_common::{BytePos, Span, Spanned};
3use swc_ecma_ast::{
4 JSXAttr, JSXAttrName, JSXAttrOrSpread, JSXAttrValue, JSXClosingElement, JSXClosingFragment,
5 JSXElement, JSXElementChild, JSXElementName, JSXEmptyExpr, JSXExpr, JSXExprContainer,
6 JSXFragment, JSXMemberExpr, JSXNamespacedName, JSXObject, JSXOpeningElement,
7 JSXOpeningFragment, JSXSpreadChild, JSXText, Lit,
8};
9use swc_estree_ast::{
10 flavor::Flavor, JSXAttrName as BabelJSXAttrName, JSXAttrVal, JSXAttribute,
11 JSXClosingElement as BabelJSXClosingElement, JSXClosingFragment as BabelJSXClosingFragment,
12 JSXElement as BabelJSXElement, JSXElementChild as BabelJSXElementChild,
13 JSXElementName as BabelJSXElementName, JSXEmptyExpression, JSXExprContainerExpr,
14 JSXExpressionContainer, JSXFragment as BabelJSXFragment, JSXMemberExprObject,
15 JSXMemberExpression, JSXNamespacedName as BabelJSXNamespacedName, JSXOpeningElAttr,
16 JSXOpeningElement as BabelJSXOpeningElement, JSXOpeningFragment as BabelJSXOpeningFragment,
17 JSXSpreadAttribute, JSXSpreadChild as BabelJSXSpreadChild, JSXText as BabelJSXText,
18};
19
20use crate::babelify::{Babelify, Context};
21
22impl Babelify for JSXObject {
23 type Output = JSXMemberExprObject;
24
25 fn babelify(self, ctx: &Context) -> Self::Output {
26 match self {
27 JSXObject::JSXMemberExpr(e) => JSXMemberExprObject::Expr(e.babelify(ctx)),
28 JSXObject::Ident(i) => JSXMemberExprObject::Id(i.babelify(ctx).into()),
29 #[cfg(swc_ast_unknown)]
30 _ => panic!("unable to access unknown nodes"),
31 }
32 }
33}
34
35impl Babelify for JSXMemberExpr {
36 type Output = JSXMemberExpression;
37
38 fn babelify(self, ctx: &Context) -> Self::Output {
39 JSXMemberExpression {
40 base: ctx.base(self.span()),
41 object: Box::alloc().init(self.obj.babelify(ctx)),
42 property: self.prop.babelify(ctx).into(),
43 }
44 }
45}
46
47impl Babelify for JSXNamespacedName {
48 type Output = BabelJSXNamespacedName;
49
50 fn babelify(self, ctx: &Context) -> Self::Output {
51 BabelJSXNamespacedName {
52 base: ctx.base(self.span()),
53 namespace: self.ns.babelify(ctx).into(),
54 name: self.name.babelify(ctx).into(),
55 }
56 }
57}
58
59impl Babelify for JSXEmptyExpr {
60 type Output = JSXEmptyExpression;
61
62 fn babelify(self, ctx: &Context) -> Self::Output {
63 JSXEmptyExpression {
64 base: ctx.base(self.span),
65 }
66 }
67}
68
69impl Babelify for JSXExprContainer {
70 type Output = JSXExpressionContainer;
71
72 fn babelify(self, ctx: &Context) -> Self::Output {
73 JSXExpressionContainer {
74 base: ctx.base(self.span),
75 expression: self.expr.babelify(ctx),
76 }
77 }
78}
79
80impl Babelify for JSXExpr {
81 type Output = JSXExprContainerExpr;
82
83 fn babelify(self, ctx: &Context) -> Self::Output {
84 match self {
85 JSXExpr::JSXEmptyExpr(e) => JSXExprContainerExpr::Empty(e.babelify(ctx)),
86 JSXExpr::Expr(e) => {
87 JSXExprContainerExpr::Expr(Box::alloc().init(e.babelify(ctx).into()))
88 }
89 #[cfg(swc_ast_unknown)]
90 _ => panic!("unable to access unknown nodes"),
91 }
92 }
93}
94
95impl Babelify for JSXSpreadChild {
96 type Output = BabelJSXSpreadChild;
97
98 fn babelify(self, ctx: &Context) -> Self::Output {
99 BabelJSXSpreadChild {
100 base: ctx.base(self.span),
101 expression: Box::alloc().init(self.expr.babelify(ctx).into()),
102 }
103 }
104}
105
106impl Babelify for JSXElementName {
107 type Output = BabelJSXElementName;
108
109 fn babelify(self, ctx: &Context) -> Self::Output {
110 match self {
111 JSXElementName::Ident(i) => BabelJSXElementName::Id(i.babelify(ctx).into()),
112 JSXElementName::JSXMemberExpr(e) => BabelJSXElementName::Expr(e.babelify(ctx)),
113 JSXElementName::JSXNamespacedName(n) => BabelJSXElementName::Name(n.babelify(ctx)),
114 #[cfg(swc_ast_unknown)]
115 _ => panic!("unable to access unknown nodes"),
116 }
117 }
118}
119
120impl Babelify for JSXOpeningElement {
121 type Output = BabelJSXOpeningElement;
122
123 fn babelify(self, ctx: &Context) -> Self::Output {
124 BabelJSXOpeningElement {
125 base: ctx.base(self.span),
126 name: self.name.babelify(ctx),
127 attributes: self.attrs.babelify(ctx),
128 self_closing: self.self_closing,
129 type_parameters: self.type_args.map(|arg| arg.babelify(ctx).into()),
130 }
131 }
132}
133
134impl Babelify for JSXAttrOrSpread {
135 type Output = JSXOpeningElAttr;
136
137 fn babelify(self, ctx: &Context) -> Self::Output {
138 match self {
139 JSXAttrOrSpread::JSXAttr(a) => JSXOpeningElAttr::Attr(a.babelify(ctx)),
140 JSXAttrOrSpread::SpreadElement(spread) => {
141 let span = extend_spread_span_to_braces(spread.span(), ctx);
144 JSXOpeningElAttr::Spread(JSXSpreadAttribute {
145 base: ctx.base(span),
146 argument: Box::alloc().init(spread.expr.babelify(ctx).into()),
147 })
148 }
149 #[cfg(swc_ast_unknown)]
150 _ => panic!("unable to access unknown nodes"),
151 }
152 }
153}
154
155fn extend_spread_span_to_braces(sp: Span, ctx: &Context) -> Span {
156 let mut span = sp;
157 let _ = ctx.cm.with_span_to_prev_source(sp, |prev_source| {
158 let mut num_chars = 0;
159 for c in prev_source.chars().rev() {
160 num_chars += 1;
161 if c == '{' {
162 span = span.with_lo(span.lo - BytePos(num_chars));
163 } else if !c.is_whitespace() {
164 break;
165 }
166 }
167 });
168
169 let _ = ctx.cm.with_span_to_next_source(sp, |next_source| {
170 let mut num_chars = 0;
171 for c in next_source.chars() {
172 num_chars += 1;
173 if c == '}' {
174 span = span.with_hi(span.hi + BytePos(num_chars));
175 } else if !c.is_whitespace() {
176 break;
177 }
178 }
179 });
180
181 span
182}
183
184impl Babelify for JSXClosingElement {
185 type Output = BabelJSXClosingElement;
186
187 fn babelify(self, ctx: &Context) -> Self::Output {
188 BabelJSXClosingElement {
189 base: ctx.base(self.span),
190 name: self.name.babelify(ctx),
191 }
192 }
193}
194
195impl Babelify for JSXAttr {
196 type Output = JSXAttribute;
197
198 fn babelify(self, ctx: &Context) -> Self::Output {
199 JSXAttribute {
200 base: ctx.base(self.span),
201 name: self.name.babelify(ctx),
202 value: self.value.map(|val| val.babelify(ctx)),
203 }
204 }
205}
206
207impl Babelify for JSXAttrName {
208 type Output = BabelJSXAttrName;
209
210 fn babelify(self, ctx: &Context) -> Self::Output {
211 match self {
212 JSXAttrName::Ident(i) => BabelJSXAttrName::Id(i.babelify(ctx).into()),
213 JSXAttrName::JSXNamespacedName(n) => BabelJSXAttrName::Name(n.babelify(ctx)),
214 #[cfg(swc_ast_unknown)]
215 _ => panic!("unable to access unknown nodes"),
216 }
217 }
218}
219
220impl Babelify for JSXAttrValue {
221 type Output = JSXAttrVal;
222
223 fn babelify(self, ctx: &Context) -> Self::Output {
224 match self {
225 JSXAttrValue::Lit(lit) => {
226 match lit {
229 Lit::Str(s) => JSXAttrVal::String(s.babelify(ctx)),
230 _ => panic!(
231 "illegal conversion: Cannot convert {:?} to JsxAttrVal::Lit",
232 &lit
233 ),
234 }
235 }
236 JSXAttrValue::JSXExprContainer(e) => JSXAttrVal::Expr(e.babelify(ctx)),
237 JSXAttrValue::JSXElement(e) => JSXAttrVal::Element(e.babelify(ctx)),
238 JSXAttrValue::JSXFragment(f) => JSXAttrVal::Fragment(f.babelify(ctx)),
239 #[cfg(swc_ast_unknown)]
240 _ => panic!("unable to access unknown nodes"),
241 }
242 }
243}
244
245impl Babelify for JSXText {
246 type Output = BabelJSXText;
247
248 fn babelify(self, ctx: &Context) -> Self::Output {
249 BabelJSXText {
250 base: ctx.base(self.span),
251 value: self.value,
252 }
253 }
254}
255
256impl Babelify for JSXElement {
257 type Output = BabelJSXElement;
258
259 fn babelify(self, ctx: &Context) -> Self::Output {
260 let self_closing = match Flavor::current() {
261 Flavor::Babel => None,
262 Flavor::Acorn { .. } => Some(self.closing.is_some()),
263 };
264 BabelJSXElement {
265 base: ctx.base(self.span),
266 opening_element: self.opening.babelify(ctx),
267 closing_element: self.closing.map(|el| el.babelify(ctx)),
268 children: self.children.babelify(ctx),
269 self_closing,
270 }
271 }
272}
273
274impl Babelify for JSXElementChild {
275 type Output = BabelJSXElementChild;
276
277 fn babelify(self, ctx: &Context) -> Self::Output {
278 match self {
279 JSXElementChild::JSXText(t) => BabelJSXElementChild::Text(t.babelify(ctx)),
280 JSXElementChild::JSXExprContainer(e) => BabelJSXElementChild::Expr(e.babelify(ctx)),
281 JSXElementChild::JSXSpreadChild(s) => BabelJSXElementChild::Spread(s.babelify(ctx)),
282 JSXElementChild::JSXElement(e) => BabelJSXElementChild::Element(e.babelify(ctx)),
283 JSXElementChild::JSXFragment(f) => BabelJSXElementChild::Fragment(f.babelify(ctx)),
284 #[cfg(swc_ast_unknown)]
285 _ => panic!("unable to access unknown nodes"),
286 }
287 }
288}
289
290impl Babelify for JSXFragment {
291 type Output = BabelJSXFragment;
292
293 fn babelify(self, ctx: &Context) -> Self::Output {
294 BabelJSXFragment {
295 base: ctx.base(self.span),
296 opening_fragment: self.opening.babelify(ctx),
297 closing_fragment: self.closing.babelify(ctx),
298 children: self.children.babelify(ctx),
299 }
300 }
301}
302
303impl Babelify for JSXOpeningFragment {
304 type Output = BabelJSXOpeningFragment;
305
306 fn babelify(self, ctx: &Context) -> Self::Output {
307 BabelJSXOpeningFragment {
308 base: ctx.base(self.span),
309 }
310 }
311}
312
313impl Babelify for JSXClosingFragment {
314 type Output = BabelJSXClosingFragment;
315
316 fn babelify(self, ctx: &Context) -> Self::Output {
317 BabelJSXClosingFragment {
318 base: ctx.base(self.span),
319 }
320 }
321}