1use oxc_allocator::Allocator;
6use oxc_ast::ast::*;
7use oxc_ast::{AstBuilder, NONE};
8use oxc_span::{Atom, SPAN};
9
10pub struct JsxBuilder<'a> {
14 ast: AstBuilder<'a>,
15}
16
17impl<'a> JsxBuilder<'a> {
18 pub fn new(alloc: &'a Allocator) -> Self {
20 Self {
21 ast: AstBuilder::new(alloc),
22 }
23 }
24
25 pub fn ast(&self) -> &AstBuilder<'a> {
27 &self.ast
28 }
29
30 pub fn element(
44 &self,
45 name: impl Into<Atom<'a>>,
46 attributes: Vec<JSXAttributeItem<'a>>,
47 children: Vec<JSXChild<'a>>,
48 self_closing: bool,
49 ) -> JSXElement<'a> {
50 let name_atom = name.into();
51
52 let opening_ident = self.ast.jsx_identifier(SPAN, name_atom);
54 let opening_name = JSXElementName::Identifier(self.ast.alloc(opening_ident));
55
56 let attrs_vec = self.ast.vec_from_iter(attributes);
57
58 let opening_element = self
61 .ast
62 .jsx_opening_element(SPAN, opening_name, NONE, attrs_vec);
63
64 let closing_element: Option<JSXClosingElement> = if self_closing {
66 None
67 } else {
68 let closing_ident = self.ast.jsx_identifier(SPAN, name_atom);
69 let closing_name = JSXElementName::Identifier(self.ast.alloc(closing_ident));
70 Some(self.closing_element(closing_name))
71 };
72
73 let children_vec = self.ast.vec_from_iter(children);
74 self.ast.jsx_element(
75 SPAN,
76 opening_element,
77 children_vec,
78 closing_element.map(|e| self.ast.alloc(e)),
79 )
80 }
81
82 fn closing_element(&self, name: JSXElementName<'a>) -> JSXClosingElement<'a> {
84 JSXClosingElement { span: SPAN, name }
85 }
86
87 pub fn attr(
89 &self,
90 name: impl Into<Atom<'a>>,
91 value: Option<JSXAttributeValue<'a>>,
92 ) -> JSXAttributeItem<'a> {
93 let attr_name = self.ast.jsx_attribute_name_identifier(SPAN, name);
94 let attr = self.ast.jsx_attribute(SPAN, attr_name, value);
95 JSXAttributeItem::Attribute(self.ast.alloc(attr))
96 }
97
98 pub fn string_attr(&self, value: impl Into<Atom<'a>>) -> JSXAttributeValue<'a> {
100 JSXAttributeValue::StringLiteral(self.ast.alloc(self.ast.string_literal(SPAN, value, None)))
101 }
102
103 pub fn expr_attr(&self, expr: Expression<'a>) -> JSXAttributeValue<'a> {
105 JSXAttributeValue::ExpressionContainer(self.ast.alloc(JSXExpressionContainer {
106 span: SPAN,
107 expression: JSXExpression::from(expr),
108 }))
109 }
110
111 pub fn text(&self, value: impl Into<Atom<'a>>) -> JSXChild<'a> {
113 let value_atom = value.into();
114 let text = self.ast.jsx_text(SPAN, value_atom, Some(value_atom));
115 JSXChild::Text(self.ast.alloc(text))
116 }
117
118 pub fn child(&self, element: JSXElement<'a>) -> JSXChild<'a> {
120 JSXChild::Element(self.ast.alloc(element))
121 }
122
123 pub fn expr_child(&self, expr: Expression<'a>) -> JSXChild<'a> {
125 JSXChild::ExpressionContainer(self.ast.alloc(JSXExpressionContainer {
126 span: SPAN,
127 expression: JSXExpression::from(expr),
128 }))
129 }
130
131 pub fn fragment(&self, children: Vec<JSXChild<'a>>) -> JSXFragment<'a> {
133 JSXFragment {
134 span: SPAN,
135 opening_fragment: JSXOpeningFragment { span: SPAN },
136 closing_fragment: JSXClosingFragment { span: SPAN },
137 children: self.ast.vec_from_iter(children),
138 }
139 }
140
141 pub fn jsx_expr(&self, element: JSXElement<'a>) -> Expression<'a> {
143 Expression::JSXElement(self.ast.alloc(element))
144 }
145
146 pub fn jsx_fragment_expr(&self, fragment: JSXFragment<'a>) -> Expression<'a> {
148 Expression::JSXFragment(self.ast.alloc(fragment))
149 }
150}