yolk

Codegen

yolk-codegen reads a .spec.ts file and generates typed bindings for both sides of the bridge. It uses the TypeScript compiler API so it understands your types exactly, with no separate schema language.

Usage

yolk-codegen <spec.ts> <swift-out-dir> <ts-out-dir>
yolk-codegen counter.spec.ts ./macos/Generated ./logic/src/generated

What it generates

Swift protocol + dispatch table

The generated Swift file has two parts:

The protocol — the contract you implement:

public protocol CounterModule: YolkModule {
    func increment(by: Double) async throws -> Double
    func value() async throws -> Double
}

The extension — the dispatch table, so you only implement domain methods:

public extension CounterModule {
    static var moduleName: String { "Counter" }

    func handle(method: String, args: [YolkValue]) async throws -> YolkValue {
        switch method {
        case "increment":
            let by = /* extract and validate args[0] as Double */
            let result = try await increment(by: by)
            return .double(result)
        // ...
        }
    }
}

You never write handle yourself. Codegen owns it.

TypeScript proxy class

export class Counter extends NativeModule {
  increment(by: number): Promise<number> {
    return this.call("increment", by)
  }
  value(): Promise<number> {
    return this.call("value")
  }
}

Import and use it like any other class. The bridge plumbing is invisible.

Type mapping

| TypeScript | Swift | |---|---| | string | String | | number | Double | | boolean | Bool | | void | Void | | T \| null | T? | | object | YolkValue |

Regenerating

Run codegen whenever the spec changes. The output files are marked // Generated by Yolk codegen — do not edit and should not be modified by hand. Commit them alongside the spec.