§8 Compilation model
This chapter defines how Bynk sources are organised into a project, how a unit’s name relates to its file, and the pipeline that turns sources into type-correct TypeScript. Emission itself — what each construct compiles to — is §7.
§8.1 The manifest
Section titled “§8.1 The manifest”A bynk.toml file at a directory’s root marks it as a project and configures
its layout. Its keys:
| Table | Key | Controls |
|---|---|---|
[project] | name, version | the project’s name and version |
[paths] | src | the directory holding source units |
tests | the directory holding test units | |
out | the default output directory | |
[fmt] | indent, max_line_width | formatter settings (consumed by bynkc fmt) |
[lsp] | diagnostics_mode | language-server settings |
§8.2 Project and legacy modes
Section titled “§8.2 Project and legacy modes”Bynk compiles in one of two modes.
Project mode — a bynk.toml is present. Source units live under [paths].src
and test units under [paths].tests. This is the mode that supports a
src/tests split and bynkc test.
Legacy mode — no manifest. A single .bynk file compiles as one standalone
unit. The project-only features — the src/tests split and bynkc test —
require project mode.
§8.3 Source layout
Section titled “§8.3 Source layout”In project mode a unit’s file path MUST mirror its qualified name. A
context commerce.orders MUST live at src/commerce/orders.bynk, and a
test commerce.orders at tests/commerce/orders.bynk. A path that does not match
the declared name is rejected (bynk.project.inconsistent_commons_name,
bynk.project.inconsistent_test_path), as is a name declared as both a commons
and a context (bynk.project.kind_conflict). The source tree therefore mirrors
the program’s architecture.
§8.4 Build pipeline & conformance to TypeScript
Section titled “§8.4 Build pipeline & conformance to TypeScript”A build runs the pipeline lex → parse → resolve → check → emit. The first four stages establish well-formedness (§3–§5); only a well-formed program reaches emission (§7).
Emission writes, into the output directory, the per-context and per-test modules,
the composition root, the runtime library (§7.4), and a
generated tsconfig.json. Every emitted module imports the runtime as
./runtime.js (or ../runtime.js by directory depth). The tsconfig.json
enables strict and targets ES2022 with NodeNext module resolution.
First-party commons (v0.20b). Alongside the injected first-party
adapters (the bynk surface and platform adapters,
§7.3.6), the toolchain ships first-party
library units inside the reserved bynk.* prefix: bynk.list and
bynk.map, ordinary commons written in Bynk over the collection kernel
(§5.10). A project that
uses bynk.list (or bynk.map, which itself uses bynk.list) has the unit
injected as a synthetic source file ahead of grouping; it then flows through
the ordinary commons pipeline — tables, uses resolution, type-checking,
and emission to bynk/list.ts / bynk/map.ts beside the other modules.
Unconsumed, nothing is injected and the output is unchanged.
v0.22a adds bynk.string on the same path (uses bynk.string →
bynk/string.ts): derived helpers written in Bynk over the string
kernel (§5.2) — currently
join(parts: List[String], sep: String) -> String. The kernel operations
themselves are compiler built-ins, not commons functions.
A successful Bynk build emits TypeScript that is type-correct end to end: it
compiles under tsc --strict with no errors. This is the final gate of the
compilation model — a Bynk program’s well-formedness is realised, not merely
asserted, in a type-checked TypeScript program. bynkc test continues past this
gate, running the compiled, aggregated test runner on Node.
§8.5 The platform axis
Section titled “§8.5 The platform axis”The deploy platform (--platform, values cloudflare — the default — and
node) is a selection axis distinct from the emit topology (--target {bundle,workers}, §7.2): the target chooses how the
output is laid out, the platform chooses which host the ambient surface binds
to. The platform selects the first-party bynk binding module linked into the
output (bynk-cloudflare.ts / bynk-node.ts,
§7.3.6). Because the bynk contract names canonical
provider symbols, changing platform changes only that one imported module;
porting Bynk to a new host means supplying this one binding.
As of v0.19 the axis also carries the platform lock: a deployment unit
whose closure reaches a platform-native capability MUST be built with the
matching --platform
(§5.8).
§8.6 Binding modules & npm dependencies
Section titled “§8.6 Binding modules & npm dependencies”An adapter’s binding "<module>" path is resolved relative to the adapter’s
source file; the module is copied verbatim into the output tree beside the
adapter’s emitted module, so the composition root’s import resolves and the
tsc --strict gate of §8.4 checks the binding’s implements contract. The
union of all adapters’ pinned requires entries
(§5.8) is emitted as the
dependencies map of a generated package.json; a project with no requires
emits none.