diff --git a/plugins/swc-plugin-canyon/.gitignore b/plugins/swc-plugin-canyon/.gitignore index 96ef6c0b..92fcb816 100644 --- a/plugins/swc-plugin-canyon/.gitignore +++ b/plugins/swc-plugin-canyon/.gitignore @@ -1,2 +1,3 @@ /target Cargo.lock +swc_plugin_canyon.wasm \ No newline at end of file diff --git a/plugins/swc-plugin-canyon/package.json b/plugins/swc-plugin-canyon/package.json index 42f2b264..65635375 100644 --- a/plugins/swc-plugin-canyon/package.json +++ b/plugins/swc-plugin-canyon/package.json @@ -1,11 +1,14 @@ { "name": "swc-plugin-canyon", - "version": "0.0.2-alpha.8", + "version": "0.0.2-alpha.9", "description": "Canyon SWC plugin, for debugging", "main": "swc_plugin_canyon.wasm", "scripts": { "prepack": "cargo build --release -p swc_plugin_canyon --target wasm32-wasi && cp ../../target/wasm32-wasi/release/swc_plugin_canyon.wasm . && ls && cat package.json" }, + "files": [ + "swc_plugin_canyon.wasm" + ], "devDependencies": { "@swc/cli": "0.4.1-nightly.20240914", "@swc/core": "1.6.13", diff --git a/plugins/swc-plugin-canyon/src/lib.rs b/plugins/swc-plugin-canyon/src/lib.rs index ccdd470b..377c81e2 100644 --- a/plugins/swc-plugin-canyon/src/lib.rs +++ b/plugins/swc-plugin-canyon/src/lib.rs @@ -1,67 +1,75 @@ -#![allow(clippy::not_unsafe_ptr_arg_deref)] - -use swc_common::{Spanned, SyntaxContext}; -use swc_core::plugin::proxies::TransformPluginProgramMetadata; -use swc_ecma_ast::{Program, Script, Expr, ExprStmt, Stmt, Lit, Str, BinExpr, op, Ident}; -use swc_ecma_visit::{as_folder, Fold, FoldWith, VisitMut, VisitMutWith}; -use swc_plugin_macro::plugin_transform; -use swc_core::{ - ecma::{ - transforms::testing::test, - } +use swc_core::ecma::{ + ast::{ + Program, Module, Expr, Stmt, ModuleItem, Ident, Lit, KeyValueProp, Prop, PropName, + ObjectLit, ExprStmt, AssignExpr, AssignOp, MemberExpr, MemberProp, + }, + transforms::testing::test_inline, + visit::{as_folder, FoldWith, VisitMut}, }; +use swc_core::ecma::ast::{AssignTarget, IdentName}; +use swc_core::ecma::visit::VisitMutWith; +use swc_core::plugin::{plugin_transform, proxies::TransformPluginProgramMetadata}; -#[plugin_transform] -fn plugin(program: Program, metadata: TransformPluginProgramMetadata) -> Program { - // 确认插件被调用 - println!("SWC 插件被调用"); +pub struct TransformVisitor { + injected: bool, // 用于确保只注入一次 +} - // 打印文件路径 - if let Some(context) = metadata.get_context(&swc_core::plugin::metadata::TransformPluginMetadataContextKind::Filename) { - println!("当前文件的路径: {}", context); - } else { - println!("无法获取文件路径"); +impl TransformVisitor { + pub fn new() -> Self { + Self { injected: false } } - - // 直接在每个文件末尾插入指定的代码 - program.fold_with(&mut AddSimpleCode) } +impl VisitMut for TransformVisitor { + fn visit_mut_module(&mut self, module: &mut Module) { + // 先调用父类的 visit_mut_module 方法 + module.visit_mut_children_with(self); + + // 在最后一行注入 window.canyon = {name: "zt"}; + if !self.injected { + // 创建 window.canyon 的 MemberExpr + let window_canyon = Expr::Member(MemberExpr { + obj: Box::new(Expr::Ident(Ident::new("window".into(), Default::default(), Default::default()))), + prop: MemberProp::Ident(IdentName::from(Ident::new("__canyon__".into(), Default::default(), Default::default()))), + span: Default::default(), + }); + -struct AddSimpleCode; + // 默认为"",如果没有设置环境变量,则会报错 + let dsn = std::env::var("dsn").unwrap_or_default(); -impl Fold for AddSimpleCode { - fn fold_script(&mut self, mut script: Script) -> Script { - // 插入的代码是 console.log('hi'); - let new_code = Expr::Call(swc_ecma_ast::CallExpr { - callee: swc_ecma_ast::Callee::Expr(Box::new(Expr::Member(swc_ecma_ast::MemberExpr { - obj: Box::new(Expr::Ident(Ident::new("console".into(), Default::default(), SyntaxContext::empty()))), - // prop: Box::new(Expr::Ident(Ident::new("log".into(), Default::default(), SyntaxContext::empty()))), + let object_lit = Expr::Object(ObjectLit { + props: vec![Prop::KeyValue(KeyValueProp { + key: PropName::Ident(IdentName::from(Ident::new("dsn".into(), Default::default(), Default::default()))), + value: Box::new(Expr::Lit(Lit::Str(dsn.into()))), + }).into()], span: Default::default(), - prop: Default::default(), - }))), - args: vec![swc_ecma_ast::ExprOrSpread { - spread: None, - expr: Box::new(Expr::Lit(Lit::Str(Str { - value: "hi".into(), - span: Default::default(), - raw: None, - }))), - }], - span: Default::default(), - type_args: None, - ctxt: Default::default(), - }); + }); - // 构建表达式语句并插入 - let new_item = Stmt::Expr(ExprStmt { - expr: Box::new(new_code), - span: Default::default(), - }); + // 读取当前环境变量,把环境变量的dsn赋值给window.__canyon__.dsn + // 创建 window.canyon = {name: "zt"} 的赋值表达式 + let assign_expr = AssignExpr { + left: AssignTarget::try_from(Box::new(window_canyon)).unwrap(), // 直接使用 Box + op: AssignOp::Assign, + right: Box::new(object_lit), + span: Default::default(), + }; - // 在脚本的末尾追加语句 - script.body.push(new_item); + // 创建表达式语句 + let assign_stmt = Stmt::Expr(ExprStmt { + expr: Box::new(Expr::Assign(assign_expr)), + span: Default::default(), + }); - script + // 将新的语句添加到模块体中 + module.body.push(ModuleItem::Stmt(assign_stmt)); + self.injected = true; // 标记为已注入 + } } } + +/// SWC 插件的主函数 +#[plugin_transform] +pub fn process_transform(program: Program, _metadata: TransformPluginProgramMetadata) -> Program { + program.fold_with(&mut as_folder(TransformVisitor::new())) +} \ No newline at end of file