Problem
tdbin is only half a wire format if only one language can speak it. A binary IPC channel needs at least two ends, and for us the second end is TypeScript — the VS Code extension and its webview UI consume every wire type in live-ipc.td.
Three separate blockers stop that today.
1. No CLI path
$ typediagram --help
…
TDBIN encode emits a generated Rust ADT+codec module; decode emits codec impls
for generated Rust ADTs; verify validates schema support.
docs/tdbin.html confirms it:
"Generation requires using the Node.js API programmatically since the current CLI has TDBIN commands for Rust only."
Our codegen is a single script that shells out to the typediagram binary once per target (--to rust, --to typescript) and post-processes the output. Requiring a bespoke Node API integration for the TS half — while the Rust half is a CLI call — means two different generation mechanisms for one schema. Please expose TS codec generation through the same CLI surface, e.g. typediagram encode --lang typescript.
2. Lists are unsupported, and our payloads are almost entirely lists
docs/tdbin.html, TypeScript support boundary:
Not yet supported: "lists, scalar Option<T>, semantic scalars (DateTime, Uuid, Decimal), generics, inline enum-unions"
Every top-level payload we send is list-shaped:
type Report {
action_hints: List<ActionHint>
boilerplate_hints: List<ReportBoilerplateHint>
clusters: List<ReportCluster> # 712 of these in our own repo
…
}
type ReportCluster {
occurrences: List<ReportOccurrence> # 1688 total
…
}
type ReportPage { clusters: List<ClusterSummary> }
type ReportDelta { clusters_added: List<ReportCluster>, clusters_removed: List<String>, … }
type MergePlan { parameters: List<MergeParameter> }
type MergeParameter{ per_site_arguments: List<String> }
Scalar Option<T> is likewise everywhere (min_score: Option<Float>, dimensions: Option<Int>, since_generation: Option<Int>). The Rust emitter already handles both — w.child_list / r.child_list::<T> and presence bits — so this is parity work, not new design.
3. number instead of bigint for Int
Per docs/tdbin-future-typescript.html, the TS value model still uses number for 64-bit integers. Our Int fields are byte offsets, line numbers, and generation counters — currently safe, but a format whose whole premise is exactness should not silently truncate at 2^53 on one end of the wire and not the other. Round-tripping Rust i64 → TS number → Rust i64 must be lossless or the schema hash guarantees mean nothing.
Ask
typediagram encode/decode accept a language flag; TypeScript is a first-class target.
- TS codec parity with Rust for:
List<T> (scalar, string, and composite element kinds), scalar Option<T> presence bits, and inline enum-unions.
bigint for Int, with the migration documented.
- Publish the TS runtime as a resolvable entry point (
typediagram-core/tdbin) with the same version-pinning story as the Rust crate, and state its bundle-size cost — a VS Code webview pays for every byte.
- Golden-vector conformance tests that run Rust-encode → TS-decode and TS-encode → Rust-decode over a schema containing lists and optional scalars, not just the Person/Contact fixtures.
Context
Deslop ships a VS Code extension, a JetBrains plugin, and two Rust servers, all generated from one .td file. Rust-only tdbin would let the servers talk to each other but force the editor clients to stay on JSON — meaning we would maintain two wire encodings for one schema forever. That is worse than staying on JSON.
Problem
tdbin is only half a wire format if only one language can speak it. A binary IPC channel needs at least two ends, and for us the second end is TypeScript — the VS Code extension and its webview UI consume every wire type in
live-ipc.td.Three separate blockers stop that today.
1. No CLI path
docs/tdbin.htmlconfirms it:Our codegen is a single script that shells out to the
typediagrambinary once per target (--to rust,--to typescript) and post-processes the output. Requiring a bespoke Node API integration for the TS half — while the Rust half is a CLI call — means two different generation mechanisms for one schema. Please expose TS codec generation through the same CLI surface, e.g.typediagram encode --lang typescript.2. Lists are unsupported, and our payloads are almost entirely lists
docs/tdbin.html, TypeScript support boundary:Every top-level payload we send is list-shaped:
Scalar
Option<T>is likewise everywhere (min_score: Option<Float>,dimensions: Option<Int>,since_generation: Option<Int>). The Rust emitter already handles both —w.child_list/r.child_list::<T>and presence bits — so this is parity work, not new design.3.
numberinstead ofbigintforIntPer
docs/tdbin-future-typescript.html, the TS value model still usesnumberfor 64-bit integers. OurIntfields are byte offsets, line numbers, and generation counters — currently safe, but a format whose whole premise is exactness should not silently truncate at 2^53 on one end of the wire and not the other. Round-tripping Rusti64→ TSnumber→ Rusti64must be lossless or the schema hash guarantees mean nothing.Ask
typediagram encode/decodeaccept a language flag; TypeScript is a first-class target.List<T>(scalar, string, and composite element kinds), scalarOption<T>presence bits, and inline enum-unions.bigintforInt, with the migration documented.typediagram-core/tdbin) with the same version-pinning story as the Rust crate, and state its bundle-size cost — a VS Code webview pays for every byte.Context
Deslop ships a VS Code extension, a JetBrains plugin, and two Rust servers, all generated from one
.tdfile. Rust-only tdbin would let the servers talk to each other but force the editor clients to stay on JSON — meaning we would maintain two wire encodings for one schema forever. That is worse than staying on JSON.