Skip to main content

Builder API

The Builder provides a fluent interface for creating item specifications with type-safe attribute setting and modifier application.

Class: Builder<C>

A fluent builder for creating item specifications with compile-time type safety.

Constructor

new Builder<C>(config: C, name?: string)

Typically created through engine.builder() rather than directly.

Attribute Methods

set()

Sets an attribute value with full type safety.

set<K extends AttrKeyOf<C>>(key: K, value: AttrValueOf<C, K>): Builder<C>

Parameters

  • key - Attribute key (validated against configuration)
  • value - Attribute value (type-checked against attribute schema)

Example

const attributeDefaults = {
Rarity: "Epic" as const,
Level: 50,
Enchanted: true,
};

const item = engine
.builder("Magic Sword")
.set("Rarity", attributeDefaults.Rarity)
.set("Level", attributeDefaults.Level)
.set("Enchanted", attributeDefaults.Enchanted)
.build();

setAttributes()

Applies multiple attributes from an object. Useful for defaults or cloning state.

setAttributes(attrs: Partial<Attributes<C>>): Builder<C>

Example

const defaults = {
Rarity: "Epic" as const,
Level: 50,
Enchanted: true,
};

const item = engine.builder("Magic Sword").setAttributes(defaults).build();

Modifier Methods

increase()

Adds a sum operation modifier to increase a metric.

increase<M extends MetricOf<C>>(metric: M): { by(value: number): Builder<C> }

Example

const item = engine.builder("Sword").increase("Damage").by(50).build();

decrease()

Adds a subtract operation modifier to decrease a metric.

decrease<M extends MetricOf<C>>(metric: M): { by(value: number): Builder<C> }

Example

const item = engine.builder("Cursed Item").decrease("Health").by(25).build();

multiply()

Adds a multiply operation modifier to scale a metric.

multiply<M extends MetricOf<C>>(metric: M): { by(value: number): Builder<C> }

Example

const item = engine
.builder("Legendary Weapon")
.multiply("Damage")
.by(1.5)
.build();

apply()

Adds a modifier with a specific operation.

apply<M extends MetricOf<C>, O extends OperationOf<C>>(
metric: M,
operation: O
): { by(value: number): Builder<C> }

Example

const item = engine
.builder("Powered Item")
.apply("Damage", "pow")
.by(2)
.build();

Conditional Methods

when()

Sets a condition for subsequent modifiers.

when(condition: Condition<C>): Builder<C>

Condition Types

  • { op: "eq", attr: K, value: V } - Equality check
  • { op: "gt", attr: K, value: V } - Greater than
  • { op: "gte", attr: K, value: V } - Greater than or equal
  • { op: "lt", attr: K, value: V } - Less than
  • { op: "lte", attr: K, value: V } - Less than or equal
  • { op: "includes", attr: K, value: V[] } - Value in array

Example

const item = engine
.builder("Conditional Item")
.setAttributes({ Rarity: "Epic" as const })
// Only applies to Epic items
.when({ op: "eq", attr: "Rarity", value: "Epic" })
.multiply("Damage")
.by(2.0)
.build();

clearConditions()

Removes all active conditions.

clearConditions(): Builder<C>

Metadata Methods

with()

Sets metadata for subsequent modifiers.

with(metadata: {
stacking?: Stacking;
priority?: number;
source?: string;
}): Builder<C>

Parameters

  • stacking - Stacking behavior ("stack" | "unique" | { uniqueBy: string })
  • priority - Application priority (higher = applied later)
  • source - Source identifier for unique stacking

Example

const item = engine
.builder("Prioritized Item")
// High priority modifier applied last
.with({ priority: 100 })
.multiply("Damage")
.by(1.5)
// Unique modifier that can't stack
.with({ stacking: "unique", source: "fire-enchant" })
.increase("Damage")
.by(25)
.build();

clearMeta()

Clears all current metadata (priority, stacking, source).

clearMeta(): Builder<C>

Grouping Methods

group()

Groups modifiers with shared conditions and metadata.

group(
options: {
when?: Condition<C>;
with?: { stacking?: Stacking; priority?: number; source?: string };
},
fn: (builder: Builder<C>) => void
): Builder<C>

Example

const item = engine
.builder("Grouped Item")
.group(
{
when: { op: "eq", attr: "Enchanted", value: true },
with: { priority: 50 },
},
(builder) => {
builder.increase("Damage").by(25).increase("Health").by(50);
}
)
.build();

Utility Methods

build()

Creates the final immutable item specification.

build(): ItemSpec<C>

Returns

An ItemSpec<C> containing:

  • name? - Optional item name
  • attributes - All set attributes
  • modifiers - All added modifiers

clone()

Creates a copy of the builder with the same state.

clone(): Builder<C>

reset()

Resets the builder to initial state.

reset(): Builder<C>

clearAttributes()

Removes all set attributes.

clearAttributes(): Builder<C>

clearModifiers()

Removes all added modifiers.

clearModifiers(): Builder<C>

Advanced Patterns

Attribute Helper Function

Create a helper to apply multiple attributes:

function applyAttributes<C extends ConfigSpec>(
builder: Builder<C>,
attributes: Record<string, any>
): Builder<C> {
Object.entries(attributes).forEach(([key, value]) => {
builder.set(key as any, value);
});
return builder;
}

// Usage
const warriorDefaults = {
Class: "Warrior" as const,
Level: 25,
Strength: 18,
};

const warrior = applyAttributes(engine.builder("Warrior"), warriorDefaults)
.increase("Health")
.by(100)
.build();

Conditional Chains

Chain multiple conditions:

const item = engine
.builder("Complex Item")
.when({ op: "eq", attr: "Rarity", value: "Legendary" })
.multiply("Damage")
.by(2.0)
.when({ op: "gte", attr: "Level", value: 50 })
.increase("Health")
.by(100)
.when({ op: "eq", attr: "Enchanted", value: true })
.increase("Mana")
.by(50)
.build();

Priority Ordering

Control modifier application order:

const item = engine
.builder("Ordered Item")
// Applied first (highest priority)
.with({ priority: 100 })
.increase("Damage")
.by(50)
// Applied second
.with({ priority: 50 })
.multiply("Damage")
.by(1.5)
// Applied last (lowest priority)
.with({ priority: 10 })
.increase("Damage")
.by(25)
.build();

Type Safety

The Builder provides complete compile-time type checking:

  • Attribute keys must exist in configuration
  • Attribute values must match schema types
  • Metric names must be declared in configuration
  • Operation names must be available

Invalid usage results in TypeScript compilation errors:

// ❌ TypeScript error - invalid attribute
.set("InvalidAttr", "value")

// ❌ TypeScript error - invalid metric
.increase("InvalidMetric")

// ✅ Valid usage
.set("Rarity", "Epic")
.increase("Damage")