@macroforge/mcp-server
Version:
MCP server for Macroforge documentation and code analysis
203 lines (155 loc) • 9.99 kB
Markdown
# Built-in Macros
Macroforge comes with built-in derive macros that cover the most common code generation needs. All
macros work with classes, interfaces, enums, and type aliases.
## Overview
| Macro | Generates | Description |
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------- |
| [`Debug`](../docs/builtin-macros/debug) | `static toString(value: T): string` | Human-readable string representation |
| [`Clone`](../docs/builtin-macros/clone) | `static clone(value: T): T` | Creates a deep copy of the object |
| [`Default`](../docs/builtin-macros/default) | `static defaultValue(): T` | Creates an instance with default values |
| [`Hash`](../docs/builtin-macros/hash) | `static hashCode(value: T): number` | Generates a hash code for the object |
| [`PartialEq`](../docs/builtin-macros/partial-eq) | `static equals(a: T, b: T): boolean` | Value equality comparison |
| [`Eq`](../docs/builtin-macros/eq) | None | Marks equality as total; requires `PartialEq` |
| [`Ord`](../docs/builtin-macros/ord) | `static compare(a: T, b: T): number` | Total ordering comparison (-1, 0, 1); requires `Eq` and `PartialOrd` |
| [`PartialOrd`](../docs/builtin-macros/partial-ord) | `static partialCompare(a: T, b: T): number | null` | Partial ordering comparison; requires `PartialEq` |
| [`Encode`](../docs/builtin-macros/encode) | `static encode(value: T, keepMetadata?: boolean): string` | JSON encoding with type handling |
| [`Decode`](../docs/builtin-macros/decode) | `static decode(input, opts?): { success: true; value: T } | { success: false; errors }` | JSON decoding with validation |
## Type-Position Macros
One built-in macro is written where a type goes rather than in ``:
| Macro | Expands To | Description |
| ----------------------------------------------- | ---------------------------------------------- | -------------------------------------------------- |
| [`$Newtype<T>`](../docs/builtin-macros/newtype) | `T & { readonly [brand]: true }` | Nominal brand backed by a per-site `unique symbol` |
## Using Built-in Macros
Built-in macros don't require imports. Just use them with ``:
TypeScript
```
/** @derive(Debug, Clone, PartialEq) */
class User {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
```
## Interface Support
All built-in macros work with interfaces. Interfaces have no class to attach statics to, so they get
standalone functions named `{typeName}{Operation}` taking the value as
the first parameter. When `generateConvenienceConst` is enabled (the default), a grouping `const` is
also emitted so you can call them by short name:
TypeScript
```
/** @derive(Debug, Clone, PartialEq) */
interface Point {
x: number;
y: number;
}
// Generated standalone functions:
// export function pointToString(value: Point): string { ... }
// export function pointClone(value: Point): Point { ... }
// export function pointEquals(a: Point, b: Point): boolean { ... }
// export function pointHashCode(value: Point): number { ... }
// Plus a grouping const (generateConvenienceConst, on by default):
// export const Point = {
// toString: pointToString,
// clone: pointClone,
// equals: pointEquals,
// hashCode: pointHashCode,
// } as const;
const point: Point = { x: 10, y: 20 };
console.log(pointToString(point)); // "Point { x: 10, y: 20 }"
const copy = pointClone(point); // { x: 10, y: 20 }
console.log(pointEquals(point, copy)); // true
// …or via the grouping const
console.log(Point.toString(point));
```
## Enum Support
All built-in macros work with enums. For enums, methods are generated as functions in a namespace
with the same name:
TypeScript
```
/** @derive(Debug, Clone, PartialEq, Encode, Decode) */
enum Status {
Active = "active",
Inactive = "inactive",
Pending = "pending",
}
// Generated standalone functions:
// export function statusToString(value: Status): string { ... }
// export function statusClone(value: Status): Status { ... }
// export function statusEquals(a: Status, b: Status): boolean { ... }
// export function statusHashCode(value: Status): number { ... }
// export function statusEncode(value: Status): string { ... }
// export function statusDecode(input: unknown): Status { ... }
// Enums use namespace merging for the convenience names:
// namespace Status {
// export const toString = statusToString;
// export const encode = statusEncode;
// }
console.log(statusToString(Status.Active)); // "Status.Active"
console.log(statusEquals(Status.Active, Status.Active)); // true
const json = statusEncode(Status.Pending); // "pending"
// Note: enum decode throws on invalid input rather than
// returning a success/errors union.
const parsed = statusDecode("active"); // Status.Active
```
## Type Alias Support
All built-in macros work with type aliases. Object type aliases get field-aware standalone
functions, plus the optional grouping `const`:
TypeScript
```
/** @derive(Debug, Clone, PartialEq, Encode, Decode) */
type Point = {
x: number;
y: number;
};
// Generated standalone functions:
// export function pointToString(value: Point): string { ... }
// export function pointClone(value: Point): Point { ... }
// export function pointEquals(a: Point, b: Point): boolean { ... }
// export function pointHashCode(value: Point): number { ... }
// export function pointEncode(value: Point, keepMetadata?: boolean): string { ... }
// export function pointDecode(input: unknown, opts?): { success: true; value: Point }
// | { success: false; errors } { ... }
const point: Point = { x: 10, y: 20 };
console.log(pointToString(point)); // "Point { x: 10, y: 20 }"
const copy = pointClone(point); // { x: 10, y: 20 }
console.log(pointEquals(point, copy)); // true
```
Union type aliases also work, using JSON-based implementations:
TypeScript
```
/** @derive(Debug, PartialEq) */
type ApiStatus = "loading" | "success" | "error";
const status: ApiStatus = "success";
console.log(ApiStatus.toString(status)); // "ApiStatus(\\"success\\")"
console.log(ApiStatus.equals("success", "success")); // true
```
## Combining Macros
All macros can be used together. They don't conflict and each generates independent methods:
TypeScript
```
const user = new User("Alice", 30);
// Debug
console.log(User.toString(user));
// "User { name: Alice, age: 30 }"
// Clone
const copy = User.clone(user);
console.log(copy.name); // "Alice"
// PartialEq
console.log(User.equals(user, copy)); // true
```
## Detailed Documentation
Each macro has its own options and behaviors:
- [**Debug**](../docs/builtin-macros/debug) - Customizable field renaming and skipping
- [**Clone**](../docs/builtin-macros/clone) - Deep copying for all field types
- [**Default**](../docs/builtin-macros/default) - Default value generation with field attributes
- [**Hash**](../docs/builtin-macros/hash) - Hash code generation for use in maps and sets
- [**PartialEq**](../docs/builtin-macros/partial-eq) - Value-based equality comparison
- [**Eq**](../docs/builtin-macros/eq) - Marks equality as total, as Rust's `Eq`
- [**Ord**](../docs/builtin-macros/ord) - Total ordering for sorting
- [**PartialOrd**](../docs/builtin-macros/partial-ord) - Partial ordering comparison
- [**Encode**](../docs/builtin-macros/encode) - JSON encoding with endec-style options
- [**Decode**](../docs/builtin-macros/decode) - JSON decoding with validation
- [**$Newtype**](../docs/builtin-macros/newtype) - Nominal brands, constructed through `Decode`