TypeScript Binding (Xantham)

TypeScript Binding via Xantham: The Persistent Analysis Substrate

Library Binding for C/C++ describes how Farscape generates Clef bindings for native libraries. This document describes the analogous concern for TypeScript surfaces. The analysis layer ingests .d.ts files and produces the structural type information consumer generators turn into bindings. Today that analysis layer is Xantham, a schema-driven extractor maintained by Shayan Habibi at shayanhabibi/Xantham.

What Xantham contributes persists across changes in the rest of the toolchain. The current binding pipeline (Xantham → F# generator → Fickl → JavaScript) and the eventual pipeline (Xantham → Clef-via-JSIR) consume the same analysis substrate. The downstream stages differ across the two pipelines; the analysis substrate is common to both.

What Xantham Analyzes, and Where It Stops

Xantham’s current generator uses the TypeScript compiler’s API server to obtain declaration and type information and produces F# bindings. Its Xantham.TypeScript.Wire package describes the compiler API protocol, while Xantham.Generator supplies the generation pipeline. See the current Xantham documentation for its supported inputs and packages.

The earlier architecture separated an extractor, a decoder and a common schema for consumers. The schema discussion below records that design and its motivation. Xantham has since evolved, so its exact project names, schema and extension points should be checked against the selected revision before implementing a new consumer. Fickl compiles the generated F# on the selected JavaScript path; it is not the name of the extractor.

The earlier design emphasized giving consumers access to analyzed type information. The current project also publishes Xantham.Generator and the xantham tool for generating F# bindings. A Clef consumer remains a design to establish against the current analysis and generator interfaces.

The multi-consumer goal continues to motivate the Clef binding direction. Its concrete interface should follow the selected Xantham revision rather than assume that the earlier JSON schema and decoder are the current API.

The Earlier Analysis Schema

In the earlier design, Xantham.Common/Common.Types.fs defined a vocabulary for representing TypeScript shapes in target-language-neutral form. These schema constructs show the information a consumer needed to carry. They are a historical reference for the current generator, not a list of its current public API:

Schema constructWhat it captures
TsType (22 cases)Every TypeScript type construct: primitives, interfaces, classes, unions, intersections, generics, type aliases, conditional types, mapped types, indexed access, type literals, template literals, predicates, type queries, etc.
TsAstNode (32 cases)Every TypeScript AST node kind that affects type information: declarations, references, members, parameters, signatures, etc.
TypeKey indirectionInteger references into a TypeMap, allowing cyclic graphs to be representable without physical nesting.
LibEsExports setThe set of TypeScript standard library exports, distinguishable from user types so consumers can route lib.es references to external resolvers rather than re-binding them.
Source path metadataThe originating .d.ts file and position, available for diagnostics and (eventually) explicit package-boundary identification.

A stable schema is what holds the multi-consumer architecture together. A consumer written today against the schema keeps working as long as the schema’s compatibility commitments hold. Consumers written for new target languages negotiate against that schema, never with the encoder directly.

Two related concerns are tracked as open work in the upstream repo:

  • Decoder behavior on MISSREF keys. The encoder logs [MISSREF] diagnostics during ingestion when it can’t bind a referenced TypeKey to a type definition, then writes the key into the JSON anyway. The decoder’s compression pass then crashes. Fixing this contract (whether by encoder stub-emission, decoder substitution, or refusing to write dangling JSON) is an open issue with consumer impact.
  • Explicit package-boundary information. Currently consumers parse Source paths to recover npm package identity; surfacing this explicitly in the schema would let consumer generators produce clean module names without ad hoc parsing.
  • Stable lib.es reference policy. Sometimes lib.es references survive cleanly to consumers; sometimes they become unresolvable MISSREF keys. A consistent policy (“lib.es references always emit by external name, never inlined”) would let consumers wire a single resolver.

These concerns are filed upstream and informed by current consumer experience. They don’t change Xantham’s role; they refine the contract it provides.

Multi-Consumer Architecture

The current Xantham.Generator produces F# bindings. Fidelity.CloudEdge uses the binding work for Cloudflare runtime SDK surfaces; see the Fidelity.CloudEdge JSIR strategic assessment for the migration context. Check generator versions and support packages for the chosen Fickl consumer.

The proposed Clef consumer, described in From Fickl to JSIR, would turn the admitted TypeScript analysis into Clef boundary declarations and evidence for the normal CCS/Baker and Alex pipeline. Its input contract must be selected with the current Xantham implementation.

The earlier downstream interface had this shape:

Xantham.Decoder.Runtime.create "input.json"
  └── XanthamTree
       ├── KeyExportMap        : exports keyed by TypeKey
       ├── ExportMap           : exports keyed by source module path
       ├── LibEsExports        : lib.es-marker set
       ├── GetArenaInterner()  : lazy resolved object graph
       └── (other accessors)

That design allowed multiple consumers to use the same analysis without changing its meaning. The current implementation’s corresponding extension point and representation need to be established from its documented API.

What Persists Across Toolchain Transitions

Xantham’s TypeScript compiler API integration makes the compiler’s understanding of declarations available to binding generation. Its treatment of libraries, cycles, overloads, and other TypeScript details gives future consumers a foundation to build on. A Clef consumer should establish which information it needs and check that the selected Xantham version carries it through.

The wire protocol and generator’s type representations connect analysis to generated bindings. A Clef consumer can build on that work while establishing a versioned contract for the information it consumes. Xantham maintains its analysis and binding-generation machinery, while consumers develop their own integrations and contribute improvements where experience exposes shared needs.

Supply Chain Boundary

Xantham uses a TypeScript compiler API server alongside its .NET-hosted generator. The compiler and its Node environment are part of the binding-generation toolchain. Generated bindings, the compiler used for an application, any bundler, and the application’s runtime dependencies each have their own supply-chain boundary.

Declaration files describe the interface being analyzed, while the compiler API server executes as part of the build. Pinning the compiler, Xantham version, declaration packages, and build-time tools makes the inputs and executable dependencies reviewable. Package installation and build scripts deserve their own review; reading declarations does not establish that the entire toolchain is free of executable dependencies.

The .NET-hosted generator and compiler tooling introduce their own dependencies, as do MLIR and LLVM. Each should be assessed according to the versions and distribution channels used for a particular build. The Fickl path and the planned Clef-to-JSIR path may have different dependencies after binding generation. Their actual dependency closures depend on the chosen compiler, libraries, and packaging tools, and should be measured for each deployment.

Connection to the Library of Alexandria

The Clef-via-JSIR pipeline introduces a curated catalog of witnessing rules, what we informally call the “Library of Alexandria” inside our Alex middle-end in Composer. Each rule characterizes how the compilation pipeline lowers a given TypeScript shape category to the right JSIR ops and ultimately the right JavaScript AST.

Those rules are characterized from Xantham’s analysis output. The encoder doesn’t write witnessing rules; that’s consumer territory. The structural information it provides (a function returns Promise<T>; this class extends another generic class with type-arg passthrough; this interface has overloaded methods, etc.) is exactly what the consumer needs to identify which Pattern from the Library applies.

As more libraries are bound via the Clef-via-JSIR pipeline, the Library of Alexandria matures: D3’s chained-method-builder pattern, SolidJS’s reactive primitives, TanStack’s hook-with-options pattern. The patterns recur across libraries; the Library accumulates them. Xantham provides the source material. The consumer maps that source to a pattern, and the rule library grows with each new library characterized.

Fickl output for a Xantham-analyzed TypeScript surface can provide useful behavioral examples for the Clef path. Tests and explicit boundary contracts must establish which observations the two paths should share, including cases where their generated code differs.

Practical Considerations

For the medium-term horizon (months through end of year and beyond), Xantham’s role is operational:

  • Track upstream stability. Pin the relevant Xantham interfaces and coordinate breaking changes with their consumers.
  • Pin versions per binding. Each Fidelity.CloudEdge binding (workers-types, agents, dynamic-workflows) pins to a specific Cloudflare SDK version and is regenerated as that source changes. Xantham analysis is reproducible against pinned inputs.
  • Contribute back where the contract is being defined. Revisit reference resolution, package-boundary metadata, and standard-library policy against the current implementation. Improvements to shared analysis can benefit all consumers.
  • The Fickl+F# consumer continues. Fidelity.CloudEdge ships against the F# binding pipeline today and through the JSIR transition. The eventual rename to FSharp.CloudEdge (when that lands) doesn’t affect Xantham consumption. The F# binding pipeline serves F# users indefinitely.

The Long Arc

The analysis capability described in this document has further forms beyond the document’s planning horizon. Our Atelier IDE anticipates a polyglot ingestion feature called Transcribe (see Atelier docs/10_transcribe.md) that would handle many source languages (F#, Python, Rust, Go, TypeScript / JavaScript, C / C++) as a unified IDE workflow producing matched (Clef binding + Alex lowering witness) pairs. Xantham is the analysis substrate Transcribe consumes for the TypeScript / JavaScript case. Farscape covers C / C++, and other substrates cover their own languages.

Transcribe and Atelier are where the analysis-substrate framing points; their details belong to that work to settle. The current plan sets up the long arc without committing to its specifics: Xantham as a standalone tool, shared analysis for multiple consumers, and explicit versioned boundaries. Xantham continues being maintained as a standalone analysis tool by Shayan Habibi for the medium-term horizon. How the eventual IDE-side coordination layer consumes it (and how the parallel substrates for other languages do the equivalent thing) is Atelier’s territory to design and document.

Cross-references