swc_ecma_ast/
jsx.rs

1use is_macro::Is;
2use swc_atoms::Atom;
3use swc_common::{ast_node, util::take::Take, EqIgnoreSpan, Span, DUMMY_SP};
4
5use crate::{
6    expr::{Expr, SpreadElement},
7    ident::Ident,
8    lit::Lit,
9    typescript::TsTypeParamInstantiation,
10    IdentName,
11};
12
13/// Used for `obj` property of `JSXMemberExpr`.
14#[ast_node]
15#[derive(Eq, Hash, Is, EqIgnoreSpan)]
16#[allow(variant_size_differences)]
17#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
18#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
19pub enum JSXObject {
20    #[tag("JSXMemberExpression")]
21    JSXMemberExpr(Box<JSXMemberExpr>),
22    #[tag("Identifier")]
23    Ident(Ident),
24}
25
26#[ast_node("JSXMemberExpression")]
27#[derive(Eq, Hash, EqIgnoreSpan)]
28#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
29#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
30pub struct JSXMemberExpr {
31    pub span: Span,
32
33    #[cfg_attr(feature = "serde-impl", serde(rename = "object"))]
34    pub obj: JSXObject,
35
36    #[cfg_attr(feature = "serde-impl", serde(rename = "property"))]
37    pub prop: IdentName,
38}
39
40/// XML-based namespace syntax:
41#[ast_node("JSXNamespacedName")]
42#[derive(Eq, Hash, EqIgnoreSpan)]
43#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
44#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
45pub struct JSXNamespacedName {
46    pub span: Span,
47    #[cfg_attr(feature = "serde-impl", serde(rename = "namespace"))]
48    pub ns: IdentName,
49    pub name: IdentName,
50}
51
52#[ast_node("JSXEmptyExpression")]
53#[derive(Eq, Hash, Copy, EqIgnoreSpan)]
54#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
55#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
56pub struct JSXEmptyExpr {
57    pub span: Span,
58}
59
60#[ast_node("JSXExpressionContainer")]
61#[derive(Eq, Hash, EqIgnoreSpan)]
62#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
63#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
64pub struct JSXExprContainer {
65    pub span: Span,
66    #[cfg_attr(feature = "serde-impl", serde(rename = "expression"))]
67    pub expr: JSXExpr,
68}
69
70#[ast_node]
71#[derive(Eq, Hash, EqIgnoreSpan)]
72#[allow(variant_size_differences)]
73#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
74#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
75pub enum JSXExpr {
76    #[tag("JSXEmptyExpression")]
77    JSXEmptyExpr(JSXEmptyExpr),
78    #[tag("*")]
79    Expr(Box<Expr>),
80}
81
82#[ast_node("JSXSpreadChild")]
83#[derive(Eq, Hash, EqIgnoreSpan)]
84#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
85#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
86pub struct JSXSpreadChild {
87    pub span: Span,
88    #[cfg_attr(feature = "serde-impl", serde(rename = "expression"))]
89    pub expr: Box<Expr>,
90}
91
92#[ast_node]
93#[derive(Eq, Hash, EqIgnoreSpan)]
94#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
95#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
96pub enum JSXElementName {
97    #[tag("Identifier")]
98    Ident(Ident),
99    #[tag("JSXMemberExpression")]
100    JSXMemberExpr(JSXMemberExpr),
101    #[tag("JSXNamespacedName")]
102    JSXNamespacedName(JSXNamespacedName),
103}
104
105impl Take for JSXElementName {
106    fn dummy() -> Self {
107        JSXElementName::Ident(Take::dummy())
108    }
109}
110
111#[ast_node("JSXOpeningElement")]
112#[derive(Eq, Hash, EqIgnoreSpan)]
113#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
114#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
115pub struct JSXOpeningElement {
116    pub name: JSXElementName,
117
118    pub span: Span,
119
120    #[cfg_attr(feature = "serde-impl", serde(default, rename = "attributes"))]
121    pub attrs: Vec<JSXAttrOrSpread>,
122
123    #[cfg_attr(feature = "serde-impl", serde(rename = "selfClosing"))]
124    pub self_closing: bool,
125
126    /// Note: This field's name is different from one from babel because it is
127    /// misleading
128    #[cfg_attr(feature = "serde-impl", serde(default, rename = "typeArguments"))]
129    pub type_args: Option<Box<TsTypeParamInstantiation>>,
130}
131
132impl Take for JSXOpeningElement {
133    fn dummy() -> Self {
134        JSXOpeningElement {
135            name: Take::dummy(),
136            span: DUMMY_SP,
137            attrs: Take::dummy(),
138            self_closing: Default::default(),
139            type_args: Take::dummy(),
140        }
141    }
142}
143
144#[ast_node]
145#[derive(Eq, Hash, EqIgnoreSpan)]
146#[allow(variant_size_differences)]
147#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
148#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
149pub enum JSXAttrOrSpread {
150    #[tag("JSXAttribute")]
151    JSXAttr(JSXAttr),
152    #[tag("SpreadElement")]
153    SpreadElement(SpreadElement),
154}
155
156#[ast_node("JSXClosingElement")]
157#[derive(Eq, Hash, EqIgnoreSpan)]
158#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
159#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
160pub struct JSXClosingElement {
161    pub span: Span,
162    pub name: JSXElementName,
163}
164
165#[ast_node("JSXAttribute")]
166#[derive(Eq, Hash, EqIgnoreSpan)]
167#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
168#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
169pub struct JSXAttr {
170    pub span: Span,
171    pub name: JSXAttrName,
172    /// Babel uses Expr instead of JSXAttrValue
173    pub value: Option<JSXAttrValue>,
174}
175
176#[ast_node]
177#[derive(Eq, Hash, EqIgnoreSpan)]
178#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
179#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
180pub enum JSXAttrName {
181    #[tag("Identifier")]
182    Ident(IdentName),
183    #[tag("JSXNamespacedName")]
184    JSXNamespacedName(JSXNamespacedName),
185}
186
187#[ast_node]
188#[derive(Eq, Hash, EqIgnoreSpan)]
189#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
190#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
191pub enum JSXAttrValue {
192    #[tag("StringLiteral")]
193    #[tag("BooleanLiteral")]
194    #[tag("NullLiteral")]
195    #[tag("NumericLiteral")]
196    #[tag("RegExpLiteral")]
197    #[tag("JSXText")]
198    Lit(Lit),
199
200    #[tag("JSXExpressionContainer")]
201    JSXExprContainer(JSXExprContainer),
202
203    #[tag("JSXElement")]
204    JSXElement(Box<JSXElement>),
205
206    #[tag("JSXFragment")]
207    JSXFragment(JSXFragment),
208}
209
210#[ast_node("JSXText")]
211#[derive(Eq, Hash, EqIgnoreSpan)]
212#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
213pub struct JSXText {
214    pub span: Span,
215    pub value: Atom,
216    pub raw: Atom,
217}
218
219#[cfg(feature = "arbitrary")]
220#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
221impl<'a> arbitrary::Arbitrary<'a> for JSXText {
222    fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
223        let span = u.arbitrary()?;
224        let value = u.arbitrary::<String>()?.into();
225        let raw = u.arbitrary::<String>()?.into();
226
227        Ok(Self { span, value, raw })
228    }
229}
230
231#[ast_node("JSXElement")]
232#[derive(Eq, Hash, EqIgnoreSpan)]
233#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
234#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
235pub struct JSXElement {
236    pub span: Span,
237    pub opening: JSXOpeningElement,
238    pub children: Vec<JSXElementChild>,
239    pub closing: Option<JSXClosingElement>,
240}
241
242impl Take for JSXElement {
243    fn dummy() -> Self {
244        JSXElement {
245            span: DUMMY_SP,
246            opening: Take::dummy(),
247            children: Take::dummy(),
248            closing: Take::dummy(),
249        }
250    }
251}
252
253#[ast_node]
254#[derive(Eq, Hash, EqIgnoreSpan)]
255#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
256#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
257pub enum JSXElementChild {
258    #[tag("JSXText")]
259    JSXText(JSXText),
260
261    #[tag("JSXExpressionContainer")]
262    JSXExprContainer(JSXExprContainer),
263
264    #[tag("JSXSpreadChild")]
265    JSXSpreadChild(JSXSpreadChild),
266
267    #[tag("JSXElement")]
268    JSXElement(Box<JSXElement>),
269
270    #[tag("JSXFragment")]
271    JSXFragment(JSXFragment),
272}
273
274#[ast_node("JSXFragment")]
275#[derive(Eq, Hash, EqIgnoreSpan)]
276#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
277#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
278pub struct JSXFragment {
279    pub span: Span,
280
281    pub opening: JSXOpeningFragment,
282
283    #[cfg_attr(feature = "serde-impl", serde(default))]
284    pub children: Vec<JSXElementChild>,
285
286    pub closing: JSXClosingFragment,
287}
288
289impl Take for JSXFragment {
290    fn dummy() -> Self {
291        JSXFragment {
292            span: DUMMY_SP,
293            opening: Take::dummy(),
294            children: Take::dummy(),
295            closing: Take::dummy(),
296        }
297    }
298}
299
300#[ast_node("JSXOpeningFragment")]
301#[derive(Eq, Hash, Copy, EqIgnoreSpan)]
302#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
303#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
304pub struct JSXOpeningFragment {
305    pub span: Span,
306}
307
308impl Take for JSXOpeningFragment {
309    fn dummy() -> Self {
310        JSXOpeningFragment { span: DUMMY_SP }
311    }
312}
313
314#[ast_node("JSXClosingFragment")]
315#[derive(Eq, Hash, Copy, EqIgnoreSpan)]
316#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
317#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
318pub struct JSXClosingFragment {
319    pub span: Span,
320}
321
322impl Take for JSXClosingFragment {
323    fn dummy() -> Self {
324        JSXClosingFragment { span: DUMMY_SP }
325    }
326}