fix(transformer): correct spans for JSX transform (#3549)

Correct spans in output of React JSX transform, so it should produce correct source maps.

Have copied which AST nodes have spans and which don't from Babel.
This commit is contained in:
overlookmotel 2024-06-06 03:19:47 +00:00
parent e4d74ac3ee
commit 7982b93fb5

View file

@ -429,7 +429,7 @@ enum JSXElementOrFragment<'a, 'b> {
impl<'a, 'b> JSXElementOrFragment<'a, 'b> { impl<'a, 'b> JSXElementOrFragment<'a, 'b> {
fn span(&self) -> Span { fn span(&self) -> Span {
match self { match self {
Self::Element(e) => e.span(), Self::Element(e) => e.span,
Self::Fragment(e) => e.span, Self::Fragment(e) => e.span,
} }
} }
@ -693,7 +693,7 @@ impl<'a> ReactJsx<'a> {
} }
let callee = self.get_create_element(has_key_after_props_spread, need_jsxs, ctx); let callee = self.get_create_element(has_key_after_props_spread, need_jsxs, ctx);
self.ast().call_expression(SPAN, callee, arguments, false, None) self.ast().call_expression(e.span(), callee, arguments, false, None)
} }
fn transform_element_name( fn transform_element_name(
@ -704,9 +704,9 @@ impl<'a> ReactJsx<'a> {
match name { match name {
JSXElementName::Identifier(ident) => { JSXElementName::Identifier(ident) => {
if ident.name == "this" { if ident.name == "this" {
self.ast().this_expression(SPAN) self.ast().this_expression(ident.span)
} else if ident.name.chars().next().is_some_and(|c| c.is_ascii_lowercase()) { } else if ident.name.chars().next().is_some_and(|c| c.is_ascii_lowercase()) {
let string = StringLiteral::new(SPAN, ident.name.clone()); let string = StringLiteral::new(ident.span, ident.name.clone());
self.ast().literal_string_expression(string) self.ast().literal_string_expression(string)
} else { } else {
let ident = get_read_identifier_reference(ident.span, ident.name.clone(), ctx); let ident = get_read_identifier_reference(ident.span, ident.name.clone(), ctx);
@ -716,12 +716,12 @@ impl<'a> ReactJsx<'a> {
JSXElementName::MemberExpression(member_expr) => { JSXElementName::MemberExpression(member_expr) => {
self.transform_jsx_member_expression(member_expr, ctx) self.transform_jsx_member_expression(member_expr, ctx)
} }
JSXElementName::NamespacedName(name) => { JSXElementName::NamespacedName(namespaced) => {
if self.options.throw_if_namespace { if self.options.throw_if_namespace {
self.ctx.error(diagnostics::namespace_does_not_support(name.span)); self.ctx.error(diagnostics::namespace_does_not_support(namespaced.span));
} }
let name = self.ast().new_atom(&name.to_string()); let name = self.ast().new_atom(&namespaced.to_string());
let string_literal = StringLiteral::new(SPAN, name); let string_literal = StringLiteral::new(namespaced.span, name);
self.ast().literal_string_expression(string_literal) self.ast().literal_string_expression(string_literal)
} }
} }
@ -786,7 +786,7 @@ impl<'a> ReactJsx<'a> {
let object = match &expr.object { let object = match &expr.object {
JSXMemberExpressionObject::Identifier(ident) => { JSXMemberExpressionObject::Identifier(ident) => {
if ident.name == "this" { if ident.name == "this" {
self.ast().this_expression(SPAN) self.ast().this_expression(ident.span)
} else { } else {
let ident = get_read_identifier_reference(ident.span, ident.name.clone(), ctx); let ident = get_read_identifier_reference(ident.span, ident.name.clone(), ctx);
self.ast().identifier_reference_expression(ident) self.ast().identifier_reference_expression(ident)
@ -796,8 +796,8 @@ impl<'a> ReactJsx<'a> {
self.transform_jsx_member_expression(expr, ctx) self.transform_jsx_member_expression(expr, ctx)
} }
}; };
let property = IdentifierName::new(SPAN, expr.property.name.clone()); let property = IdentifierName::new(expr.property.span, expr.property.name.clone());
self.ast().static_member_expression(SPAN, object, property, false) self.ast().static_member_expression(expr.span, object, property, false)
} }
fn transform_jsx_attribute_item( fn transform_jsx_attribute_item(
@ -811,8 +811,9 @@ impl<'a> ReactJsx<'a> {
let kind = PropertyKind::Init; let kind = PropertyKind::Init;
let key = self.get_attribute_name(&attr.name); let key = self.get_attribute_name(&attr.name);
let value = self.transform_jsx_attribute_value(attr.value.as_ref(), ctx); let value = self.transform_jsx_attribute_value(attr.value.as_ref(), ctx);
let object_property = let object_property = self
self.ast().object_property(SPAN, kind, key, value, None, false, false, false); .ast()
.object_property(attr.span, kind, key, value, None, false, false, false);
let object_property = ObjectPropertyKind::ObjectProperty(object_property); let object_property = ObjectPropertyKind::ObjectProperty(object_property);
properties.push(object_property); properties.push(object_property);
} }
@ -822,7 +823,7 @@ impl<'a> ReactJsx<'a> {
} }
expr => { expr => {
let argument = self.ast().copy(expr); let argument = self.ast().copy(expr);
let spread_property = self.ast().spread_element(SPAN, argument); let spread_property = self.ast().spread_element(attr.span, argument);
let object_property = ObjectPropertyKind::SpreadProperty(spread_property); let object_property = ObjectPropertyKind::SpreadProperty(spread_property);
properties.push(object_property); properties.push(object_property);
} }
@ -849,8 +850,8 @@ impl<'a> ReactJsx<'a> {
} }
Some(JSXAttributeValue::ExpressionContainer(c)) => match &c.expression { Some(JSXAttributeValue::ExpressionContainer(c)) => match &c.expression {
e @ match_expression!(JSXExpression) => self.ast().copy(e.to_expression()), e @ match_expression!(JSXExpression) => self.ast().copy(e.to_expression()),
JSXExpression::EmptyExpression(_e) => { JSXExpression::EmptyExpression(e) => {
self.ast().literal_boolean_expression(BooleanLiteral::new(SPAN, true)) self.ast().literal_boolean_expression(BooleanLiteral::new(e.span, true))
} }
}, },
None => self.ast().literal_boolean_expression(BooleanLiteral::new(SPAN, true)), None => self.ast().literal_boolean_expression(BooleanLiteral::new(SPAN, true)),
@ -863,7 +864,7 @@ impl<'a> ReactJsx<'a> {
ctx: &mut TraverseCtx<'a>, ctx: &mut TraverseCtx<'a>,
) -> Option<Expression<'a>> { ) -> Option<Expression<'a>> {
match child { match child {
JSXChild::Text(text) => self.transform_jsx_text(text.value.as_str()), JSXChild::Text(text) => self.transform_jsx_text(text),
JSXChild::ExpressionContainer(e) => match &e.expression { JSXChild::ExpressionContainer(e) => match &e.expression {
e @ match_expression!(JSXExpression) => Some(self.ast().copy(e.to_expression())), e @ match_expression!(JSXExpression) => Some(self.ast().copy(e.to_expression())),
JSXExpression::EmptyExpression(_) => None, JSXExpression::EmptyExpression(_) => None,
@ -886,23 +887,25 @@ impl<'a> ReactJsx<'a> {
JSXAttributeName::Identifier(ident) => { JSXAttributeName::Identifier(ident) => {
let name = ident.name.clone(); let name = ident.name.clone();
if ident.name.contains('-') { if ident.name.contains('-') {
let expr = self.ast().literal_string_expression(StringLiteral::new(SPAN, name)); let expr =
self.ast().literal_string_expression(StringLiteral::new(ident.span, name));
self.ast().property_key_expression(expr) self.ast().property_key_expression(expr)
} else { } else {
self.ast().property_key_identifier(IdentifierName::new(SPAN, name)) self.ast().property_key_identifier(IdentifierName::new(ident.span, name))
} }
} }
JSXAttributeName::NamespacedName(name) => { JSXAttributeName::NamespacedName(namespaced) => {
let name = self.ast().new_atom(&name.to_string()); let name = self.ast().new_atom(&namespaced.to_string());
let expr = self.ast().literal_string_expression(StringLiteral::new(SPAN, name)); let expr =
self.ast().literal_string_expression(StringLiteral::new(namespaced.span, name));
self.ast().property_key_expression(expr) self.ast().property_key_expression(expr)
} }
} }
} }
fn transform_jsx_text(&self, text: &str) -> Option<Expression<'a>> { fn transform_jsx_text(&self, text: &JSXText<'a>) -> Option<Expression<'a>> {
Self::fixup_whitespace_and_decode_entities(text).map(|s| { Self::fixup_whitespace_and_decode_entities(text.value.as_str()).map(|s| {
let s = StringLiteral::new(SPAN, self.ast().new_atom(&s)); let s = StringLiteral::new(text.span, self.ast().new_atom(&s));
self.ast().literal_string_expression(s) self.ast().literal_string_expression(s)
}) })
} }