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
20 changes: 2 additions & 18 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,8 @@ and each CI job runs exactly one `gha::` recipe (`just ci` = exactly CI;
affect; the full pass before commit is:

```sh
just gates # everything below, in this order
```

```sh
just build test-rust # cargo build --workspace; translator-shim/bindgen/testgen tests
just test-runtime # runtime check + tests (deps: shim, fixtures, corpus)
just test-protocol
just test-wasi test-ct-runner
just test-sockets-node # sockets fragment's node backend on pinned Node
just test-bundle # embedder-bundle release asset
just publish-check # deno publish --dry-run: the JSR publish checks, no upload
just examples test-translate # embedder examples; build-time translation CLI
just conformance # official CM suite, Deno lane
just sched-seeds # seeded-shuffle reruns: POLYENGINE_SCHED_SEED=1, =4242 (FIFO when unset)
just shells # pinned engine/runtime lanes: sm + node everywhere, jsc on x64, bun findings-only
just browsers # chromium + firefox lanes incl. worker/shared-worker realm rows (`just browsers-install` once)
just smoke-tls # polymorph-tls suite (issue #18)
just smoke-c0 # consumer smoke legs
just gates # everything below, in this order; see the justfile (or
# `just --list`) for the recipe list and per-gate one-liners
```

Conformance discipline: the harness fails loudly on unexpected failures *and*
Expand Down
37 changes: 4 additions & 33 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion contracts/digest.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

The digest is the skew-protection handshake of docs/architecture.md §9: bindings generated
from WIT embed an expected digest; the generated typed `instantiate` recomputes
it from the loaded plan and fails fast with a structural diff on mismatch,
it from the loaded plan and fails fast on mismatch,
before any guest code runs (contracts/embedder-api.md §"Module wiring and
instantiation" — the runtime's untyped `instantiate` names no world, so it
does not verify). A digest match must imply ABI-shape compatibility for
Expand Down
29 changes: 5 additions & 24 deletions crates/bindgen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,11 @@ name = "bindgen"
path = "src/lib.rs"

[dependencies]
# Version pinning (docs/architecture.md §9 pins wit-parser to the wasmtime-environ
# cadence): wasmtime-environ =47.0.3 (crates/translator-shim) pins
# wasmparser 0.252.0 exactly. wit-parser and wasmparser are released in
# lockstep as part of the wasm-tools workspace (same version number across
# the whole workspace's crates), so wit-parser's version number IS the
# wasm-tools release train version. There is no wit-parser 0.252.0 release
# whose *wit-bindgen-core* counterpart also exists (wit-bindgen has its own,
# slower release cadence and vendors a specific wasm-tools/wit-parser
# version per release — see wit-bindgen-core's own Cargo.toml pins).
# Surveyed via `cargo add --dry-run` against the crates.io index:
# wit-bindgen-core 0.55.0 -> wit-parser 0.246.2 (wasmparser 0.246.2)
# wit-bindgen-core 0.58.0 -> wit-parser 0.251.0 (wasmparser 0.251.0)
# wit-bindgen-core 0.60.0 -> wit-parser 0.254.0 (wasmparser 0.254.0)
# 0.251.0 is one release behind wasmtime-environ's 0.252.0 pin (0.254.0
# would be two releases ahead). Picked the nearest-and-not-newer pair
# (0.58.0 / 0.251.0): WIT feature-resolution semantics for a slightly older
# wasm-tools release are a subset of a newer one, so parsing our fixture
# corpus (no bleeding-edge WIT features) is unaffected; being *behind*
# wasmtime-environ is the conservative direction (never claims to resolve a
# feature wasmtime's frontend doesn't also know about). Bump both together
# when translator-shim's wasmtime-environ pin moves and a matching
# wit-bindgen-core release exists.
wit-parser = { version = "=0.251.0", features = ["serde"] }
wit-bindgen-core = "=0.58.0"
# wit-parser is pinned to match crates/translator-shim's wasmparser pin
# exactly (docs/architecture.md §9): both ride the wasm-tools workspace's
# lockstep release train, so a single version number covers both crates.
# Bump this pin together with translator-shim's wasmtime-environ pin.
wit-parser = { version = "=0.252.0", features = ["serde"] }
anyhow = "1"
sha2 = { version = "0.10", default-features = false, features = ["std"] }
serde = { version = "1", features = ["derive"] }
Expand Down
23 changes: 13 additions & 10 deletions crates/bindgen/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,24 @@
//! behavior is emitted or assumed to exist yet (the runtime's own facade is
//! a separate crate) — every generated file must `deno check` standalone.
//!
//! Built on `wit_bindgen_core::Source`/`Files` for text accumulation, still
//! a hand-written generator, not a `WorldGenerator` trait implementation,
//! not a `WorldGenerator` trait implementation (CONTRACT: docs/architecture.md §9 doesn't
//! mandate the trait specifically, only "built on wit-bindgen-core").
//! Built on a local `Source` buffer (`crate::source`) matching
//! `wit_bindgen_core::Source`'s brace-tracking auto-indent behavior — still
//! a hand-written generator, not a `WorldGenerator` trait implementation
//! (CONTRACT: docs/architecture.md §9 doesn't mandate the trait
//! specifically, only "built on wit-bindgen-core"; the vocabulary carries
//! over even though the dependency itself does not).

use std::collections::BTreeSet;
use std::fmt::Write as _;

use anyhow::{bail, Context, Result};
use wit_bindgen_core::Source;
use wit_parser::{
Function, FunctionKind, Handle, Resolve, Type, TypeDefKind, TypeId, WorldId, WorldItem,
WorldKey,
};

use crate::digest;
use crate::source::Source;

/// Default import base for generated bindings: the versioned JSR specifier
/// for `@polyengine/runtime`, with the version derived at build time from
Expand Down Expand Up @@ -271,7 +273,7 @@ pub fn generate(
for (key, item) in w.imports.iter().chain(w.exports.iter()) {
collect_and_emit_types(resolve, key, item, &mut emitted, &mut type_decls)?;
}
src.push_str(&type_decls);
src.push_str(type_decls.as_str());

// ---- Resource class declarations, in first-encountered order.
for rid in &resource_order {
Expand Down Expand Up @@ -333,10 +335,11 @@ pub fn generate(
* Verifies the loaded plan's world digest against `WORLD_DIGEST`\n\
* BEFORE instantiating (contracts/digest.md; contracts/embedder-api.md\n\
* §\"Module wiring and instantiation\"), throwing\n\
* `WorldDigestMismatchError` with the structural diff on skew — no\n\
* guest code has run when that throws. Accepts the same sources as\n\
* the runtime `instantiate` (pre-translated artifacts, an envelope\n\
* via `artifactsFromEnvelope`, or component bytes plus a translator).\n\
* `WorldDigestMismatchError` — fails fast on skew, no\n\
* structural diff — no guest code has run when that throws. Accepts\n\
* the same sources as the runtime `instantiate` (pre-translated\n\
* artifacts, an envelope via `artifactsFromEnvelope`, or component\n\
* bytes plus a translator).\n\
*\n\
* Use `bind` instead only when the plan was verified already. */\n\
export async function instantiate(\n\
Expand Down
1 change: 1 addition & 0 deletions crates/bindgen/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod codegen;
pub mod digest;
mod source;
41 changes: 0 additions & 41 deletions crates/bindgen/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,41 +56,6 @@ struct Cli {

#[derive(Subcommand)]
enum Command {
/// Generate the typed TS facade for a world.
Generate {
wit_path: PathBuf,
#[arg(long)]
world: Option<String>,
#[arg(long)]
out: PathBuf,

/// Import base the generated bindings resolve the runtime through.
///
/// Resolution rule, by what the base addresses: a path or URL
/// specifier addresses a *file* and yields `{base}/{module}/mod.ts`; a
/// bare or registry specifier addresses an entry in a package's
/// `exports` map — runtime/deno.json declares `./plan` / `./digest` /
/// `./embedder` — and yields `{base}/{module}`.
///
/// Concretely, file-addressed when the base starts with `.`, `/`,
/// `file:`, `http://` or `https://`; export-addressed otherwise. An
/// unrecognized scheme falls back to export-addressed, so a future
/// registry scheme works by default while anything file-like must be
/// spelled as a path, a `file:` URL, or an `http(s)` URL.
///
/// Useful non-default values: `../../../src` (in-repo fixture
/// regeneration), `@polyengine/runtime` (consumers using an import map
/// or npm rather than a `jsr:` specifier).
///
/// The default's version is derived from runtime/deno.json at build
/// time. Caveat: this repo's manifests always carry the NEXT release,
/// so on a development checkout between releases the default pins a
/// version that is not published yet (semver ranges never resolve to
/// the `-pre.g<hash>` prereleases) — bindings from a dev checkout
/// belong to that unreleased line.
#[arg(long, value_name = "PREFIX", default_value = bindgen::codegen::DEFAULT_IMPORT_BASE)]
import_base: String,
},
/// Print only the canonical digest (debugging / cross-language tests).
Digest {
wit_path: PathBuf,
Expand All @@ -105,12 +70,6 @@ enum Command {
fn main() -> Result<()> {
let cli = Cli::parse();
match cli.cmd {
Some(Command::Generate {
wit_path,
world,
out,
import_base,
}) => generate(&wit_path, world.as_deref(), &out, &import_base),
Some(Command::Digest {
wit_path,
world,
Expand Down
86 changes: 86 additions & 0 deletions crates/bindgen/src/source.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//! A minimal local replacement for `wit_bindgen_core::Source` (issue: drop
//! the `wit-bindgen-core` dependency, whose only use in this crate was this
//! type as a string-accumulation buffer). Reproduces its brace-tracking
//! auto-indent behavior exactly (verified byte-for-byte by
//! `crates/bindgen/tests/codegen_snapshot.rs`): each `push_str` line gets the
//! current indent prepended, a line ending in `{` bumps the indent for
//! subsequent lines, a line starting with `}` drops the indent (and trims a
//! trailing two-space indent already written for that line), and text
//! recognized as a line comment (`//`) suspends brace tracking until the next
//! newline — `codegen.rs` uses `\x20` escapes on intentional `{`/`}`
//! characters that are not real braces to defeat this exact tracking.
//!
//! Source: wit-bindgen-core 0.58.0 `src/source.rs` (`push_str`), reproduced
//! under upstream's license (this crate is Apache-2.0; wit-bindgen-core is
//! Apache-2.0 WITH LLVM-exception).

use std::fmt;

#[derive(Default)]
pub struct Source {
s: String,
indent: usize,
in_line_comment: bool,
continuing_line: bool,
}

impl Source {
pub fn push_str(&mut self, src: &str) {
let lines = src.lines().collect::<Vec<_>>();
for (i, line) in lines.iter().enumerate() {
if !self.continuing_line {
if !line.is_empty() {
for _ in 0..self.indent {
self.s.push_str(" ");
}
}
self.continuing_line = true;
}

let trimmed = line.trim();
if trimmed.starts_with("//") {
self.in_line_comment = true;
}

if !self.in_line_comment {
if trimmed.starts_with('}') && self.s.ends_with(" ") {
self.s.pop();
self.s.pop();
}
}
self.s.push_str(if lines.len() == 1 {
line
} else {
line.trim_start()
});
if !self.in_line_comment {
if trimmed.ends_with('{') {
self.indent += 1;
}
if trimmed.starts_with('}') {
self.indent = self.indent.saturating_sub(1);
}
}
if i != lines.len() - 1 || src.ends_with('\n') {
self.newline();
}
}
}

fn newline(&mut self) {
self.in_line_comment = false;
self.continuing_line = false;
self.s.push('\n');
}

pub fn as_str(&self) -> &str {
&self.s
}
}

impl fmt::Write for Source {
fn write_str(&mut self, s: &str) -> fmt::Result {
self.push_str(s);
Ok(())
}
}
2 changes: 1 addition & 1 deletion crates/bindgen/tests/codegen_snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//! Regenerate after an intentional codegen change:
//! ```text
//! for w in hello values resources async-probe stream-echo future-user; do
//! cargo run -p bindgen -- generate examples/guests/$w/wit --world $w \
//! cargo run -p bindgen -- examples/guests/$w/wit --world $w \
//! --out runtime/tests/bindgen/generated/$w.ts --import-base ../../../src
//! done
//! ```
Expand Down
6 changes: 2 additions & 4 deletions ct-runner/deno.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
{
"name": "@polyengine/ct-runner",
"version": "0.5.2",
"version": "0.6.0",
"exports": {
".": "./src/mod.ts",
"./imports": "./src/import-analysis.ts",
"./run": "./src/run-suite.ts"
".": "./src/mod.ts"
},
"tasks": {
"test": "deno test --allow-read=..,/tmp --allow-write=/tmp --allow-run",
Expand Down
14 changes: 0 additions & 14 deletions ct-runner/src/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ export {
type RunCounts,
runSuite,
type RunSuiteOptions,
TESTS_INTERFACE,
} from "./run-suite.ts";

export {
Expand All @@ -20,16 +19,3 @@ export {
MissingImportsError,
requireImportsResolved,
} from "./import-analysis.ts";

export { Context, TEST_CONTEXT_INTERFACE, testContextImportRecord } from "./context.ts";

export {
applies,
collectTagsSections,
firstExcluding,
loadTagsInventory,
parseTagsRecords,
TAGS_SECTION,
type TagsInventory,
tagsOf,
} from "./tags.ts";
Loading
Loading