Skip to content

Commit

Permalink
fix: correct generate this expr
Browse files Browse the repository at this point in the history
  • Loading branch information
IWANABETHATGUY committed Dec 3, 2024
1 parent 521df42 commit db63e45
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 25 deletions.
105 changes: 82 additions & 23 deletions crates/oxc_transformer/src/jsx/jsx_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,8 +314,7 @@ fn get_import_source(jsx_runtime_importer: &str, react_importer_len: u32) -> Ato

/// Pragma used in classic mode
struct Pragma<'a> {
object: Atom<'a>,
properties: Vec<Atom<'a>>,
ident_parts: Vec<Atom<'a>>,
}

impl<'a> Pragma<'a> {
Expand All @@ -329,16 +328,12 @@ impl<'a> Pragma<'a> {
ctx: &TransformCtx<'a>,
) -> Self {
if let Some(pragma) = pragma {
let mut parts = pragma.split('.');

let object_name = parts.next().unwrap();
if object_name.is_empty() {
if pragma.is_empty() {
return Self::invalid(default_property_name, ctx);
}
let props = parts.map(|item| ast.atom(item)).collect();

let object = ast.atom(object_name);
Self { object, properties: props }
let ident_parts = pragma.split('.').map(|item| ast.atom(item)).collect::<Vec<_>>();
Self { ident_parts }
} else {
Self::default(default_property_name)
}
Expand All @@ -350,23 +345,30 @@ impl<'a> Pragma<'a> {
}

fn default(default_property_name: &'static str) -> Self {
Self { object: Atom::from("React"), properties: vec![Atom::from(default_property_name)] }
Self { ident_parts: vec![Atom::from("React"), Atom::from(default_property_name)] }
}

fn create_expression(&self, ctx: &mut TraverseCtx<'a>) -> Expression<'a> {
let object = get_read_identifier_reference(SPAN, self.object.clone(), ctx);
Self::create_arbitrary_length_member_expr_or_ident(object, &self.properties, ctx)
}

/// create a static member expression without caring about the referenceId,
/// this function is always used to creat a tail part of a real member expression
fn create_arbitrary_length_member_expr_or_ident(
object: IdentifierReference<'a>,
list: &[Atom<'a>],
ctx: &mut TraverseCtx<'a>,
) -> Expression<'a> {
let mut expr = Expression::Identifier(ctx.alloc(object));
for item in list {
let (mut expr, parts) = match &self.ident_parts[..] {
[] => unreachable!(),
[atom, _rest @ ..] if atom == "this" => {
(ctx.ast.expression_this(SPAN), Box::new(&self.ident_parts[1..]))
}
[first, second, _rest @ ..] if first == "import" && second == "meta" => (
ctx.ast.expression_meta_property(
SPAN,
ctx.ast.identifier_name(SPAN, first),
ctx.ast.identifier_name(SPAN, second),
),
Box::new(&self.ident_parts[2..]),
),
[first, rest @ ..] => {
let object = get_read_identifier_reference(SPAN, first.clone(), ctx);
let expr = Expression::Identifier(ctx.alloc(object));
(expr, Box::new(rest))
}
};
for item in parts.iter() {
let name = ctx.ast.identifier_name(SPAN, item.clone());
expr = ctx.ast.member_expression_static(SPAN, expr, name, false).into();
}
Expand Down Expand Up @@ -1067,3 +1069,60 @@ fn create_static_member_expression<'a>(
fn has_proto(e: &ObjectExpression<'_>) -> bool {
e.properties.iter().any(|p| p.prop_name().is_some_and(|name| name.0 == "__proto__"))
}

#[cfg(test)]
mod test {
use std::path::Path;

use oxc_allocator::Allocator;
use oxc_ast::{ast::Expression, AstBuilder};
use oxc_semantic::{ScopeTree, SymbolTable};
use oxc_traverse::ReusableTraverseCtx;

use crate::{context::TransformCtx, TransformOptions};

use super::Pragma;

#[test]
fn this_expr_pragma() {
let alloc = Allocator::default();
let ast = AstBuilder::new(&alloc);
let ctx = TransformCtx::new(Path::new("test.jsx"), &TransformOptions::default());
// SAFETY: constructed to avoid unsoundness
let mut traverse_ctx = unsafe {
ReusableTraverseCtx::new(ScopeTree::default(), SymbolTable::default(), &alloc).unwrap()
};
let pragma = Pragma::parse(Some(&"this.a.b".to_string()), "createElement", ast, &ctx);

let expr = pragma.create_expression(&mut traverse_ctx);
let member_expr = expr.as_member_expression().unwrap();
assert_eq!(member_expr.static_property_name(), Some("b"));
let object = member_expr.object().as_member_expression().unwrap();
assert_eq!(object.static_property_name(), Some("a"));
match object.object() {
Expression::ThisExpression(_) => {}
_ => panic!("Expected ThisExpression"),
}
}

#[test]
fn import_meta() {
let alloc = Allocator::default();
let ast = AstBuilder::new(&alloc);
let ctx = TransformCtx::new(Path::new("test.jsx"), &TransformOptions::default());
// SAFETY: constructed to avoid unsoundness
let mut traverse_ctx = unsafe {
ReusableTraverseCtx::new(ScopeTree::default(), SymbolTable::default(), &alloc).unwrap()
};
let pragma =
Pragma::parse(Some(&"import.meta.prop".to_string()), "createElement", ast, &ctx);

let expr = pragma.create_expression(&mut traverse_ctx);
let member_expr = expr.as_member_expression().unwrap();
assert_eq!(member_expr.static_property_name(), Some("prop"));
match member_expr.object() {
Expression::MetaProperty(_) => {}
_ => panic!("Expected ThisExpression"),
}
}
}
4 changes: 2 additions & 2 deletions tasks/transform_conformance/snapshots/oxc.snap.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
commit: 54a8389f

Passed: 91/102
Passed: 93/104

# All Passed:
* babel-plugin-transform-class-static-block
Expand Down Expand Up @@ -170,7 +170,7 @@ rebuilt : SymbolId(2): []
x Output mismatch


# babel-plugin-transform-react-jsx (32/35)
# babel-plugin-transform-react-jsx (34/37)
* refresh/does-not-transform-it-because-it-is-not-used-in-the-AST/input.jsx
x Output mismatch

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<test></test>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"plugins": [
[
"transform-react-jsx",
{
"runtime": "classic",
"pragma": "import.meta.a"
}
]
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import.meta.a("test", null);
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<test></test>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"plugins": [
[
"transform-react-jsx",
{
"runtime": "classic",
"pragma": "this.a"
}
]
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
this.a("test", null);

0 comments on commit db63e45

Please sign in to comment.