/** * The AFI fixture, TypeScript side — mirrors `tests/afi/fixture.py` 1:1. * * Each function declares the same IR type schema the Python fixture's Pydantic * Input/Output models imply, so `buildIr()` here emits the same KDL the Python * `build_ir()` emits from `fixture.py`. The byte-parity test (`ir.test.ts`) * subprocesses the live Python emitter and asserts equality. * * Output structs are declared under their model name (`ProfileOutput`, * `OrderOutput`, …) and referenced via `{ kind: 'ref' }`; the emitter renames * them to the canonical `Output`, exactly as `_collect_named_types` * renames the Pydantic models. */ import { client, ReactContext } from '../src' import type { NamedType, StructField } from '../src' const intField = (name: string): StructField => ({ name, required: true, shape: { kind: 'primitive', primitive: 'integer' }, }) const strField = (name: string): StructField => ({ name, required: true, shape: { kind: 'primitive', primitive: 'string' }, }) const boolField = (name: string): StructField => ({ name, required: true, shape: { kind: 'primitive', primitive: 'boolean' }, }) const ProfileOutput: NamedType = { kind: 'struct', fields: [intField('user_id'), strField('name')] } const OrderOutput: NamedType = { kind: 'struct', fields: [intField('id'), intField('user_id'), intField('total')], } const UserCtx = new ReactContext('user') /** Register the AFI fixture functions with the mizan-ts registry. */ export function registerFixture(): void { // echo — plain function, typed input + struct output. client( { ir: { input: [strField('text')], output: { kind: 'ref', name: 'EchoOutput' }, types: { EchoOutput: { kind: 'struct', fields: [strField('message')] } }, }, }, async function echo(text: string) { return { message: `echo: ${text}` } }, ) // whoami — no input. client( { ir: { output: { kind: 'ref', name: 'WhoamiOutput' }, types: { WhoamiOutput: { kind: 'struct', fields: [strField('email'), boolField('authenticated')], }, }, }, }, async function whoami() { return { email: 'anon@example.com', authenticated: false } }, ) // user_profile — context member. client( { context: UserCtx, ir: { input: [intField('user_id')], output: { kind: 'ref', name: 'ProfileOutput' }, types: { ProfileOutput }, }, }, async function user_profile(user_id: number) { return { user_id, name: 'placeholder' } }, ) // user_orders — context member, list output, same param (param elevation). client( { context: UserCtx, ir: { input: [intField('user_id')], output: { kind: 'list', inner: { kind: 'ref', name: 'OrderOutput' } }, types: { OrderOutput }, }, }, async function user_orders(_user_id: number) { return [] }, ) // update_profile — mutation affecting the user context. client( { affects: UserCtx, ir: { input: [intField('user_id'), strField('name')], output: { kind: 'ref', name: 'StatusOutput' }, types: { StatusOutput: { kind: 'struct', fields: [boolField('ok')] } }, }, }, async function update_profile(_user_id: number, _name: string) { return { ok: true } }, ) // find_user — optional return. client( { ir: { input: [intField('user_id')], output: { kind: 'optional', inner: { kind: 'ref', name: 'ProfileOutput' } }, types: { ProfileOutput }, }, }, async function find_user(_user_id: number) { return null }, ) // rename_user — merge target. client( { merge: UserCtx, ir: { input: [intField('user_id'), strField('name')], output: { kind: 'ref', name: 'ProfileOutput' }, types: { ProfileOutput }, }, }, async function rename_user(user_id: number, name: string) { return { user_id, name } }, ) }