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.

Command Line Interface

macroforge v0.1.80

Command-line interface for expanding Macroforge macros

Installation

The CLI is a Rust binary. You can install it using Cargo:

Bash
cargo install macroforge_ts

Or build from source:

Bash
git clone https://github.com/macroforge-ts/macroforge-ts.git
cd macroforge-ts/crates
cargo build --release --bin macroforge

# The binary is at target/release/macroforge

Commands

macroforge expand

Expands macros in a TypeScript file and outputs the transformed code.

Bash
macroforge expand <input> [options]

Arguments

ArgumentDescription
<input>Path to the TypeScript or TSX file to expand

Options

OptionDescription
--out <path>Write the expanded JavaScript/TypeScript to a file
--types-out <path>Write the generated .d.ts declarations to a file
--printPrint output to stdout even when --out is specified
--scanScan directory for TypeScript files with macros
--include-ignoredInclude files ignored by .gitignore when scanning
-q, --quietSuppress output when no macros are found

Examples

Expand a file (writes a sibling src/user.expanded.ts):

Bash
macroforge expand src/user.ts

Print the expansion to stdout instead:

Bash
macroforge expand src/user.ts --print

Expand and write to a file:

Bash
macroforge expand src/user.ts --out dist/user.js

Expand with both runtime output and type declarations:

Bash
macroforge expand src/user.ts --out dist/user.js --types-out dist/user.d.ts
Note
Expansion runs natively in Rust — no Node.js process is spawned. External macro packages are loaded from node_modules via FFI, so run the CLI from your project root when your code uses them.

macroforge tsc

Runs TypeScript type checking with macro expansion. This wraps tsc --noEmit and expands macros before type checking, so your generated methods are properly type-checked.

Bash
macroforge tsc [options]

Options

OptionDescription
-p, --project <path>Path to tsconfig.json (defaults to tsconfig.json in current directory)

Examples

Type check with default tsconfig.json:

Bash
macroforge tsc

Type check with a specific config:

Bash
macroforge tsc -p tsconfig.build.json

macroforge svelte-check

Runs svelte-check with macro expansion, so Svelte components using macros are properly type-checked.

Bash
macroforge svelte-check [options]

Options

OptionDescription
--workspace <path>Workspace directory (defaults to current directory)
--tsconfig <path>Path to tsconfig.json
--output <format>Output format: human, human-verbose, machine, machine-verbose
--fail-on-warningsExit with error on warnings (not just errors)

macroforge svelte-package

Runs svelte-package with macro expansion, so a published Svelte library ships fully expanded source and type declarations.

Bash
macroforge svelte-package [options]

Options

OptionDescription
-i, --input <path>Source directory (defaults to src/lib)
-o, --output <path>Output directory (defaults to dist)
--tsconfig <path>Path to tsconfig.json
--no-typesSkip generating type declarations

macroforge watch

Watches source files and maintains the macro expansion cache, keeping it up to date as files change.

Bash
macroforge watch [root] [options]

Options

OptionDescription
--debounce-ms <ms>Debounce interval in milliseconds (default: 100)

macroforge cache

Builds the .macroforge/cache directory once for all source files. Useful for CI or pre-build steps.

Bash
macroforge cache [root] [options]

Options

OptionDescription

macroforge refresh

Deletes and rebuilds the macro cache from scratch.

Bash
macroforge refresh [root] [options]

Options

OptionDescription

macroforge build

Builds a macro crate to WebAssembly with wasm-bindgen and post-processes the output to add $-prefixed re-exports for function-like (Call) macros. Used when distributing your own macro packages.

Bash
macroforge build [crate_dir] [options]

Steps:

  1. cargo build --release --target wasm32-unknown-unknown
  2. Runs wasm-bindgen --target nodejs into pkg/ (or the directory given via -o)
  3. Parses the generated .d.ts to discover Call macros and appends export { state as $state }-style aliases so consumers can import both forms.

Options

OptionDescription
[crate_dir]Path to the macro crate (defaults to .)
-o, --out <out>Output directory for the WASM package (defaults to <crate_dir>/pkg)

Examples

Bash
# Build the current macro crate
macroforge build

# Build a specific crate into a custom directory
macroforge build ./packages/my-macros -o dist/wasm

Output Format

Expanded Code

When expanding a file like this:

TypeScript
/** @derive(Debug) */
class User {
  name: string;
  age: number;

  constructor(name: stringage: number) {
    this.name = name;
    this.age = age;
  }
}

The CLI outputs the expanded code with the generated methods:

TypeScript
class User {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  [Symbol.for("nodejs.util.inspect.custom")](): string {
    return `User { name: ${this.name}, age: ${this.age} }`;
  }
}

Diagnostics

Errors and warnings are printed to stderr in a readable format:

Text
[macroforge] error at src/user.ts:5:1: Unknown derive macro: InvalidMacro
[macroforge] warning at src/user.ts:10:3: Field 'unused' is never used

Use Cases

CI/CD Type Checking

Use macroforge tsc in your CI pipeline to type-check with macro expansion:

JSON
# package.json
{
  "scripts": {
    "typecheck""macroforge tsc"
  }
}

Debugging Macro Output

Use macroforge expand to inspect what code your macros generate:

Bash
macroforge expand src/models/user.ts --print | less

Build Pipeline

Generate expanded files as part of a custom build:

Bash
#!/bin/bash
for file in src/**/*.tsdo
  outfile="dist/$(basename "$file" .ts).js"
  macroforge expand "$file" --out "$outfile"
done