Skip to content

The axion CLI

Code generation is a single command. It reads *.contract.ts files and emits committed, readable Kotlin or Swift — no hidden directories, no Nitrogen for feature code. Generated files are committed to the repo; there is no Gradle task or Xcode build phase that runs the CLI automatically.

Terminal window
axion bridgekit generate --contracts 'src/**/*.contract.ts' --out-dir bridgekit/generated
FlagDefaultPurpose
--contracts <glob>**/*.contract.tsGlob for contract files (cwd-relative; excludes node_modules, /dist/).
--out-dir <path>bridgekit/generatedOutput directory for generated files and bridgekit.lock. Created recursively if absent.
--platform <kotlin|swift>kotlinTarget language. Drives the emitter. Any other value is a hard CliError at parse.
--package <pkg>derived from idKotlin package override (default axion.bridgekit.contracts.<id>). Ignored by the Swift emitter.
--checkDiff against existing output; exit 1 on drift (CI mode). Writes nothing.
--into <path>After writing to --out-dir, cpSync every generated file (including the lock) to this path. Must pre-exist.

Per contract, the generator writes one <PascalName>Contract.kt containing:

  • Shared object types (data class, sealed class, enum class)
  • interface <ClassName> — the provider interface
  • interface <ClassName>Client — the consumer/RN-side interface
  • private object <ClassName>Codecs — encode/decode to plain Map<String, Any?>
  • object <ClassName>Contract : BridgeContractDefinition<…>id, contractHash, memberHashes, inbound(), outbound()

See Anatomy of generated Kotlin for a full dissection.

Both platforms share a single bridgekit.lock file. The lock carries a platform field ("kotlin" or "swift") that records which emitter produced it.

Terminal window
# Default: Kotlin, bridgekit/generated/
axion bridgekit generate
# Explicit contract glob + custom output dir
axion bridgekit generate --contracts 'src/**/*.contract.ts' --out-dir android/bridgekit
# Swift output
axion bridgekit generate --platform swift --out-dir ios/contracts/generated
# Cross-repo mirror (Kotlin)
axion bridgekit generate --into ../Android.Application/features/lia/bridgekit
# Cross-repo mirror (Swift)
axion bridgekit generate --platform swift \
--out-dir ios/contracts/generated \
--into ../iOS.Application/lia/contracts

--into makes the cross-repo copy tool-owned rather than a manual cp. The directory must pre-exist. See Drift & cross-repo delivery for the full workflow.

The CLI detects the authoring style and loads each accordingly — both produce the same serializable descriptor ($type tag + descriptorVersion, duck-typed, never instanceof).

The CLI spawns a child ESM subprocess (--experimental-strip-types), imports the .ts file via a worker, duck-types the exports for { descriptor, hash }, and serializes to JSON.

Marker type parameters are erased at runtime, so they cannot be read by importing. Marker contracts are detected by a regex for Sync<, Async<, Void<, Stream<, State< in value position and parsed with ts-morph: it loads the type checker, injects a stub for @axion/bridgekit/contract, then walks the defineContract AST to extract params/result types from the generic arguments. No subprocess required.

Before loading, the CLI walks the import graph. Any import other than @axion/bridgekit/contract or a relative contract path is a hard error with file:line. This guarantees contracts are safe to import under Node, Jest, and web builds.

Terminal window
axion bridgekit generate \
--contracts 'src/**/*.contract.ts' \
--out-dir bridgekit/generated \
--check

--check compares against the last generated files and exits non-zero on any drift. The drift message labels the platform explicitly:

Drift detected in generated Kotlin bindings:
AxionHostContract.kt: content differs
Run `axion bridgekit generate` to regenerate and commit the result.
Drift detected in generated Swift bindings:
AxionHostContract.swift: content differs
Run `axion bridgekit generate --platform swift` to regenerate and commit the result.

Wire it into CI so contract changes and regenerated output always land together.