IRRI & IRRef
IRRef pairs IR with its AST node. IRRI collects all IRRefs for batch transformations.
IRRef: The Pairing
Section titled “IRRef: The Pairing”Each IR has a corresponding AST node. IRRef<T, TNode> holds both:
export class IRRef<T extends IR, TNode extends Node> { constructor( readonly ir: T, // Immutable IR readonly node: TNode, // AST node to transform ) { inject(IRRI).register(this) // Auto-register }}When you create an IRRef, it auto-registers with IRRI and becomes discoverable.
IRRI: Registry and Querying
Section titled “IRRI: Registry and Querying”IRRI collects all IRRef instances during compilation:
export class IRRI { // Query all IRs of a kind allByKind<K extends IRKind>(kind: K): IRRef<KnownIRs[K], Node>[]
// Find single IRRef with filter firstIrr<K extends IRKind>(kind: K, filterFn: (item: KnownIRs[K]) => boolean): IRRef<KnownIRs[K], Node> | undefined
// Get pure IR without AST (for generators) implode<T extends IR>(irrs: IRRef<T, Node>[]): ImplodeIRRef<T>[]}Usage Patterns
Section titled “Usage Patterns”Batch Transformations
Section titled “Batch Transformations”Process all IRs of a kind at once:
const components = irri.allByKind('Component')for (const ref of components) { componentTransformer.transform(ref) // Has both IR and AST}Single Lookup
Section titled “Single Lookup”const myButton = irri.firstIrr('Component', (comp) => comp.tag === 'my-button')if (myButton) { updateDecorator(myButton.node, myButton.ir)}Pure IR Tree
Section titled “Pure IR Tree”For generators that don’t need AST:
const components = irri.allByKind('Component')const pureIR = irri.implode(components) // ComponentIR[]generateIRJSON(pureIR)Why This Design
Section titled “Why This Design”Convenience – IR and AST are together; no separate lookup needed.
Efficiency – Batch by kind enables efficient transformation: process all components once.
Clarity – Fresh IR each compilation; IRRef is purely organizational.