Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
name: Generator support drift
name: Language support drift

# `reference/generator-support.md` carries a copy of generation's
# `FEATURES.md`: the matrix its conformance suite proves. This checks the copy
# is current. Like the IDL drift check it needs no Rust build, only a fetch,
# The Reference -> Languages pages are rendered from generation's
# `features.json`: what its conformance suite proves. This checks they're
# current. Like the IDL drift check it needs no Rust build, only a fetch,
# so it runs per pull request. It's kept separate from the Docs workflow,
# because a fetch from another repo shouldn't be able to block a deploy.

Expand All @@ -13,16 +13,16 @@ on:
- cron: '45 7 * * 1'
pull_request:
paths:
- 'docs/docs/reference/generator-support.md'
- 'scripts/sync-generator-support.py'
- '.github/workflows/generator-support-drift.yml'
- 'docs/docs/reference/languages/**'
- 'scripts/sync-language-support.py'
- '.github/workflows/language-support-drift.yml'
workflow_dispatch:

permissions:
contents: read

concurrency:
group: generator-support-drift-${{ github.ref }}
group: language-support-drift-${{ github.ref }}
cancel-in-progress: true

jobs:
Expand All @@ -38,9 +38,9 @@ jobs:
- name: Check for drift
shell: bash
run: |
if ! python3 scripts/sync-generator-support.py --check | tee drift.txt; then
if ! python3 scripts/sync-language-support.py --check | tee drift.txt; then
{
echo '### Generator support drift'
echo '### Language support drift'
echo
echo '```'
cat drift.txt
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/guide/idl/validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
without a default, or an undeclared `params.*` reference all fail the build. Generated **Rust** code then
[runs them](#in-generated-code). Generated TypeScript doesn't yet: it
generates the types without the checks, and `comline generate` warns. See
[Generator support](../../reference/generator-support.md).
[TypeScript's language reference](../../reference/languages/typescript.md#code-generation).

A **validator** is a named, parameterised check you attach to a
[struct](structure.md) or [error](error.md) field, or to a
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ parse → resolve imports → validate → (freeze into .comline/) → (generate
| `comline clean [--dry-run]` | Remove generated code (the `generate` output root or files). Never touches `.comline/`. |
| `comline reset [--force] [--dry-run]` | **Destructive.** Delete `.comline/` — the whole version history, no undo — *and* generated code. Next `build` starts over at `0.0.1`. On a terminal it shows how many versions will be lost and makes you type `reset`; without a terminal it refuses (exit `2`) unless `--force`. |
| `comline completions <shell>` | Print a completion script to stdout. `bash` `zsh` `fish` `powershell` `elvish`. |
| `comline targets [--features [--json]]` | Print one `language#version` per line to stdout — the token syntax `config.idp`'s `code_generation.languages` expects — for every generator this binary was compiled with. Ignores `--path`: it reflects the build, not a project. `--features` also lists what each generator supports, feature by feature ([Generator support](generator-support.md)); `--json` prints that as JSON. |
| `comline targets [--features [--json]]` | Print one `language#version` per line to stdout — the token syntax `config.idp`'s `code_generation.languages` expects — for every generator this binary was compiled with. Ignores `--path`: it reflects the build, not a project. `--features` also lists what each generator supports, feature by feature ([Languages](languages/index.md)); `--json` prints that as JSON. |

`--out` / `--layout` / `--mode` override one target and need `--target` when
several are configured. `COMLINE_GENERATE_OUT` / `_LAYOUT` / `_MODE` do the same
Expand Down
75 changes: 0 additions & 75 deletions docs/docs/reference/generator-support.md

This file was deleted.

81 changes: 81 additions & 0 deletions docs/docs/reference/languages/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Languages

What Comline supports in each target language. Every language has its own
page, with what its **code generator** emits and, once runtime conformance
covers it, what its **runtime** speaks on the wire. The matrix below compares
the code generators side by side.

Nothing here is written by hand. Each entry comes from a conformance suite,
which checks the claim against what the generator actually does, so a
language page can't claim something that isn't true.

## What the states mean

| State | Generating a schema that uses the feature |
|---|---|
| ✅ **supported** | Works. |
| 🟡 **partial** | Works, with the limit the note states. |
| ⚪ **ignored** | Succeeds, but the output is what it would be without the feature: the types are right, the feature has no effect. `comline generate` warns, and so does the editor. |
| ❌ **unsupported** | Is refused, with an error naming every use. The editor warns at each use. |

## How a claim is proven

Each generator states its support in a `SUPPORT` table in its own crate. The
conformance suite in
[`ComlineProject/generation`](https://github.com/ComlineProject/generation)
runs every generator over a corpus of schemas and checks each claim against
what the generator actually does:

- **supported** or **partial**: a schema in the corpus uses the feature,
generates, and matches its checked-in output. Where the feature can be taken
out of the schema, the output must change without it; otherwise the feature
is really being ignored.
- **ignored**: the output is identical with the feature taken out, apart from
the IR hash, which names the schema.
- **unsupported**: every schema using the feature is refused, with an error
naming the feature.

A claim that no schema in the corpus can back fails the suite. So a new
feature, or a generator that gains one, comes with a schema that proves it.
The proving schemas are named in each cell below.

## Code generation, side by side

<!-- matrix:start -->
<!-- Rendered from ComlineProject/generation's features.json by scripts/sync-language-support.py - don't edit by hand. -->

| Feature | [rust 1.70.0](rust.md) | [typescript 5.0](typescript.md) |
|---|---|---|
| structs <br><sub>`structs`</sub> | ✅ supported | ✅ supported |
| enums <br><sub>`enums`</sub> | ✅ supported | ✅ supported |
| optional fields <br><sub>`optional-fields`</sub> | ✅ supported | ✅ supported |
| arrays <br><sub>`arrays`</sub> | ✅ supported | ✅ supported |
| fixed-length arrays <br><sub>`fixed-arrays`</sub> | ✅ supported | 🟡 partial: rendered as `T[]`: the length isn't part of the type |
| fixed arrays over 32 elements, nested <br><sub>`large-fixed-arrays-nested`</sub> | ❌ unsupported: a fixed array over 32 elements renders only as a struct or error field's own, non-optional type (serde's derive stops at 32) | 🟡 partial: rendered as `T[]`: the length isn't part of the type |
| unions <br><sub>`unions`</sub> | ❌ unsupported: Rust has no anonymous sum type to render one as | ✅ supported |
| type aliases <br><sub>`type-aliases`</sub> | ✅ supported | ✅ supported |
| constants <br><sub>`constants`</sub> | ✅ supported | ✅ supported |
| protocols <br><sub>`protocols`</sub> | ✅ supported | ✅ supported |
| errors <br><sub>`errors`</sub> | ✅ supported | ✅ supported |
| functions that throw <br><sub>`throws`</sub> | ✅ supported | ✅ supported |
| validators <br><sub>`validators`</sub> | ✅ supported | ⚪ ignored: the types are generated; the checks aren't run yet ([core#96](https://github.com/ComlineProject/core/issues/96)) |
| imports between schemas <br><sub>`imports`</sub> | ✅ supported | ✅ supported |
| nested namespaces <br><sub>`nested-namespaces`</sub> | ✅ supported | ✅ supported |
| `lib` mode <br><sub>`lib-mode`</sub> | ✅ supported | ✅ supported |
| `external_std` <br><sub>`external-std`</sub> | ✅ supported | ✅ supported |
| `validate_on_decode` <br><sub>`validate-on-decode`</sub> | ✅ supported | ⚪ ignored: no checks are generated to run on decode yet ([core#96](https://github.com/ComlineProject/core/issues/96)) |
| JSON-RPC framing <br><sub>`framing-jsonrpc`</sub> | ✅ supported | ✅ supported |

<!-- matrix:end -->

## Elsewhere

- `comline targets --features` prints the code generation support for the
generators your `comline` was built with, and `--json` prints it as JSON (see
the [CLI](../cli.md)).
- In the editor, a schema using a feature that a language declared in
`config.idp` can't generate gets a warning at the use. Hovering the language
in `config.idp` shows what its generator supports.
- Each generator's repository README carries its own table:
[comline-rust](https://github.com/ComlineProject/comline-rust#features),
[comline-typescript](https://github.com/ComlineProject/comline-typescript#features).
45 changes: 45 additions & 0 deletions docs/docs/reference/languages/rust.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Rust

What Comline supports in Rust, as its conformance suites prove it. For how
to use it, see the [Rust guide](../../languages/rust/index.md). The states are explained in the
[overview](index.md#what-the-states-mean).

## Code generation

What the [`comline-rust`](https://github.com/ComlineProject/comline-rust) generator emits
for each language feature, and the conformance fixtures that prove it.

<!-- codegen:start -->
<!-- Rendered from ComlineProject/generation's features.json by scripts/sync-language-support.py - don't edit by hand. -->

Generator `rust#1.70.0`.

| Feature | What it covers | State | Proven by |
|---|---|---|---|
| structs <br><sub>`structs`</sub> | `struct` declarations | ✅ supported | `primitives`, `optional_and_arrays`, `type_refs`, `shapes`, `cross_schema`, `import_alias`, `import_glob`, `nested_namespace`, `external_std`, `validators`, `validators_on_decode` |
| enums <br><sub>`enums`</sub> | `enum` declarations | ✅ supported | `enum_basic` |
| optional fields <br><sub>`optional-fields`</sub> | fields marked `optional` | ✅ supported | `optional_and_arrays`, `type_refs`, `shapes`, `cross_schema`, `validators`, `validators_on_decode` |
| arrays <br><sub>`arrays`</sub> | variable-length arrays, `T[]` | ✅ supported | `optional_and_arrays`, `type_refs`, `shapes`, `cross_schema`, `validators`, `validators_on_decode` |
| fixed-length arrays <br><sub>`fixed-arrays`</sub> | fixed-length arrays, `T[N]` | ✅ supported | `shapes` |
| fixed arrays over 32 elements, nested <br><sub>`large-fixed-arrays-nested`</sub> | a `T[N]` with N over 32 anywhere but a field's own, non-optional type: inside another array, optional, an alias, an argument or a return | ❌ unsupported: a fixed array over 32 elements renders only as a struct or error field's own, non-optional type (serde's derive stops at 32) | `large_fixed_arrays_nested` |
| unions <br><sub>`unions`</sub> | `union(A B ...)` types | ❌ unsupported: Rust has no anonymous sum type to render one as | `unions` |
| type aliases <br><sub>`type-aliases`</sub> | `type Name = ...` declarations | ✅ supported | `validators`, `validators_on_decode` |
| constants <br><sub>`constants`</sub> | `const` declarations | ✅ supported | `constant`, `shapes`, `validators`, `validators_on_decode` |
| protocols <br><sub>`protocols`</sub> | `protocol` declarations and their functions | ✅ supported | `protocol`, `error_shapes`, `validators`, `validators_on_decode`, `framing_jsonrpc` |
| errors <br><sub>`errors`</sub> | `error` declarations | ✅ supported | `protocol`, `error_shapes` |
| functions that throw <br><sub>`throws`</sub> | functions declared with `! Error` | ✅ supported | `protocol`, `error_shapes` |
| validators <br><sub>`validators`</sub> | `@validators` on fields and type aliases, checked in generated code | ✅ supported | `validators`, `validators_on_decode` |
| imports between schemas <br><sub>`imports`</sub> | `use` of another schema's declarations | ✅ supported | `cross_schema`, `import_alias`, `import_glob`, `nested_namespace`, `external_std`, `validators`, `validators_on_decode` |
| nested namespaces <br><sub>`nested-namespaces`</sub> | schemas in subdirectories (`chat::admin`) | ✅ supported | `nested_namespace`, `external_std`, `validators`, `validators_on_decode` |
| `lib` mode <br><sub>`lib-mode`</sub> | `--mode lib`: a buildable package, not bare source files | ✅ supported | `nested_namespace`, `external_std` |
| `external_std` <br><sub>`external-std`</sub> | `[generate] external_std`: `std` referenced as its own package | ✅ supported | `external_std` |
| `validate_on_decode` <br><sub>`validate-on-decode`</sub> | `[generate] validate_on_decode`: decoding runs the checks | ✅ supported | `validators_on_decode` |
| JSON-RPC framing <br><sub>`framing-jsonrpc`</sub> | `@framing = "jsonrpc"` (or as the package default) | ✅ supported | `framing_jsonrpc` |

<!-- codegen:end -->

## Runtime

Not yet covered by conformance. Runtime conformance checks each runtime against
shared, byte-exact wire examples (the handshake, the envelopes, each framing
and each wire format). This section lists the result once it covers Rust.
Loading
Loading