基于SWC Rust插件注入代码注释的实现与测试问题
在SWC中为AST添加注释并优化测试代码的方案
问题背景
之前在Babel里可以直接用addComment操作AST节点添加注释,比如把:
console.log`Hello, ${name}!`;
转换成:
/*#__PURE__*/console.log("Hello, ", name, "!");
但切换到Rust的SWC后,受内存所有权规则和性能优化限制,必须用PluginCommentsProxy来添加注释。用swc_core::ecma::transforms::testing做测试时,发现tester.comments的类型是Rc<SingleThreadedComments>,导致测试跑不通。虽然可以用泛型<C>适配,但不想为了测试加泛型降低代码可读性,想找更优的解决办法。
优化方案:不依赖泛型的测试写法
你可以手动处理注释实例,不用给测试函数加泛型。核心是创建SingleThreadedComments实例并包装成Rc,替换测试上下文的注释对象,同时保证注释能正确关联AST节点。
具体实现代码
use swc_core::ecma::transforms::testing::{test, FixtureTestConfig}; use swc_core::ecma::comments::{SingleThreadedComments, Comments}; use swc_core::common::Rc; use swc_core::ecma::ast::Program; use swc_core::ecma::visit::FoldWith; // 你的注释注入转换逻辑 fn add_pure_comment_transform(program: Program, comments: Rc<SingleThreadedComments>) -> Program { // 创建PluginCommentsProxy用于操作注释 let proxy = swc_core::plugin::proxy::PluginCommentsProxy::new(comments.clone()); // 这里编写你的AST遍历逻辑,给目标节点添加注释 // 示例:找到所有CallExpr节点,添加/*#__PURE__*/注释 program.fold_with(&mut your_custom_transformer(proxy)) } #[test] fn test_add_pure_comment() { // 创建注释实例并包装为Rc let comments = Rc::new(SingleThreadedComments::default()); test( FixtureTestConfig::default(), |mut context| { // 替换测试上下文的comments为我们创建的实例 context.comments = comments.clone(); Box::new(|program| add_pure_comment_transform(program, comments.clone())) }, // 替换为你的测试用例路径或内联测试逻辑 "tests/fixtures/add-pure-comment", ); }
关键注意点
- 手动创建
SingleThreadedComments并通过Rc包装,直接替换测试上下文的comments字段,完全不需要泛型参数。 - 转换函数直接接收
Rc<SingleThreadedComments>,用来创建PluginCommentsProxy,避免泛型带来的代码复杂度。 - 借助
Rc的克隆特性,确保注释实例在测试上下文和转换逻辑中共享,符合SWC的内存管理规则。
进一步简化:封装测试辅助函数
如果有多个测试用例,可以把注释实例的创建和上下文替换逻辑封装成辅助函数,让测试代码更简洁:
fn create_test_with_comments<F>(transformer: F) -> impl Fn(FixtureTestConfig) -> Box<dyn Fn(Program) -> Program> where F: Fn(Program, Rc<SingleThreadedComments>) -> Program + 'static, { move |mut config| { let comments = Rc::new(SingleThreadedComments::default()); config.comments = comments.clone(); Box::new(move |program| transformer(program, comments.clone())) } } // 使用辅助函数编写测试 #[test] fn test_add_pure_comment_simplified() { test( FixtureTestConfig::default(), create_test_with_comments(|program, comments| { add_pure_comment_transform(program, comments) }), "tests/fixtures/add-pure-comment", ); }
这样既避开了泛型,又能保持测试代码的清爽可读。
内容的提问来源于stack exchange,提问作者jantimon
相关产品推荐
相关产品推荐

