problem when writing a swc plugin with rust

99 Views Asked by At

I am writing a swc plugin to transform tsx. And I want to replace 'props' to '$$props' in spreadElement. It seems trouble to solve. I have no way to replace it. The swc document can check in https://rustdoc.swc.rs/swc_ecma_visit/trait.VisitMut.html How can I do? Here is my code, and the test case is in the bottom of the code.

use std::borrow::Cow;

use swc_core::{ecma::{ast::{Program, Expr, JSXElement}, visit::as_folder, parser::{Syntax, TsConfig}}, plugin::{proxies::TransformPluginProgramMetadata, plugin_transform}, common::comments::Comments};

use swc_core::ecma::{
    transforms::testing::test,
    visit::{FoldWith, VisitMut, VisitMutWith, Fold},
    ast::*,
    atoms::JsWord,
};
pub struct TransformVisitor;




impl VisitMut for TransformVisitor {
    fn visit_mut_expr(&mut self, e: &mut Expr) {
        e.visit_mut_children_with(self);
    }
    fn visit_mut_jsx_element(&mut self, e: &mut swc_core::ecma::ast::JSXElement) {
        e.visit_mut_children_with(self);
        println!("Ident: {:?}", e.opening.attrs);
        
        if e.opening.attrs.len() > 0 {
            let mut new_attrs = vec![];
            for attr in e.opening.attrs.iter() {
                let mut new_attr = attr.clone();
                if let JSXAttrOrSpread::JSXAttr(attr) = &attr {
                    println!("attr new: {:?}", attr.name);
                    if let JSXAttrName::Ident(Ident { sym, .. }) = &attr.name {
                        if sym == "props" {
                            println!("props: {}", sym);
                            // new_attr.name = JSXAttrName::Ident(Ident::new("$$props".into(), attr.name.span));
                        }
                    }
                } else if let JSXAttrOrSpread::SpreadElement(SpreadElement { expr, dot3_token, .. }) = &attr {
                    println!("attr new spread: {:?}", expr);
                    let mut new_expr = expr.clone();

                    // replace props to $$props
                    if let Expr::Object(ObjectLit { props, span, .. }) = &**expr {
                        println!("attr new spread props: {:?}", props);
                        let mut new_props = props.clone();
                        for j in 0..props.len() {
                            if let PropOrSpread::Prop(prop) = &props[j] {
                                if let Prop::KeyValue(KeyValueProp { key: PropName::Ident(Ident { sym, span, .. }), value }) = &**prop {
                                        if sym == "props" {
                                            println!("attr new spread props sym: {}", sym);
                                            // please help me to replace props to $$props
                                            new_props[j] = PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
                                                key: PropName::Ident(Ident::new("$$props".into(), span.clone())),
                                                value: value.clone(),
                                            })));
                                            

                                        }
                                }
                            }
                        }
                        println!("attr new spread props new_props: {:?}", new_props);
                        new_expr = Box::new(Expr::Object(ObjectLit { props: new_props, span: span.clone() }));
                    }
                    new_attr = JSXAttrOrSpread::SpreadElement(SpreadElement { expr: new_expr, dot3_token: dot3_token.clone() });
        
                }
                new_attrs.push(new_attr);
            }
            e.opening.attrs = new_attrs;
          }

    }
}


/// An example plugin function with macro support.
/// `plugin_transform` macro interop pointers into deserialized structs, as well
/// as returning ptr back to host.
///
/// It is possible to opt out from macro by writing transform fn manually
/// if plugin need to handle low-level ptr directly via
/// `__transform_plugin_process_impl(
///     ast_ptr: *const u8, ast_ptr_len: i32,
///     unresolved_mark: u32, should_enable_comments_proxy: i32) ->
///     i32 /*  0 for success, fail otherwise.
///             Note this is only for internal pointer interop result,
///             not actual transform result */`
///
/// This requires manual handling of serialization / deserialization from ptrs.
/// Refer swc_plugin_macro to see how does it work internally.
#[plugin_transform]
pub fn my_plugin(program: Program, _metadata: TransformPluginProgramMetadata) -> Program {
    program.fold_with(&mut as_folder(TransformVisitor))
}

// An example to test plugin transform.
// Recommended strategy to test plugin's transform is verify
// the Visitor's behavior, instead of trying to run `process_transform` with mocks
// unless explicitly required to do so.
test!(
    Syntax::Typescript(TsConfig {
        tsx: true,
        ..Default::default()
    }),
    |_| as_folder(TransformVisitor),
    boo,
    r#"<comp a="2" props={11} { ...{props: { a: 1 }} }></comp>"#,
    r#"<comp a="2" props={11} { ...{props: { a: 1 }} }></comp>"#
);

replace 'props' to '$$props' in spreadElement

0

There are 0 best solutions below