I'm working on a SWC Rust WASM plugin to transform JavaScript.
Overall SWC and its API are well designed. However currently I struggle to convert a TaggedTemplateExpression
to a CallExpression
like in this example:
console.log`Hello, ${name}!`;
to:
console.log("Hello, ", name, "!");
In Babel, this transformation would be relatively straightforward. Here's an example of how it might look:
const babel = require("@babel/core");
function transform({ types: t }) {
return {
visitor: {
TaggedTemplateExpression(path) {
const { tag, quasi } = path.node;
if (
t.isMemberExpression(tag) &&
t.isIdentifier(tag.object, { name: "console" }) &&
t.isIdentifier(tag.property, { name: "log" })
) {
let args = [];
quasi.quasis.forEach((element, index) => {
args.push(t.stringLiteral(element.value.raw));
if (index < quasi.expressions.length) {
args.push(quasi.expressions[index]);
}
});
path.replaceWith(
t.callExpression(
t.memberExpression(
t.identifier("console"),
t.identifier("log")
),
args
)
);
}
},
},
};
}
I found the Changing AST Type section of the SWC CheatSheet but still I don't know how to convert it properly:
use swc_core::ecma::{
ast::*,
visit::{VisitMut, VisitMutWith},
};
struct TemplateToCallTransform;
impl VisitMut for TemplateToCallTransform {
fn visit_mut_tagged_tpl(&mut self, n: &mut TaggedTpl) {=
// How do I replace the current node with the new CallExpr?
}
}
SWC author here (again).
You need to handle it from fn visit_mut_expr(&mut self, e: &mut Expr)
.
TaggedTpl
and CallExpr
both belongs to expression in ECMAScript, so you can handle it from there.
use swc_core::ecma::{
ast::*,
visit::{VisitMut, VisitMutWith},
};
struct TemplateToCallTransform;
impl VisitMut for TemplateToCallTransform {
fn visit_mut_expr(&mut self, e: &mut Expr) {
// You may skip this, depending on the requirements.
e.visit_mut_children_with(self);
match e {
Expr::TaggedTpl(n) => {
*e = Expr::Call(CallExpr {
// ...fields
});
}
_ => {}
}
}
}