API Stability Notice
Macroforge is under active development. The API is not yet stable and may change between versions. Some documentation sections may be outdated.
Custom Macros
Macroforge allows you to create custom macros in Rust: derive macros, attribute macros and call macros. Your macros see the declaration they are attached to, can look up any type in the project, and can generate any TypeScript code.
Overview
Custom macros are written in Rust and compiled to WebAssembly. The process involves:
- Creating a Rust crate that builds to WebAssembly
- Defining macro functions with
#[ts_macro_derive],#[ts_macro_attribute]or#[ts_macro] - Using
macroforge_ts_quoteto generate TypeScript code - Building and publishing as an npm package
Quick Example
Rust
use macroforge_ts::macros::{ts_macro_derive, ts_template};
use macroforge_ts::ts_syn::{Data, DeriveInput, MacroforgeError, TsStream, parse_ts_macro_input};
#[ts_macro_derive(
JSON,
description = "Generates toJSON() returning a plain object"
)]
pub fn derive_json(mut input: TsStream) -> Result<TsStream, MacroforgeError> {
let input = parse_ts_macro_input!(input as DeriveInput);
match &input.data {
Data::Class(class) => {
Ok(ts_template!(Within {
toJSON(): Record<string, unknown> {
return {
{#for field in class.field_names()}
@{field}: this.@{field},
{/for}
};
}
}))
}
_ => Err(MacroforgeError::new(
input.error_span(),
"@derive(JSON) only works on classes",
)),
}
}Using Custom Macros
Once your macro package is published, users can import and use it:
TypeScript
/** import macro { JSON } from "@my/macros"; */
/** @derive(JSON) */
class User {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
const user = new User("Alice", 30);
console.log(user.toJSON()); // { name: "Alice", age: 30 } Note
The
import macro comment tells Macroforge which package provides the macro.Getting Started
Follow these guides to create your own macros:
Reference
#[ts_macro]and#[ts_macro_attribute]: call and attribute macros- Output and Imports: where generated code goes, imports, patches and warnings
- Context and IR: everything a macro can read about its target
- Type-Aware Macros: looking up other types and reading the project's config
- Errors and Diagnostics: failing with errors, reporting warnings
- Testing and Debugging: unit tests, debug logging, registering macros by hand