comline.toml
Consumer-owned configuration for comline generate: where generated code goes,
in what layout, in what form, and for which package versions. It is committed,
never frozen, and never part of a published package. With no comline.toml (or
an all-commented one) the defaults below apply and targets come from
config.idp's code_generation.languages.
For the task-oriented walkthrough see Generating code.
[generate]
Defaults for every target.
| Key | Type | Default | Meaning |
|---|---|---|---|
out |
string (path) | "generated" |
Output root, relative to comline.toml. |
layout |
string (template) | "{{language}}/{{namespace}}.{{ext}}" |
Path of each generated file under out. Handlebars, strict. |
mode |
"code" | "lib" | "dylib" |
"code" |
Emit form. code and lib are implemented for rust and typescript; dylib is planned — see Library generation. |
package_versions |
"latest" | "all" | list |
"latest" |
Which package versions to emit — see below. |
external_std |
bool | on in lib, off in code |
Reference std as its own package instead of inlining it — see below. |
validate_on_decode |
"off" | "collect" | "first" |
"off" |
Whether decoding a value runs its @validators — see below. |
async |
bool | false |
Generate protocols on a connection for an async driver — see below. |
only |
list of strings | — | Generate just these languages, out of the ones config.idp declares — see below. |
[[generate.target]]
One block per declared language you want to configure. Any key from
[generate] may be repeated here to override it for that language only.
A block configures a language; it does not choose which languages are
generated. That comes from config.idp alone — a declared language with no
block takes the [generate] defaults, several blocks for one language give
several outputs, and a block naming a language the congregation doesn't
declare is an error. To generate fewer than the package declares, use
only.
| Key | Type | Meaning |
|---|---|---|
language |
string | Required. Must be one the manifest declares under code_generation.languages. |
lang_version |
string | Optional; the toolchain version to generate for. Defaults to what config.idp declared, and may raise it but never lower it (Language versions). |
out, layout, mode, package_versions, external_std, validate_on_decode, async |
— | Per-target override of the [generate] value. |
flatten |
bool | lib/dylib only, target-only (no [generate] default): write the crate straight into out instead of out/<language>/. See below. |
[generate]
out = "generated"
layout = "{{language}}/{{namespace}}.{{ext}}"
[[generate.target]]
language = "rust"
lang_version = "1.88.0"
out = "src/generated"
flatten
layout only governs code mode's one-file-per-schema paths — a lib-mode
target ignores it entirely (comline generate warns if one is set) and
always writes the crate's fixed internal shape (Cargo.toml, src/lib.rs, a
file per schema under src/) rooted at out/<language>/, so two lib
targets can safely share one out without their files colliding.
A target with its own dedicated out doesn't need that disambiguation —
flatten = true skips it, writing the crate straight into out:
[[generate.target]]
language = "rust"
mode = "lib"
out = "../my-rust-crate/"
flatten = true # crate lands at out/, not out/rust/
Only set this when the target's out is exclusively its own — flattening a
shared out across more than one lib target reintroduces the collision
the default layout avoids.
external_std
Comline's standard library is implicitly available to every package, so
std/http and std/validators are part of every generation request. This
decides whether their code is copied into your generated output or
referenced from std's own pre-generated package:
| Language | Package |
|---|---|
rust |
comline_std (a crate, pinned by git rev) |
typescript |
@comline/std (an npm package, by semver range) |
It defaults to on in lib mode — a buildable package should depend on std
rather than vendor it — and off in code mode, which has no manifest to
declare a dependency in. In code mode with it on, the generated file names
what to install in a comment at the top.
--external-std and --no-external-std override it for one run.
Neither package is published yet, so a lib target that references one needs
it linked locally (npm link, a path override) until that changes — which is
already true of @comline/runtime for any package with a protocol.
validate_on_decode
Generated code always carries a schema's @validators
checks as validate() / validate_first(), for you to call. This decides
whether decoding calls them too:
| Value | Decoding a value that fails its checks |
|---|---|
"off" |
succeeds; nothing runs until you call validate() |
"collect" |
fails, with every failed check |
"first" |
fails, with the first failed check |
It's yours to choose rather than the schema's: it changes what decoding costs, and a form that wants every problem at once and a hot path that wants to stop early want different things from the same type. With it on, a provider also refuses a call whose arguments fail their checks, the same way it refuses arguments that don't decode.
Today only the rust generator runs validators; typescript ignores this.
--validate-on-decode and COMLINE_GENERATE_VALIDATE_ON_DECODE override it.
async
A protocol on a connection
is generated for a blocking driver by default. async = true generates it for
an async one instead:
rust: async handlers,<Proto>AsyncDispatcherand<Proto>AsyncSender, and an async packageserve/accept/connect, for the runtime'sAsyncConnectionon any executor — see Rust connections. Alibpackage turns on the runtime'sasyncfeature.typescript: nothing changes; its handlers and senders return Promises either way.
Every protocol is on a connection unless it's lockstep (the datagram
framing, or JSON-RPC with no client-provided protocol); those are the same
either way, and comline generate warns when async = true changes nothing. Like
external_std, it's a consumer's choice: the same package can be generated
async for one application and blocking for another.
only
Generate a subset of the languages config.idp declares, for a checkout that
doesn't need all of them:
A name the congregation doesn't declare is an error, so a typo fails loudly
instead of quietly generating nothing. --target narrows a single run the
same way.
This is also the escape hatch when a declared language has no generator in
your comline build: declaring a language means you mean it, so a missing
generator is an error rather than a silent skip, and only is how you say
you want fewer.
Layout variables
| Variable | Value |
|---|---|
{{language}} |
target language, e.g. rust |
{{namespace}} |
the schema's namespace, /-joined |
{{ext}} |
the generator's file extension, e.g. rs |
{{lang_version}} |
the declared language / toolchain version |
{{spec_version}} |
the manifest's specification_version |
{{package_version}} |
the package version being generated (see below) |
package_versions
| Value | Effect |
|---|---|
"latest" (default) |
The working tree only. No .comline/ read. {{package_version}} is the last committed version (empty if never built). |
"all" |
Every release in the project's history (not the builds between them). |
["0.3.0", "0.4.0"] |
Exactly those versions: releases, builds (0.3.0-dev.2) or commit hashes. |
Anything but "latest" reads the content-addressable store, so the project must
have been built at least once. Selecting more than one version requires
{{package_version}} in layout — otherwise every version writes to the same
paths. Old schemas are emitted with the current generator.
[generate]
package_versions = "all"
layout = "{{language}}/{{package_version}}/{{namespace}}.{{ext}}"
default_framing (moved)
The framing is part of the schema, since both ends have to agree on it, so it
moved to the package: config.idp's wire = { framing = "..." }
(Wire defaults). A
default_framing, in [generate] or in a target, is an error that names the
line to write there instead:
`default_framing` moved from comline.toml to config.idp
help: drop it here, and declare the package's framing in config.idp:
wire = { framing = "jsonrpc" }
Precedence
Lowest to highest, applied field by field:
COMLINE_GENERATE_OUT/COMLINE_GENERATE_LAYOUT/COMLINE_GENERATE_MODE— apply to every target (a CI global). Empty values are ignored.--out/--layout/--mode— apply to one target and need--targetwhen more than one is configured.