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.

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

MacroGeneratesDescription
DebugtoString(): stringHuman-readable string representation
Cloneclone(): TCreates a deep copy of the object
Defaultstatic default(): TCreates an instance with default values
HashhashCode(): numberGenerates a hash code for the object
PartialEqequals(other: T): booleanValue equality comparison
Ordcompare(other: T): numberTotal ordering comparison (-1, 0, 1)
PartialOrdpartialCompare(other: T): number | nullPartial ordering comparison
SerializetoJSON(): Record<string, unknown>JSON serialization with type handling
Deserializestatic fromJSON(data: unknown): TJSON deserialization with validation

Using Built-in Macros

Built-in macros don't require imports. Just use them with @derive:

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. For interfaces, methods are generated as functions in a namespace with the same name, using self as the first parameter:

TypeScript
/** @derive(Debug, Clone, PartialEq) */
interface Point {
  x: number;
  y: number;
}

// Generated namespace:
// namespace Point {
//   export function toString(self: Point): string { ... }
//   export function clone(self: Point): Point { ... }
//   export function equals(self: Point, other: Point): boolean { ... }
//   export function hashCode(self: Point): number { ... }
// }

const point: Point = { x: 10, y: 20 };

// Use the namespace functions
console.log(Point.toString(point));     // "Point { x: 10, y: 20 }"
const copy = Point.clone(point);        // { x: 10, y: 20 }
console.log(Point.equals(point, copy)); // true

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, Serialize, Deserialize) */
enum Status {
  Active = "active",
  Inactive = "inactive",
  Pending = "pending",
}

// Generated namespace:
// namespace Status {
//   export function toString(value: Status): string { ... }
//   export function clone(value: Status): Status { ... }
//   export function equals(a: Status, b: Status): boolean { ... }
//   export function hashCode(value: Status): number { ... }
//   export function toJSON(value: Status): string | number { ... }
//   export function fromJSON(data: unknown): Status { ... }
// }

// Use the namespace functions
console.log(Status.toString(Status.Active));     // "Status.Active"
console.log(Status.equals(Status.Active, Status.Active)); // true
const json = Status.toJSON(Status.Pending);      // "pending"
const parsed = Status.fromJSON("active");        // Status.Active

Type Alias Support

All built-in macros work with type aliases. For object type aliases, field-aware methods are generated in a namespace:

TypeScript
/** @derive(Debug, Clone, PartialEq, Serialize, Deserialize) */
type Point = {
  x: number;
  y: number;
};

// Generated namespace:
// namespace Point {
//   export function toString(value: Point): string { ... }
//   export function clone(value: Point): Point { ... }
//   export function equals(a: Point, b: Point): boolean { ... }
//   export function hashCode(value: Point): number { ... }
//   export function toJSON(value: Point): Record<string, unknown> { ... }
//   export function fromJSON(data: unknown): Point { ... }
// }

const point: Point = { x: 10, y: 20 };
console.log(Point.toString(point));     // "Point { x: 10, y: 20 }"
const copy = Point.clone(point);        // { x: 10, y: 20 }
console.log(Point.equals(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 { name: Alice, age: 30 }"

// Clone
const copy = user.clone();
console.log(copy.name); // "Alice"

// Eq
console.log(user.equals(copy)); // true

Detailed Documentation

Each macro has its own options and behaviors:

  • Debug - Customizable field renaming and skipping
  • Clone - Deep copying for all field types
  • Default - Default value generation with field attributes
  • Hash - Hash code generation for use in maps and sets
  • PartialEq - Value-based equality comparison
  • Ord - Total ordering for sorting
  • PartialOrd - Partial ordering comparison
  • Serialize - JSON serialization with serde-style options
  • Deserialize - JSON deserialization with validation