From 7ce0b7fecc8372d696dd10844690a0afac1b190d Mon Sep 17 00:00:00 2001 From: Scott Scoble Date: Mon, 29 Jun 2026 17:16:11 -0700 Subject: [PATCH] =?UTF-8?q?fix(speckl):=20TS=20generator=20=E2=80=94=20emi?= =?UTF-8?q?t=20interface=20record=20types=20(cycle=2073)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same defect as Rust backend: interface records (Money, Ticket, Order, etc.) were not emitted as TS interfaces. Only events were emitted. Now record-kind interfaces (with fields, not methods) emit as TS interfaces, placed between the enum declarations and event interfaces. Output for FederatedMeetupProduct: 426 lines (was 191), 47 interfaces (was ~11). 57/57 tests pass. --- .../src/generators/typescript-state-machine.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/compiler/src/generators/typescript-state-machine.ts b/compiler/src/generators/typescript-state-machine.ts index 648b5f2..aba1f07 100644 --- a/compiler/src/generators/typescript-state-machine.ts +++ b/compiler/src/generators/typescript-state-machine.ts @@ -187,6 +187,22 @@ function emitSpeck(speck: SpeckNode): string { } const stateEnum = allEnums.join('\n\n'); + // Cycle 73: emit interface record types as TS interfaces. + // Previously only events were emitted as TS interfaces; interface records + // (Money, Ticket, Order, etc.) were missing from the output. + const recordInterfaces = allInterfaces.filter(iface => + (iface?.kind === 'record' || (iface?.fields && iface.fields.length > 0)) && + // Skip enum-like interfaces (they have methods, not fields) + !iface?.methods?.length + ); + const recordInterfaceStr = recordInterfaces.map(iface => { + const fields = iface.fields.map((f: any) => { + const name = cleanName(f.name); + return ` ${name}: ${tsType(f.type, speck.name, enumMap)};`; + }).join('\n'); + return `export interface ${iface.name} {\n${fields}\n}`; + }).join('\n\n'); + const eventInterfaces = [ // Explicit event declarations ...events.map(e => { @@ -419,6 +435,7 @@ ${verifyChecks} `// Auto-generated by speckl-compile from ${speck.name}\n` + `// DO NOT EDIT MANUALLY — regenerate from .speckdl source\n\n` + `${stateEnum}\n\n` + + `${recordInterfaceStr ? recordInterfaceStr + '\n\n' : ''}` + `${eventInterfaces}\n\n` + `${hashUtility}` + `${classBody}`;