Getting Started
Welcome to ReluxScript! This guide will help you write your first AST transformation plugin.
What is ReluxScript?
ReluxScript is a domain-specific language for writing AST transformation plugins that compile to both Babel (JavaScript) and SWC (Rust). Write your transformation logic once, and ReluxScript generates plugins for both platforms.
Installation
Install ReluxScript from crates.io:
cargo install reluxscriptThis installs the relux CLI tool globally.
Your First Plugin
Let's create a simple plugin that removes console.log statements:
1. Create a New Plugin
relux new remove-consoleThis creates remove-console.lux with a basic template.
2. Implement the Transformation
Edit remove-console.lux:
// Remove all console.log calls from your code
plugin RemoveConsole {
fn visit_call_expression(node: &mut CallExpression, ctx: &Context) {
// Check if this is a console.log call
if matches!(node.callee, "console.log") {
// Replace with an empty statement
*node = Statement::empty();
}
}
}3. Compile to Babel
relux build remove-console.lux --target babelThis generates dist/index.js - a Babel plugin you can use with webpack, rollup, or babel-cli.
4. Compile to SWC
relux build remove-console.lux --target swcThis generates dist/lib.rs - a SWC plugin you can compile to WASM.
5. Use Your Plugin
With Babel:
// babel.config.js
module.exports = {
plugins: [
'./dist/index.js'
]
}With SWC:
// .swcrc
{
"jsc": {
"experimental": {
"plugins": [
["./dist/lib.wasm", {}]
]
}
}
}What's Next?
Key Concepts
The Visitor Pattern
ReluxScript uses the visitor pattern to traverse and transform the AST. You implement visitor methods like:
visit_call_expression- Called for every function callvisit_function_declaration- Called for every function declarationvisit_identifier- Called for every identifier
Mutations are Explicit
All changes to the AST must be explicit:
*node = Statement::empty(); // Replace node
node.name = "newName"; // Modify propertyThe matches! Macro
Use matches! to pattern match on AST nodes:
if matches!(node.callee, "console.log") {
// This is console.log
}
if matches!(node.operator, "+") {
// This is addition
}Common Patterns
Removing Nodes
*node = Statement::empty();Modifying Properties
node.name = "newName";
node.async = true;Creating New Nodes
let new_call = CallExpression {
callee: Identifier::new("console.log"),
arguments: vec![StringLiteral::new("Hello")]
};Conditional Transformations
if matches!(node.operator, "+") && node.left.is_number() {
// Transform only numeric additions
}Getting Help
- Documentation: docs.reluxscript.com
- Examples: Check the
/examplesfolder in the repo - Issues: GitHub Issues
Ready to dive deeper? Continue to Core Concepts.
