Rust ECMAScript转换插件库swc_ecma_ext_transforms的使用:高性能JavaScript/TypeScript代码转换与语法树操作

Rust ECMAScript转换插件库swc_ecma_ext_transforms的使用:高性能JavaScript/TypeScript代码转换与语法树操作

安装 运行以下Cargo命令在您的项目目录中:

cargo add swc_ecma_ext_transforms

或者将以下行添加到您的Cargo.toml中:

swc_ecma_ext_transforms = “21.0.0”

元数据

  • 版本:21.0.0
  • 发布时间:6天前
  • 版本:2021 edition
  • 许可证:Apache-2.0
  • 大小:8.26 KiB

文档 rustdoc.swc.rs/swc_ecma_ext_transforms

仓库 github.com/swc-project/swc

所有者

  • Donny/강동윤
  • SWC Bot

完整示例代码:

use swc_common::chain;
use swc_ecma_ext_transforms::{
    compat::{es2015::regenerator, es2022::class_properties},
    optimization::simplify,
    proposal::decorators,
};
use swc_ecma_parser::{EsConfig, Syntax};
use swc_ecma_transforms::{
    helpers::{self, Helpers},
    pass::Optional,
};
use swc_ecma_visit::Fold;

// 创建转换器链
fn create_transforms() -> impl Fold {
    chain!(
        // ES2015 regenerator转换
        Optional::new(regenerator(), true),
        // ES2022类属性转换
        Optional::new(class_properties(class_properties::Config::default()), true),
        // 装饰器提案转换
        Optional::new(decorators(decorators::Config::default()), true),
        // 代码简化优化
        Optional::new(simplify(), true)
    )
}

// 配置解析器语法
fn get_syntax() -> Syntax {
    Syntax::Es(EsConfig {
        jsx: false,
        decorators: true,
        decorators_before_export: true,
        ..Default::default()
    })
}

// 配置助手函数
fn get_helpers() -> Helpers {
    Helpers::new(false)
}

fn main() {
    // 初始化转换器
    let transforms = create_transforms();
    
    // 示例JavaScript/TypeScript代码
    let code = r#"
        @decorator
        class Example {
            #privateField = 'value';
            
            @methodDecorator
            method() {
                return function* generator() {
                    yield 42;
                };
            }
        }
    "#;
    
    // 在这里可以使用swc的解析器和转换器处理代码
    println!("使用swc_ecma_ext_transforms进行代码转换");
}

完整示例demo:

use swc_common::{chain, comments::SingleThreadedComments, sync::Lrc, FileName, Globals, Mark, SourceMap};
use swc_ecma_codegen::text_writer::JsWriter;
use swc_ecma_ext_transforms::{
    compat::{es2015::regenerator, es2022::class_properties},
    optimization::simplify,
    proposal::decorators,
};
use swc_ecma_parser::{parse_file_as_module, EsConfig, Syntax};
use swc_ecma_transforms::{
    helpers::{self, Helpers},
    pass::Optional,
};
use swc_ecma_visit::Fold;
use std::io::Cursor;

// 创建转换器链
fn create_transforms() -> impl Fold {
    chain!(
        // ES2015 regenerator转换
        Optional::new(regenerator(), true),
        // ES2022类属性转换
        Optional::new(class_properties(class_properties::Config::default()), true),
        // 装饰器提案转换
        Optional::new(decorators(decorators::Config::default()), true),
        // 代码简化优化
        Optional::new(simplify(), true)
    )
}

// 配置解析器语法
fn get_syntax() -> Syntax {
    Syntax::Es(EsConfig {
        jsx: false,
        decorators: true,
        decorators_before_export: true,
        ..Default::default()
    })
}

// 配置助手函数
fn get_helpers() -> Helpers {
    Helpers::new(false)
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 初始化源码映射和全局变量
    let cm = Lrc::new(SourceMap::default());
    let globals = Globals::new();
    
    // 初始化转换器
    let transforms = create_transforms();
    
    // 示例JavaScript/TypeScript代码
    let code = r#"
        @decorator
        class Example {
            #privateField = 'value';
            
            @methodDecorator
            method() {
                return function* generator() {
                    yield 42;
                };
            }
        }
    "#;
    
    // 创建文件名
    let fm = cm.new_source_file(FileName::Anon, code.into());
    
    // 解析代码为AST
    let mut parser = parse_file_as_module(
        &fm,
        get_syntax(),
        Default::default(),
        None,
        &mut vec![],
    )?;
    
    // 应用转换
    let helpers = get_helpers();
    let module = helpers.build(&mut parser.module);
    let transformed_module = transforms.fold_module(module);
    
    // 生成转换后的代码
    let mut buf = Vec::new();
    {
        let writer = Box::new(JsWriter::new(cm.clone(), "\n", &mut buf, None));
        let mut emitter = swc_ecma_codegen::Emitter {
            cfg: Default::default(),
            cm: cm.clone(),
            comments: None,
            wr: writer,
        };
        
        emitter.emit_module(&transformed_module)?;
    }
    
    // 输出转换结果
    let result = String::from_utf8(buf)?;
    println!("转换前代码:");
    println!("{}", code);
    println!("\n转换后代码:");
    println!("{}", result);
    
    Ok(())
}

1 回复

Rust ECMAScript转换插件库swc_ecma_ext_transforms使用指南

概述

swc_ecma_ext_transforms是SWC(Speedy Web Compiler)生态系统中的一个核心库,专门用于对JavaScript和TypeScript代码进行高性能的语法树转换操作。该库提供了丰富的AST操作API,支持代码优化、语法降级、代码转换等场景。

主要特性

  • 高性能的ECMAScript语法树转换
  • 完整的JavaScript/TypeScript语法支持
  • 插件化的转换器架构
  • 线程安全的API设计
  • 丰富的内置转换器集合

安装方法

在Cargo.toml中添加依赖:

[dependencies]
swc_ecma_ext_transforms = "0.90"
swc_ecma_parser = "0.90"
swc_ecma_ast = "0.90"

基本使用方法

1. 创建转换器

use swc_ecma_ext_transforms::*;
use swc_ecma_parser::{Parser, StringInput, Syntax};
use swc_ecma_ast::*;

// 创建转换器配置
let config = Config::default();

2. 解析和转换代码

fn transform_code(input: &str) -> String {
    let mut errors = vec![];
    
    // 解析代码为AST
    let mut parser = Parser::new(
        Syntax::Es(Default::default()),
        StringInput::new(input, Default::default(), Default::default()),
        None,
    );
    
    let module = parser.parse_module().unwrap();
    
    // 应用转换
    let mut transformer = swc_ecma_ext_transforms::transforms::resolver();
    let transformed = transformer.transform_module(module);
    
    // 将AST转换回代码
    let mut output = vec![];
    let mut emitter = swc_ecma_codegen::Emitter {
        cfg: Default::default(),
        cm: Default::default(),
        wr: Box::new(swc_ecma_codegen::text_writer::JsWriter::new(
            Default::default(),
            "\n",
            &mut output,
            None,
        )),
    };
    
    emitter.emit_module(&transformed).unwrap();
    String::from_utf8(output).unwrap()
}

3. 使用内置转换器示例

use swc_ecma_ext_transforms::transforms::*;

// 箭头函数转换
let arrow_config = arrow::Config { 
    spec: true 
};
let arrow_transformer = arrow(arrow_config);

// 类属性转换
let class_props_config = class_properties::Config {
    loose: false,
    set_public_fields: true,
};
let class_props_transformer = class_properties(class_props_config);

// 可选链操作符转换
let optional_chaining_config = optional_chaining::Config {
    no_document_all: false,
    pure_getter: false,
};
let optional_chaining_transformer = optional_chaining(optional_chaining_config);

完整示例

use swc_ecma_ext_transforms::*;
use swc_ecma_parser::{Parser, StringInput, Syntax};
use swc_ecma_ast::*;
use swc_ecma_visit::VisitMutWith;

fn main() {
    let code = r#"
        const greet = (name) => `Hello, ${name}!`;
        class Person {
            #privateField = 42;
            method() {
                return this.#privateField;
            }
        }
    "#;
    
    // 解析
    let mut parser = Parser::new(
        Syntax::Es(Default::default()),
        StringInput::new(code, 0.into(), code.len().into()),
        None,
    );
    
    let mut module = parser.parse_module().unwrap();
    
    // 应用多个转换器
    let transformers: Vec<Box<dyn VisitMut>> = vec![
        Box::new(arrow(arrow::Config { spec: true })),
        Box::new(class_properties(class_properties::Config {
            loose: false,
            set_public_fields: true,
        })),
        Box::new(private_in_object(private_in_object::Config {
            pure_getter: false,
        })),
    ];
    
    for transformer in transformers {
        module.visit_mut_with(&mut *transformer);
    }
    
    println!("转换完成");
}

自定义转换器

use swc_ecma_visit::{VisitMut, VisitMutWith};
use swc_ecma_ast::*;

struct MyCustomTransformer;

impl VisitMut for MyCustomTransformer {
    fn visit_mut_expr(&mut self, expr: &mut Expr) {
        // 自定义转换逻辑
        if let Expr::Ident(ident) = expr {
            if ident.sym == "oldName" {
                *expr = Expr::Ident(Ident::new("newName".into(), ident.span));
            }
        }
        expr.visit_mut_children_with(self);
    }
}

// 使用自定义转换器
let mut custom_transformer = MyCustomTransformer;
module.visit_mut_with(&mut custom_transformer);

性能建议

  1. 批量处理:尽可能批量处理多个文件
  2. 复用解析器:在循环中复用Parser实例
  3. 选择性转换:只应用必要的转换器
  4. 并行处理:利用Rust的并发特性处理多个文件

注意事项

  • 确保正确处理错误和panic
  • 注意AST节点的所有权和生命周期
  • 在生产环境中添加适当的错误处理
  • 考虑内存使用情况,特别是在处理大型文件时

这个库为JavaScript/TypeScript代码转换提供了强大而灵活的工具集,特别适合构建编译器、代码转换工具和静态分析工具。

完整示例代码

use swc_ecma_ext_transforms::*;
use swc_ecma_parser::{Parser, StringInput, Syntax};
use swc_ecma_ast::*;
use swc_ecma_visit::VisitMutWith;
use swc_ecma_codegen::{Emitter, text_writer::JsWriter};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 输入代码示例
    let code = r#"
        // 箭头函数示例
        const add = (a, b) => a + b;
        
        // 类私有字段示例
        class Calculator {
            #result = 0;
            
            add(x) {
                this.#result += x;
                return this;
            }
            
            getResult() {
                return this.#result;
            }
        }
        
        // 可选链操作符示例
        const obj = { prop: { nested: 'value' } };
        const value = obj.prop?.nested;
    "#;
    
    println!("原始代码:");
    println!("{}", code);
    
    // 解析代码为AST
    let mut parser = Parser::new(
        Syntax::Es(Default::default()), // 使用ES语法
        StringInput::new(code, 0.into(), code.len().into()), // 字符串输入
        None, // 无注释
    );
    
    let mut module = parser.parse_module()
        .map_err(|e| format!("解析错误: {:?}", e))?;
    
    println!("\n开始应用转换器...");
    
    // 创建转换器配置
    let arrow_config = arrow::Config { spec: true };
    let class_props_config = class_properties::Config {
        loose: false,
        set_public_fields: true,
    };
    let optional_chaining_config = optional_chaining::Config {
        no_document_all: false,
        pure_getter: false,
    };
    
    // 应用多个转换器
    let transformers: Vec<Box<dyn VisitMut>> = vec![
        Box::new(arrow(arrow_config)), // 箭头函数转换
        Box::new(class_properties(class_props_config)), // 类属性转换
        Box::new(optional_chaining(optional_chaining_config)), // 可选链转换
    ];
    
    // 依次应用所有转换器
    for mut transformer in transformers {
        module.visit_mut_with(&mut *transformer);
    }
    
    println!("转换完成!");
    
    // 将转换后的AST重新生成为代码字符串
    let mut output = Vec::new();
    {
        let writer = JsWriter::new(
            Default::default(), // Source map配置
            "\n", // 换行符
            &mut output, // 输出缓冲区
            None, // 可选源映射
        );
        
        let mut emitter = Emitter {
            cfg: Default::default(), // 发射器配置
            cm: Default::default(), // 源代码管理器
            wr: Box::new(writer), // 写入器
        };
        
        emitter.emit_module(&module)?;
    }
    
    let transformed_code = String::from_utf8(output)?;
    
    println!("\n转换后的代码:");
    println!("{}", transformed_code);
    
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_basic_transformation() {
        let code = "const fn = () => {};";
        let result = transform_code(code);
        assert!(result.contains("function"));
    }
    
    fn transform_code(input: &str) -> String {
        let mut parser = Parser::new(
            Syntax::Es(Default::default()),
            StringInput::new(input, Default::default(), Default::default()),
            None,
        );
        
        let mut module = parser.parse_module().unwrap();
        
        // 应用箭头函数转换
        let arrow_config = arrow::Config { spec: true };
        let mut arrow_transformer = arrow(arrow_config);
        module.visit_mut_with(&mut arrow_transformer);
        
        // 生成代码
        let mut output = Vec::new();
        let writer = JsWriter::new(
            Default::default(),
            "\n",
            &mut output,
            None,
        );
        
        let mut emitter = Emitter {
            cfg: Default::default(),
            cm: Default::default(),
            wr: Box::new(writer),
        };
        
        emitter.emit_module(&module).unwrap();
        String::from_utf8(output).unwrap()
    }
}

这个完整示例演示了如何使用swc_ecma_ext_transforms库进行完整的代码转换流程,包括:

  • 代码解析为AST
  • 应用多个内置转换器
  • 将转换后的AST重新生成为代码
  • 包含基本的错误处理和测试用例
回到顶部