fix(speckl): TS generator — emit interface record types (cycle 73)

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.
This commit is contained in:
Scott Scoble 2026-06-29 17:16:11 -07:00
parent 84b8962d22
commit 7ce0b7fecc

View file

@ -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}`;