From 256007e5fd6a262ca5e5ee4851a9854e542e979a Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Mon, 21 Sep 2026 10:35:24 +0000 Subject: [PATCH] feat(esm): retire --deno-esm; Bun-ESM is the only JS-host ESM target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --deno-esm / -o *.deno.js is a hard error (E0826) pointing at --bun-esm. codegen_deno now emits the Bun host. The historical codegen-deno corpus compiles to .bun.js. Aspirational StartupError fixtures use real syntax (use Console/Dom, tuple-list attrs, #{…} records). Refs #56 --- .github/workflows/ci.yml | 8 +-- .gitignore | 1 + CHANGELOG.adoc | 9 +++ bin/main.ml | 54 ++++-------------- docs/CAPABILITY-MATRIX.adoc | 23 ++++---- docs/ECOSYSTEM.adoc | 4 +- docs/EFFECTS-IMPLEMENTATION.adoc | 12 ++++ docs/STDLIB-EXTERN-AUDIT.adoc | 4 +- docs/bindings-roadmap.adoc | 2 +- docs/guides/bun-esm-migration.adoc | 18 ++++-- lib/codegen_deno.ml | 13 +++-- stdlib/Console.affine | 5 +- stdlib/Deno.affine | 10 ++-- stdlib/Dom.affine | 6 +- .../codegen-deno/aggregate_smoke.harness.mjs | 2 +- .../codegen-deno/bytes_binary_io.harness.mjs | 2 +- tests/codegen-deno/canvas_smoke.harness.mjs | 2 +- tests/codegen-deno/class_basic.harness.mjs | 2 +- tests/codegen-deno/control_flow.harness.mjs | 2 +- tests/codegen-deno/deno_scripting.harness.mjs | 2 +- .../deno_scripting_part2.harness.mjs | 2 +- .../codegen-deno/deno_string_fmt.harness.mjs | 2 +- tests/codegen-deno/dom_startup_error.affine | 14 +++++ .../dom_startup_error.harness.mjs | 21 +++++++ .../codegen-deno/dom_window_smoke.harness.mjs | 2 +- tests/codegen-deno/encoding_smoke.harness.mjs | Bin 3278 -> 3277 bytes tests/codegen-deno/http_fetch.harness.mjs | 2 +- tests/codegen-deno/int_div.harness.mjs | 2 +- tests/codegen-deno/ipc_smoke.harness.mjs | 2 +- .../loop_break_continue.harness.mjs | 2 +- tests/codegen-deno/match_enum.harness.mjs | 2 +- tests/codegen-deno/motion_smoke.harness.mjs | 2 +- tests/codegen-deno/non_ascii.harness.mjs | 4 +- tests/codegen-deno/pixi_smoke.harness.mjs | 2 +- .../codegen-deno/pixisound_smoke.harness.mjs | 2 +- tests/codegen-deno/pixiui_smoke.harness.mjs | 2 +- tests/codegen-deno/random_smoke.harness.mjs | 2 +- tests/codegen-deno/ref_fields.harness.mjs | 2 +- .../sqlite_introspect_bulk.harness.mjs | 2 +- .../codegen-deno/sqlite_prepared.harness.mjs | 2 +- tests/codegen-deno/sqlite_smoke.harness.mjs | 2 +- tests/codegen-deno/string_lex_cmp.harness.mjs | 2 +- tests/codegen-deno/string_prims.harness.mjs | 2 +- .../transaction_smoke.harness.mjs | 2 +- tests/codegen-deno/wasm_call.harness.mjs | 2 +- .../wasm_exports_demo.harness.mjs | 2 +- .../wasm_wasi_instance.harness.mjs | 2 +- tests/codegen/dom_pilot_startup_error.affine | 31 ++++++++++ .../codegen/test_dom_pilot_startup_error.mjs | 12 ++++ tools/run_codegen_bun_tests.sh | 22 +++---- tools/run_codegen_deno_tests.sh | 23 ++++---- 51 files changed, 218 insertions(+), 136 deletions(-) create mode 100644 tests/codegen-deno/dom_startup_error.affine create mode 100644 tests/codegen-deno/dom_startup_error.harness.mjs create mode 100644 tests/codegen/dom_pilot_startup_error.affine create mode 100644 tests/codegen/test_dom_pilot_startup_error.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 512c85ef..578b151c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -89,10 +89,10 @@ jobs: run: opam exec -- dune runtest - name: Run codegen WASM tests run: opam exec -- ./tools/run_codegen_wasm_tests.sh - - name: Run codegen Deno-ESM tests (issue #122) - # Compiles tests/codegen-deno/*.affine with the --deno-esm backend - # and runs the *.harness.mjs under Node (CI has Node 20, not Deno; - # the Phase 1 fixtures are pure logic so Node ESM exercises them). + - name: Run codegen Bun-ESM tests (historical codegen-deno corpus) + # Compiles tests/codegen-deno/*.affine with the --bun-esm backend + # and runs the *.harness.mjs under Node (CI has Node 20; these + # fixtures mock host objects and do not need the Bun binary). run: opam exec -- ./tools/run_codegen_deno_tests.sh - name: Run native Bun-ESM tests (issue #734) run: opam exec -- ./tools/run_codegen_bun_tests.sh diff --git a/.gitignore b/.gitignore index 0f632882..b1445fa0 100644 --- a/.gitignore +++ b/.gitignore @@ -100,6 +100,7 @@ bisect*.coverage # issue #122: generated Deno-ESM regression outputs (compiled from the # committed *.affine fixtures by tools/run_codegen_deno_tests.sh). /tests/codegen-deno/*.deno.js +/tests/codegen-deno/*.bun.js # Issue #734: generated native Bun-ESM acceptance outputs. /tests/codegen-bun/*.bun.js /tests/codegen-bun/backend-conflict.json diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index ad4aa419..6cbf3377 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -15,8 +15,17 @@ https://semver.org/spec/v2.0.0.html[Semantic Versioning]. === [Unreleased] +==== Removed + +* `--deno-esm` / `-o FILE.deno.js` is a hard error (E0826). Bun-ESM +(`--bun-esm` / `.bun.js`) is the only JS-host ESM target. The flag is +kept so existing scripts fail loudly (Refs #56) + ==== Added +* Aspirational idaptik StartupError fixture compiles with real syntax +(`use Console::{log}`, `use Dom::{…}`, tuple-list attrs and +`#{ bg: … }` records) on `--bun-esm` (Refs #56) * feat(stdlib): Aggregate.affine — SQL group-by + aggregation primitives — db-theory #3 (7 externs) (PR #527) * feat(stdlib): Transaction.affine — affine-bounded write-set isolation diff --git a/bin/main.ml b/bin/main.ml index 6a6e2c62..d491c8b2 100644 --- a/bin/main.ml +++ b/bin/main.ml @@ -492,10 +492,8 @@ let repl_cmd_fn () = let compile_file face json wasm_gc vscode_ext vscode_adapter vscode_no_lc deno_esm bun_esm target path output = let face = resolve_face ~quiet:json face path in - let is_deno = deno_esm || Filename.check_suffix output ".deno.js" in - let is_bun = bun_esm || Filename.check_suffix output ".bun.js" in - if is_deno && is_bun then - let message = "--deno-esm and --bun-esm are mutually exclusive" in + if deno_esm || Filename.check_suffix output ".deno.js" then + let message = "Deno-ESM was removed; use --bun-esm (and a .bun.js output path)" in if json then json_finish [{ Affinescript.Json_output.severity = Error; code = "E0826"; message; @@ -536,10 +534,9 @@ let compile_file face json wasm_gc vscode_ext vscode_adapter vscode_no_lc use the original [prog] because they handle imports natively via Codegen.gen_imports / the import section. *) let flat_prog = Affinescript.Module_loader.flatten_imports loader prog in - let is_deno = deno_esm || Filename.check_suffix output ".deno.js" in let is_bun = bun_esm || Filename.check_suffix output ".bun.js" in let is_julia = Filename.check_suffix output ".jl" in - let is_js = (not is_deno) && (not is_bun) && Filename.check_suffix output ".js" in + let is_js = (not is_bun) && Filename.check_suffix output ".js" in let is_c = Filename.check_suffix output ".c" in let is_wgsl = Filename.check_suffix output ".wgsl" in let is_faust = Filename.check_suffix output ".dsp" in @@ -570,16 +567,6 @@ let compile_file face json wasm_gc vscode_ext vscode_adapter vscode_no_lc let oc = open_out_bin output in output_string oc esm_code; close_out oc - end else if is_deno then begin - match Affinescript.Codegen_deno.codegen_deno flat_prog resolve_ctx.symbols with - | Error msg -> - add { severity = Error; code = "E0824"; - message = Printf.sprintf "Deno-ESM codegen error: %s" msg; - span = Affinescript.Span.dummy; help = None; labels = [] } - | Ok esm_code -> - let oc = open_out_bin output in - output_string oc esm_code; - close_out oc end else if is_julia then begin match Affinescript.Julia_codegen.codegen_julia flat_prog resolve_ctx.symbols with | Error msg -> @@ -779,10 +766,9 @@ let compile_file face json wasm_gc vscode_ext vscode_adapter vscode_no_lc cross-module imports for backends that don't have native module-system support. Wasm/Wasm-GC keep the original [prog]. *) let flat_prog = Affinescript.Module_loader.flatten_imports loader prog in - let is_deno = deno_esm || Filename.check_suffix output ".deno.js" in let is_bun = bun_esm || Filename.check_suffix output ".bun.js" in let is_julia = Filename.check_suffix output ".jl" in - let is_js = (not is_deno) && (not is_bun) && Filename.check_suffix output ".js" in + let is_js = (not is_bun) && Filename.check_suffix output ".js" in let is_c = Filename.check_suffix output ".c" in let is_wgsl = Filename.check_suffix output ".wgsl" in let is_faust = Filename.check_suffix output ".dsp" in @@ -814,17 +800,6 @@ let compile_file face json wasm_gc vscode_ext vscode_adapter vscode_no_lc close_out oc; Format.printf "Compiled %s -> %s (Bun-ESM)@." path output; `Ok ()) - else if is_deno then - (match Affinescript.Codegen_deno.codegen_deno flat_prog resolve_ctx.symbols with - | Error e -> - Format.eprintf "@[Deno-ESM codegen error: %s@]@." e; - `Error (false, "Deno-ESM codegen error") - | Ok esm_code -> - let oc = open_out output in - output_string oc esm_code; - close_out oc; - Format.printf "Compiled %s -> %s (Deno-ESM)@." path output; - `Ok ()) else if is_julia then (match Affinescript.Julia_codegen.codegen_julia flat_prog resolve_ctx.symbols with | Error e -> @@ -1280,28 +1255,21 @@ let vscode_no_lc_arg = dependency for extensions that ship no language client; the \ wiring passes null in its place.") -(* Issue #122: --deno-esm. Selects the direct AST -> ES-module backend - ({!Affinescript.Codegen_deno}) regardless of output extension, so a - drop-in `.js` ES module can be produced (e.g. `-o src/storage.js - --deno-esm`). A `.deno.js` output extension also routes here without - the flag, as a convenience for the test corpus / ad-hoc use. *) +(* --deno-esm was issue #122. Retired: the ESM host is Bun (--bun-esm). + The flag is kept so existing scripts get a clear error instead of + Cmdliner unknown-option. *) let deno_esm_arg = Arg.(value & flag & info ["deno-esm"] - ~doc:"Emit a standalone Deno/Node ES module directly from the AST \ - (issue #122): `export class` for struct+impl, `export` for \ - public fns/consts, and `extern fn` lowered to direct host \ - calls (Deno.*Sync / JSON / WebAssembly). No wasm, no require, \ - no handle table — the output is a drop-in importable ESM. A \ - `.deno.js` output extension selects this backend implicitly.") + ~doc:"REMOVED. Deno-ESM is gone; use $(b,--bun-esm) / a `.bun.js` \ + output path. Passing this flag (or `-o *.deno.js`) is an error.") let bun_esm_arg = Arg.(value & flag & info ["bun-esm"] ~doc:"Emit a standalone Bun-native ES module directly from the AST: \ public declarations are exported and host operations use Bun's \ Node-compatible synchronous APIs. The emitted module contains no \ - legacy-runtime shim. A `.bun.js` output extension selects this \ - backend implicitly. This option is mutually exclusive with \ - `--deno-esm`.") + Deno runtime shim. A `.bun.js` output extension selects this \ + backend implicitly.") (** Shared --face flag: select the parser surface-syntax face. *) let face_arg = diff --git a/docs/CAPABILITY-MATRIX.adoc b/docs/CAPABILITY-MATRIX.adoc index 9986c6d8..e77ed4ab 100644 --- a/docs/CAPABILITY-MATRIX.adoc +++ b/docs/CAPABILITY-MATRIX.adoc @@ -196,16 +196,19 @@ Formal spec: link:specs/TYPED-WASM-INTERFACE.adoc[specs/TYPED-WASM-INTERFACE.ado Widening roadmap (L1–6, L14–16, multi-producer ABI): link:specs/TYPED-WASM-ROADMAP.adoc[specs/TYPED-WASM-ROADMAP.adoc]. Producer-side; target spec is the separate `hyperpolymath/typed-wasm` repo. -|Deno-ESM |works |Direct AST→ES-module transpiler (`lib/codegen_deno.ml`), -`--deno-esm` / `.deno.js`. Shipped + consumer-verified (ubicity). - -|Bun-ESM |works |Host-profiled direct AST→ES-module transpiler, -`--bun-esm` / `.bun.js`. Public declarations remain importable ESM; filesystem, -argument, and process operations lower through Bun's synchronous -Node-compatibility surface. Host operations are resolved lazily so a generated -module that only uses browser-provided externs remains browser-importable. CI -compiles, checks for legacy-runtime leakage, parses, and executes filesystem, -byte, argument, export, and missing-path controls under Bun. +|Deno-ESM |retired |`--deno-esm` / `-o FILE.deno.js` is a hard error (E0826). +The JS-host ESM target is Bun-ESM. The flag is kept so existing scripts fail +loudly instead of becoming an unknown option. + +|Bun-ESM |works |Direct AST→ES-module transpiler (`lib/codegen_deno.ml`, +`codegen_bun`), `--bun-esm` / `.bun.js`. Public declarations remain importable +ESM; filesystem, argument, and process operations lower through Bun's +synchronous Node-compatibility surface. Host operations are resolved lazily so +a generated module that only uses browser-provided externs remains +browser-importable. CI compiles, checks for legacy-runtime leakage, parses, +and executes filesystem, byte, argument, export, and missing-path controls +under Bun. `tools/run_codegen_deno_tests.sh` (historical name) compiles +`tests/codegen-deno/` with `--bun-esm`. Migration and host-contract details: link:guides/bun-esm-migration.adoc[guides/bun-esm-migration.adoc]. diff --git a/docs/ECOSYSTEM.adoc b/docs/ECOSYSTEM.adoc index 19bce1b3..2be9f4b4 100644 --- a/docs/ECOSYSTEM.adoc +++ b/docs/ECOSYSTEM.adoc @@ -168,8 +168,8 @@ surface. |`affinescript-vite` |scaffold |Build-tool integration shell. -|`affinescript-deno-test` |works |Smoke-test harness used by the Deno-ESM -target. +|`affinescript-deno-test` |historical |Smoke-test harness from the retired +Deno-ESM target. JS-host ESM is Bun-ESM (`--bun-esm`). |`affinescript-tea` |runtime |INT-07 (#182): real host-side TEA runtime + run loop (`TeaApp`: load/init/dispatch/model/setScreen/run, diff --git a/docs/EFFECTS-IMPLEMENTATION.adoc b/docs/EFFECTS-IMPLEMENTATION.adoc index 3590872c..eeede5ad 100644 --- a/docs/EFFECTS-IMPLEMENTATION.adoc +++ b/docs/EFFECTS-IMPLEMENTATION.adoc @@ -78,6 +78,18 @@ type eval_error = Handler evaluation catches `PerformEffect`, selects a matching arm, and evaluates the arm body in the handler context. +== JS-host ESM (Bun) — Canvas-style erasure + +Host FFI on `--bun-esm` does **not** require `/ IO` (or `{IO}`) effect +rows. `stdlib/Canvas.affine`, `stdlib/Dom.affine`, and +`stdlib/Console.affine` declare ordinary `extern fn` / wrappers; the +direct-ESM emitter lowers them to host calls and erases effect +declarations (`// effect declaration (erased)`). Declared `/ Async` rows +are the exception: they compile to `async function` so `await fetch` is +legal JS. Algebraic `handle { ... }` is a compile error on this backend +(Refs #555). This is the AOT-safe contract for the #56 remainder — not +a second effect system. + == Not Yet Complete [arabic] diff --git a/docs/STDLIB-EXTERN-AUDIT.adoc b/docs/STDLIB-EXTERN-AUDIT.adoc index 8d5138b3..69e0ff93 100644 --- a/docs/STDLIB-EXTERN-AUDIT.adoc +++ b/docs/STDLIB-EXTERN-AUDIT.adoc @@ -70,8 +70,8 @@ producer-side type signature here and a verifier-side contract in runtime adapter all green. `Http.fetch` is the canonical example (landed via the #225 CPS line, PR1..PR3d). -|*Adapter-side (Deno-ESM)* -|Compiles via the `--deno-esm` backend; the `extern` is realised +|*Adapter-side (JS-host ESM)* +|Compiles via the `--bun-esm` backend (Deno-ESM retired); the `extern` is realised by the emitted ESM importing a JS module. The "real impl" is the adapter shim in `packages//mod.js` (or equivalent). |Adapter package exists, the symbol is exported, and a diff --git a/docs/bindings-roadmap.adoc b/docs/bindings-roadmap.adoc index c6536568..a042a741 100644 --- a/docs/bindings-roadmap.adoc +++ b/docs/bindings-roadmap.adoc @@ -75,7 +75,7 @@ no further significant → AffineScript work is tractable. |*WASM-exports calling pattern* — invoke individual `exports.fn_name(args)` from a `WasmExports` value |`●` usable (Option A landed) |`stdlib/Deno.affine` -|`wasmCall(exports: WasmExports, name: String, args: [Float]) -> Float` lowers to `Number(exports[name](...args))` on `--deno-esm`. AS-side surface + docstring example landed in `stdlib/Deno.affine`; round-trip exercised by `tests/codegen-deno/wasm_call.{affine,harness.mjs}` against a hand-built 41-byte wasm module exporting `add(i32, i32) -> i32`. *Option A (generic) — typed per-Zig-fn shims can layer on top per-consumer if needed.* Closes #414 via host-side #422 + AS-side this PR. *Generic export-call shipped #455* (`wasm_export_call(exports, name, args: [WasmValue]) -> WasmValue` + `WasmValue` opaque + `wv_i32`/`wv_i64`/`wv_f32`/`wv_f64` + `wv_as_int`/`wv_as_float`/`wv_kind`); end-to-end demo at `examples/wasm-exports-demo.affine` (#500) with smoke-test `tests/codegen-deno/wasm_exports_demo.{affine,harness.mjs}` exercising all four scalar kinds. +|`wasmCall(exports: WasmExports, name: String, args: [Float]) -> Float` lowers to `Number(exports[name](...args))` on `--bun-esm`. AS-side surface + docstring example landed in `stdlib/Deno.affine`; round-trip exercised by `tests/codegen-deno/wasm_call.{affine,harness.mjs}` against a hand-built 41-byte wasm module exporting `add(i32, i32) -> i32`. *Option A (generic) — typed per-Zig-fn shims can layer on top per-consumer if needed.* Closes #414 via host-side #422 + AS-side this PR. *Generic export-call shipped #455* (`wasm_export_call(exports, name, args: [WasmValue]) -> WasmValue` + `WasmValue` opaque + `wv_i32`/`wv_i64`/`wv_f32`/`wv_f64` + `wv_as_int`/`wv_as_float`/`wv_kind`); end-to-end demo at `examples/wasm-exports-demo.affine` (#500) with smoke-test `tests/codegen-deno/wasm_exports_demo.{affine,harness.mjs}` exercising all four scalar kinds. |6 |*Phoenix Channels / WebSocket* (Socket connect/disconnect, Channel join/leave/push, presence) diff --git a/docs/guides/bun-esm-migration.adoc b/docs/guides/bun-esm-migration.adoc index d0f07eaa..1d1f5b8b 100644 --- a/docs/guides/bun-esm-migration.adoc +++ b/docs/guides/bun-esm-migration.adoc @@ -54,12 +54,18 @@ The source filename is retained to avoid a high-risk mechanical move in the same change as the semantic migration. It does not imply that Bun output passes through or embeds the compatibility runtime. -The compatibility flag remains available for existing external consumers. An -estate migration is complete only when its active workflows, runtime files, -lockfiles, build commands, generated artefact names, examples, and current -documentation have moved to Bun. Historical records may retain their original -runtime names when clearly marked as history; renaming history would make it -less accurate. +`--deno-esm` and `-o *.deno.js` are retired: the compiler errors with E0826 +and points at `--bun-esm` / `.bun.js`. The flag is kept so existing scripts +fail loudly instead of becoming an unknown option. An estate migration is +complete only when its active workflows, runtime files, lockfiles, build +commands, generated artefact names, examples, and current documentation have +moved to Bun. Historical records may retain their original runtime names when +clearly marked as history; renaming history would make it less accurate. + +`affinescript-vite` remains a scaffold (not in this tree). Effect rows such +as `/ IO` are not required on the JS-host ESM path: host FFI is erased at +emit the same way Canvas/Dom externs are (see +link:../EFFECTS-IMPLEMENTATION.adoc[EFFECTS-IMPLEMENTATION.adoc]). == Verification contract diff --git a/lib/codegen_deno.ml b/lib/codegen_deno.ml index 1f3a4640..84caf529 100644 --- a/lib/codegen_deno.ml +++ b/lib/codegen_deno.ml @@ -1,13 +1,14 @@ (* SPDX-License-Identifier: MPL-2.0 *) (* SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell *) -(** Deno-ESM Emit Mode (issue #122, Refs #35 #103). +(** Direct ESM emit (issue #122 origin; Bun-ESM is the only JS-host + profile — `--deno-esm` retired, Refs #56). A *direct* AffineScript-AST → ES-module transpiler. Unlike {!Codegen_node} (which wraps a compiled [Wasm.wasm_module] in a CJS shim), this backend emits standalone ES2020 module source — no wasm, no [require], no handle table — so the output is a drop-in [.js] / - [.mjs] ES module a Deno (or Node ESM) consumer can [import] directly. + [.mjs] ES module a Bun (or Node ESM) consumer can [import] directly. Why a direct transpiler and not a wasm-wrapping ESM shim: the motivating consumer ([hyperpolymath/ubicity]'s [storage.ts] / @@ -2109,12 +2110,14 @@ let generate (host : host_profile) (program : program) (symbols : Symbol.t) : st if has_main then emit_line ctx "await main();"; Buffer.contents ctx.output +(* Deno-ESM host profile is retired; the ESM emitter is Bun-only. The + name is kept so existing library callers compile. *) let codegen_deno (program : program) (symbols : Symbol.t) : (string, string) result = - try Ok (generate Deno program symbols) + try Ok (generate Bun program symbols) with - | Failure msg -> Error ("Deno-ESM codegen error: " ^ msg) - | e -> Error ("Deno-ESM codegen error: " ^ Printexc.to_string e) + | Failure msg -> Error ("Bun-ESM codegen error: " ^ msg) + | e -> Error ("Bun-ESM codegen error: " ^ Printexc.to_string e) let codegen_bun (program : program) (symbols : Symbol.t) : (string, string) result = diff --git a/stdlib/Console.affine b/stdlib/Console.affine index 050e8f91..51a9b1dc 100644 --- a/stdlib/Console.affine +++ b/stdlib/Console.affine @@ -4,9 +4,10 @@ // Console.affine — #56-A typed console surface. // // `println` / `eprintln` already lower to `console.log` / `console.error` -// on the JS/Deno backends. These wrappers give the pilot's +// on the JS-host ESM (Bun) backend. These wrappers give the pilot's // `Console.log(...)` name a home so migration does not accumulate -// `%raw` for the four console methods. +// `%raw` for the four console methods. No `/ IO` row — Canvas-style +// erasure at emit (see docs/EFFECTS-IMPLEMENTATION.adoc). module Console; diff --git a/stdlib/Deno.affine b/stdlib/Deno.affine index b3e6d118..15a6cf8f 100644 --- a/stdlib/Deno.affine +++ b/stdlib/Deno.affine @@ -1,13 +1,15 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright (c) 2026 Jonathan D.A. Jewell // -// Deno.affine — issue #122 host bindings for the Deno-ESM backend. +// Deno.affine — issue #122 host bindings (JSON / bytes / path helpers). // // Unlike stdlib/Vscode.affine (issue #35), these externs are NOT a // wasm-FFI surface with an Int-handle/readString contract. The -// `--deno-esm` backend (lib/codegen_deno.ml) is a *direct* AST → ES -// module transpiler with no wasm boundary, so each `extern fn` below is -// lowered, at compile time, straight to its host expression: +// `--bun-esm` backend (lib/codegen_deno.ml, `codegen_bun`) is a *direct* +// AST → ES module transpiler with no wasm boundary, so each `extern fn` +// below is lowered, at compile time, straight to its host expression +// (Bun Node-compat for FS; JSON/Date stay platform-neutral). `--deno-esm` +// is retired (E0826). // // writeTextFile(p, c) -> Deno.writeTextFileSync(p, c) // jsonParse(s) -> JSON.parse(s) diff --git a/stdlib/Dom.affine b/stdlib/Dom.affine index 40e673cf..11b13c88 100644 --- a/stdlib/Dom.affine +++ b/stdlib/Dom.affine @@ -5,8 +5,10 @@ // // Canonical `module Dom` so `use Dom::{div, h1, p, text, replaceBody}` // resolves from stdlib/. Constructors are pure VNode builders (no host -// FFI). Runtime mount lives in affinescript-dom (the reconciler); this -// module is the compile-time target for idaptik's pilot syntax. +// FFI, no `/ IO` row — Canvas-style erasure). Runtime mount lives in +// affinescript-dom (the reconciler); this module is the compile-time +// target for idaptik's pilot syntax. `--bun-esm` is the JS-host ESM +// emit; Deno-ESM is retired. // // Attrs are `[(String, String)]` — the same tuple-list shape as // `Http.affine` headers. Record-literal attrs (`#{style: ...}`) are a diff --git a/tests/codegen-deno/aggregate_smoke.harness.mjs b/tests/codegen-deno/aggregate_smoke.harness.mjs index b85949ce..7b0fd0f3 100644 --- a/tests/codegen-deno/aggregate_smoke.harness.mjs +++ b/tests/codegen-deno/aggregate_smoke.harness.mjs @@ -212,7 +212,7 @@ globalThis.__as_sqlite = { txDb() { return 0; }, txIsLive() { return false; }, }; -const mod = await import("./aggregate_smoke.deno.js"); +const mod = await import("./aggregate_smoke.bun.js"); // ── COUNT ─────────────────────────────────────────────────────────── assert.equal(mod.smoke_count(":memory:"), 5, "smoke_count: 5 rows inserted"); diff --git a/tests/codegen-deno/bytes_binary_io.harness.mjs b/tests/codegen-deno/bytes_binary_io.harness.mjs index ef4984d5..ee764998 100644 --- a/tests/codegen-deno/bytes_binary_io.harness.mjs +++ b/tests/codegen-deno/bytes_binary_io.harness.mjs @@ -15,7 +15,7 @@ const { read_mouse_y, fill_byte, fill_first, -} = await import("./bytes_binary_io.deno.js"); +} = await import("./bytes_binary_io.bun.js"); // Round-trip: build a Key event and read every field back. { diff --git a/tests/codegen-deno/canvas_smoke.harness.mjs b/tests/codegen-deno/canvas_smoke.harness.mjs index d0814e2e..f9fc53ed 100644 --- a/tests/codegen-deno/canvas_smoke.harness.mjs +++ b/tests/codegen-deno/canvas_smoke.harness.mjs @@ -42,7 +42,7 @@ class MockCtx2D { const ctx = new MockCtx2D(); const canvas = { getContext: (kind) => { assert.equal(kind, "2d", "getContext called with '2d'"); return ctx; } }; -const { smokeRects, smokePath, smokeTransform, smokeText, smokeImages } = await import("./canvas_smoke.deno.js"); +const { smokeRects, smokePath, smokeTransform, smokeText, smokeImages } = await import("./canvas_smoke.bun.js"); // Rects: assert each style + each of the three rect ops + clear. const ctxBack = smokeRects(canvas); diff --git a/tests/codegen-deno/class_basic.harness.mjs b/tests/codegen-deno/class_basic.harness.mjs index 447245e3..33469971 100644 --- a/tests/codegen-deno/class_basic.harness.mjs +++ b/tests/codegen-deno/class_basic.harness.mjs @@ -9,7 +9,7 @@ import { ANSWER, Red, Green, -} from "./class_basic.deno.js"; +} from "./class_basic.bun.js"; // struct + receiver-first fns -> class with synthesised constructor const c = new Counter(10); diff --git a/tests/codegen-deno/control_flow.harness.mjs b/tests/codegen-deno/control_flow.harness.mjs index b7ac940f..6ba15b42 100644 --- a/tests/codegen-deno/control_flow.harness.mjs +++ b/tests/codegen-deno/control_flow.harness.mjs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MPL-2.0 // issue #122 v2.1 — statement-position return / control flow. import assert from "node:assert/strict"; -import { sum_to, classify, first_even } from "./control_flow.deno.js"; +import { sum_to, classify, first_even } from "./control_flow.bun.js"; assert.equal(sum_to(5), 15, "while-loop + trailing return"); assert.equal(sum_to(0), 0, "while-loop zero iterations"); diff --git a/tests/codegen-deno/deno_scripting.harness.mjs b/tests/codegen-deno/deno_scripting.harness.mjs index d2e3d6ca..b12fb92d 100644 --- a/tests/codegen-deno/deno_scripting.harness.mjs +++ b/tests/codegen-deno/deno_scripting.harness.mjs @@ -43,7 +43,7 @@ const { is_pa_code, warn_then_zero, exit_with, -} = await import("./deno_scripting.deno.js"); +} = await import("./deno_scripting.bun.js"); // walkRecursive — depth-first across nested dirs. assert.equal(count_walked("/root"), 3, "walkRecursive finds 3 files (a.txt + b.txt + c.txt)"); diff --git a/tests/codegen-deno/deno_scripting_part2.harness.mjs b/tests/codegen-deno/deno_scripting_part2.harness.mjs index 3b635f67..11e24245 100644 --- a/tests/codegen-deno/deno_scripting_part2.harness.mjs +++ b/tests/codegen-deno/deno_scripting_part2.harness.mjs @@ -38,7 +38,7 @@ const { header_string, module_url_has_scheme, discard_chain, -} = await import("./deno_scripting_part2.deno.js"); +} = await import("./deno_scripting_part2.bun.js"); // statIsFile / statIsDirectory assert.equal(classify_path("/etc/hosts"), 1, "statIsFile true for a regular file"); diff --git a/tests/codegen-deno/deno_string_fmt.harness.mjs b/tests/codegen-deno/deno_string_fmt.harness.mjs index a90420d5..e28785b9 100644 --- a/tests/codegen-deno/deno_string_fmt.harness.mjs +++ b/tests/codegen-deno/deno_string_fmt.harness.mjs @@ -8,7 +8,7 @@ const { drop_ts_suffix, drop_missing_suffix, fmt_pct, -} = await import("./deno_string_fmt.deno.js"); +} = await import("./deno_string_fmt.bun.js"); // endsWith assert.equal(is_ts("foo.ts"), true, "endsWith hit"); diff --git a/tests/codegen-deno/dom_startup_error.affine b/tests/codegen-deno/dom_startup_error.affine new file mode 100644 index 00000000..b7a4cc18 --- /dev/null +++ b/tests/codegen-deno/dom_startup_error.affine @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MPL-2.0 +// #56 aspirational idaptik StartupError shape, in syntax that compiles +// today: `use` not `import`, tuple-list attrs not `{style: bg}`. +// Record-literal attrs remain `#{field: value}` in the language; the +// migration assistant (#57) emits tuple lists / `#{…}`, not JS `{}`. + +use Console::{log}; +use Dom::{VNode, div, h1, p, text}; + +pub fn startupError(msg: String) -> VNode { + log(msg); + let _style = #{ bg: "crimson" }; + div([("class", "startup-error")], [h1([], "Startup error"), p([], msg), text("")]) +} diff --git a/tests/codegen-deno/dom_startup_error.harness.mjs b/tests/codegen-deno/dom_startup_error.harness.mjs new file mode 100644 index 00000000..69299b51 --- /dev/null +++ b/tests/codegen-deno/dom_startup_error.harness.mjs @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MPL-2.0 +import assert from "node:assert/strict"; +import { startupError } from "./dom_startup_error.bun.js"; + +const logs = []; +const origLog = console.log; +console.log = (...a) => { logs.push(a); }; +try { + const node = startupError("boom"); + assert.equal(node.tag, "VElem"); + assert.equal(node.values[0], "div"); + const attrs = node.values[1]; + assert.equal(attrs[0][0], "class"); + const kids = node.values[2]; + assert.equal(kids[0].values[0], "h1"); + assert.equal(kids[1].values[0], "p"); +} finally { + console.log = origLog; +} +assert.ok(logs.some((x) => String(x[0]).includes("boom"))); +console.log("dom_startup_error.harness.mjs OK"); diff --git a/tests/codegen-deno/dom_window_smoke.harness.mjs b/tests/codegen-deno/dom_window_smoke.harness.mjs index 6df85549..a33970a6 100644 --- a/tests/codegen-deno/dom_window_smoke.harness.mjs +++ b/tests/codegen-deno/dom_window_smoke.harness.mjs @@ -43,7 +43,7 @@ globalThis.document = document; const { smokeWindow, smokeTimers, smokeDocument, smokeUtil, -} = await import("./dom_window_smoke.deno.js"); +} = await import("./dom_window_smoke.bun.js"); const handler = () => 0; assert.equal(smokeWindow(handler), 0); diff --git a/tests/codegen-deno/encoding_smoke.harness.mjs b/tests/codegen-deno/encoding_smoke.harness.mjs index 83b7534039dfb6c85aaa2fd89ca5dce77cb53af3..47aee476ef9f770a3b19c39a2f573d489700f860 100644 GIT binary patch delta 16 XcmX>nc~){m6C-m{Y2M~GMh|WPH|Yh| delta 17 YcmX>rc}{Xe6C+DXYF_^4Rz?qQ06t;{Hvj+t diff --git a/tests/codegen-deno/http_fetch.harness.mjs b/tests/codegen-deno/http_fetch.harness.mjs index 98c17aa2..fc9814f8 100644 --- a/tests/codegen-deno/http_fetch.harness.mjs +++ b/tests/codegen-deno/http_fetch.harness.mjs @@ -27,7 +27,7 @@ const { req_get_status, req_post_body, ok_get, -} = await import("./http_fetch.deno.js"); +} = await import("./http_fetch.bun.js"); // GET — status round-trips, no body sent assert.equal(await get_status("https://example.test/ok"), 200, "GET 200"); diff --git a/tests/codegen-deno/int_div.harness.mjs b/tests/codegen-deno/int_div.harness.mjs index 4a2094a2..f2c41fc1 100644 --- a/tests/codegen-deno/int_div.harness.mjs +++ b/tests/codegen-deno/int_div.harness.mjs @@ -15,7 +15,7 @@ import { for_lit, idx_half, for_float, -} from "./int_div.deno.js"; +} from "./int_div.bun.js"; // Integer division truncates toward zero. assert.equal(idiv(255, 16), 15, "idiv(255,16)"); diff --git a/tests/codegen-deno/ipc_smoke.harness.mjs b/tests/codegen-deno/ipc_smoke.harness.mjs index 9f0e3c88..b63bc0d0 100644 --- a/tests/codegen-deno/ipc_smoke.harness.mjs +++ b/tests/codegen-deno/ipc_smoke.harness.mjs @@ -7,7 +7,7 @@ import assert from "node:assert/strict"; -const { smokeChannelFlow, smokeCloseFlow, smokeTargetFlow, smokeStructuredClone } = await import("./ipc_smoke.deno.js"); +const { smokeChannelFlow, smokeCloseFlow, smokeTargetFlow, smokeStructuredClone } = await import("./ipc_smoke.bun.js"); // Channel flow: assert handlers fire on the peer side, postMessage // round-trips identical payload, and close()s don't throw. diff --git a/tests/codegen-deno/loop_break_continue.harness.mjs b/tests/codegen-deno/loop_break_continue.harness.mjs index b193830e..6b03458b 100644 --- a/tests/codegen-deno/loop_break_continue.harness.mjs +++ b/tests/codegen-deno/loop_break_continue.harness.mjs @@ -6,7 +6,7 @@ import { sum_odd, find_first, count_positive, -} from "./loop_break_continue.deno.js"; +} from "./loop_break_continue.bun.js"; // sum_until: 0+1+2+3+4+5 = 15 (stops at total >= 10 once total reaches 15). // Sequence: total=0 (i=0, +0=0), 1, 3, 6, 10 → break. diff --git a/tests/codegen-deno/match_enum.harness.mjs b/tests/codegen-deno/match_enum.harness.mjs index 25089b01..2692ed5d 100644 --- a/tests/codegen-deno/match_enum.harness.mjs +++ b/tests/codegen-deno/match_enum.harness.mjs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MPL-2.0 // issue #122 v2.4 — qualified Type::Variant patterns + recursive ADTs. import assert from "node:assert/strict"; -import { rank, Red, Blue, len, sum, demo_list } from "./match_enum.deno.js"; +import { rank, Red, Blue, len, sum, demo_list } from "./match_enum.bun.js"; assert.equal(rank(Red), 1, "match expr-body, nullary qualified pattern"); assert.equal(rank(Blue), 3, "match expr-body, last arm"); diff --git a/tests/codegen-deno/motion_smoke.harness.mjs b/tests/codegen-deno/motion_smoke.harness.mjs index 7b9abe39..a2326e35 100644 --- a/tests/codegen-deno/motion_smoke.harness.mjs +++ b/tests/codegen-deno/motion_smoke.harness.mjs @@ -55,7 +55,7 @@ const { smokeTween, smokeSpring, smokeEase, -} = await import("./motion_smoke.deno.js"); +} = await import("./motion_smoke.bun.js"); // ---- animate + cancel (original surface) ---- const controls = smokeAnimate("#player", { x: 100, opacity: 0.5 }, { duration: 1.0 }); diff --git a/tests/codegen-deno/non_ascii.harness.mjs b/tests/codegen-deno/non_ascii.harness.mjs index a36c8b40..7d55f991 100644 --- a/tests/codegen-deno/non_ascii.harness.mjs +++ b/tests/codegen-deno/non_ascii.harness.mjs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MPL-2.0 // issue #460 — round-trip non-ASCII string literals through the // Deno-ESM backend under strict-mode ESM. The `import` itself is the -// strictest test: if the emitted `.deno.js` contains octal escapes, +// strictest test: if the emitted `.bun.js` contains octal escapes, // the module fails to parse and the import throws SyntaxError before // any assertion can run. import assert from "node:assert/strict"; @@ -14,7 +14,7 @@ import { mixed, ascii_only, quotes_and_backslash, -} from "./non_ascii.deno.js"; +} from "./non_ascii.bun.js"; assert.equal(emoji_cross(), "❌", "BMP emoji ❌ round-trips"); assert.equal(emoji_check(), "✓", "BMP check mark ✓ round-trips"); diff --git a/tests/codegen-deno/pixi_smoke.harness.mjs b/tests/codegen-deno/pixi_smoke.harness.mjs index 70ea63db..ca17de12 100644 --- a/tests/codegen-deno/pixi_smoke.harness.mjs +++ b/tests/codegen-deno/pixi_smoke.harness.mjs @@ -114,7 +114,7 @@ globalThis.__as_pixi = { }, }; -const { smokeInit, smokeSpriteFlow, smokeGraphicsFlow, smokeAccessorsFlow, smokeGapFill } = await import("./pixi_smoke.deno.js"); +const { smokeInit, smokeSpriteFlow, smokeGraphicsFlow, smokeAccessorsFlow, smokeGapFill } = await import("./pixi_smoke.bun.js"); // Async init returns an Application after `await app.init(options)` const app = await smokeInit({ width: 800, height: 600, backgroundColor: 0x1099bb }); diff --git a/tests/codegen-deno/pixisound_smoke.harness.mjs b/tests/codegen-deno/pixisound_smoke.harness.mjs index 2d2dfbd2..08a1c2d5 100644 --- a/tests/codegen-deno/pixisound_smoke.harness.mjs +++ b/tests/codegen-deno/pixisound_smoke.harness.mjs @@ -38,7 +38,7 @@ globalThis.__as_pixi_sound = { const { smokeFrom, smokePlay, smokeStop, smokePause, smokeResume, smokeSetVolume, smokeSetLoop, -} = await import("./pixisound_smoke.deno.js"); +} = await import("./pixisound_smoke.bun.js"); const s = smokeFrom("assets/bgm.mp3"); assert.equal(lastFromUrl, "assets/bgm.mp3", "from URL reaches host"); diff --git a/tests/codegen-deno/pixiui_smoke.harness.mjs b/tests/codegen-deno/pixiui_smoke.harness.mjs index 4e9bdc43..1eee8d40 100644 --- a/tests/codegen-deno/pixiui_smoke.harness.mjs +++ b/tests/codegen-deno/pixiui_smoke.harness.mjs @@ -64,7 +64,7 @@ globalThis.__as_pixi_ui = { }; const { smokeButton, smokeFancyButton, smokeSlider, smokeSwitch, smokeProgressBar, smokeList, smokeInput } = - await import("./pixiui_smoke.deno.js"); + await import("./pixiui_smoke.bun.js"); // ── Button: ctor + onPress + upcast ──────────────────────────────── const buttonPressCb = () => "pressed"; diff --git a/tests/codegen-deno/random_smoke.harness.mjs b/tests/codegen-deno/random_smoke.harness.mjs index d560b797..27abb07c 100644 --- a/tests/codegen-deno/random_smoke.harness.mjs +++ b/tests/codegen-deno/random_smoke.harness.mjs @@ -8,7 +8,7 @@ const { draw_unit, draw_in_range, perf_tick, -} = await import("./random_smoke.deno.js"); +} = await import("./random_smoke.bun.js"); // math_random — every draw is in [0, 1). for (let i = 0; i < 1000; i++) { diff --git a/tests/codegen-deno/ref_fields.harness.mjs b/tests/codegen-deno/ref_fields.harness.mjs index e4c0b1ac..d09f5e98 100644 --- a/tests/codegen-deno/ref_fields.harness.mjs +++ b/tests/codegen-deno/ref_fields.harness.mjs @@ -4,7 +4,7 @@ // take Point first (ref/own/mut) so they synthesise as Point methods — // exercising auto-deref field access *and* class synthesis together. import assert from "node:assert/strict"; -import { Point } from "./ref_fields.deno.js"; +import { Point } from "./ref_fields.bun.js"; const p = new Point(3, 4); assert.equal(p.x, 3, "constructor assigns x"); diff --git a/tests/codegen-deno/sqlite_introspect_bulk.harness.mjs b/tests/codegen-deno/sqlite_introspect_bulk.harness.mjs index 8ae8cf14..42419a44 100644 --- a/tests/codegen-deno/sqlite_introspect_bulk.harness.mjs +++ b/tests/codegen-deno/sqlite_introspect_bulk.harness.mjs @@ -168,7 +168,7 @@ globalThis.__as_sqlite = { reset() {}, finalize() {}, }; -const mod = await import("./sqlite_introspect_bulk.deno.js"); +const mod = await import("./sqlite_introspect_bulk.bun.js"); // ── schema_tables ──────────────────────────────────────────────────── const tablesJson = mod.smoke_schema_tables(":memory:"); diff --git a/tests/codegen-deno/sqlite_prepared.harness.mjs b/tests/codegen-deno/sqlite_prepared.harness.mjs index 53aab5e1..d84874ba 100644 --- a/tests/codegen-deno/sqlite_prepared.harness.mjs +++ b/tests/codegen-deno/sqlite_prepared.harness.mjs @@ -247,7 +247,7 @@ globalThis.__as_sqlite = { finalize(s) { stmts.delete(s); }, }; -const mod = await import("./sqlite_prepared.deno.js"); +const mod = await import("./sqlite_prepared.bun.js"); assert.equal( mod.smoke_prepare_bind_int_step_finalize(":memory:"), diff --git a/tests/codegen-deno/sqlite_smoke.harness.mjs b/tests/codegen-deno/sqlite_smoke.harness.mjs index d9edd1bc..e151aca8 100644 --- a/tests/codegen-deno/sqlite_smoke.harness.mjs +++ b/tests/codegen-deno/sqlite_smoke.harness.mjs @@ -125,7 +125,7 @@ globalThis.__as_sqlite = { }, }; -const mod = await import("./sqlite_smoke.deno.js"); +const mod = await import("./sqlite_smoke.bun.js"); assert.equal( mod.smoke_full_lifecycle(":memory:"), diff --git a/tests/codegen-deno/string_lex_cmp.harness.mjs b/tests/codegen-deno/string_lex_cmp.harness.mjs index 3f284548..7a3876c4 100644 --- a/tests/codegen-deno/string_lex_cmp.harness.mjs +++ b/tests/codegen-deno/string_lex_cmp.harness.mjs @@ -8,7 +8,7 @@ import { first_lt, first_gt, equal_strings_le, equal_strings_ge, equal_strings_lt, empty_lt, empty_le, prefix_lt, -} from "./string_lex_cmp.deno.js"; +} from "./string_lex_cmp.bun.js"; assert.equal(lt("abc", "abd"), true, "abc < abd"); assert.equal(lt("abd", "abc"), false, "abd not < abc"); diff --git a/tests/codegen-deno/string_prims.harness.mjs b/tests/codegen-deno/string_prims.harness.mjs index 5a018c41..b406cdfc 100644 --- a/tests/codegen-deno/string_prims.harness.mjs +++ b/tests/codegen-deno/string_prims.harness.mjs @@ -9,7 +9,7 @@ import { n2s, str_cat, arr_cat, -} from "./string_prims.deno.js"; +} from "./string_prims.bun.js"; assert.equal(ends_with2("foo.json", ".json"), true, "string_sub/len ends_with"); assert.equal(ends_with2("foo.txt", ".json"), false, "negative ends_with"); diff --git a/tests/codegen-deno/transaction_smoke.harness.mjs b/tests/codegen-deno/transaction_smoke.harness.mjs index 8e4cd9a1..c1968a00 100644 --- a/tests/codegen-deno/transaction_smoke.harness.mjs +++ b/tests/codegen-deno/transaction_smoke.harness.mjs @@ -189,7 +189,7 @@ globalThis.__as_sqlite = { exportCsv() { return 0; }, lastError() { return ""; }, }; -const mod = await import("./transaction_smoke.deno.js"); +const mod = await import("./transaction_smoke.bun.js"); // ── commit_persists ──────────────────────────────────────────────── assert.equal( diff --git a/tests/codegen-deno/wasm_call.harness.mjs b/tests/codegen-deno/wasm_call.harness.mjs index b42044b0..bb69b771 100644 --- a/tests/codegen-deno/wasm_call.harness.mjs +++ b/tests/codegen-deno/wasm_call.harness.mjs @@ -6,7 +6,7 @@ // __as_wasmCall(exports, "add", [a, b]), round-trips correctly. import assert from "node:assert/strict"; -import { addViaWasm } from "./wasm_call.deno.js"; +import { addViaWasm } from "./wasm_call.bun.js"; // Hand-built minimal wasm module: // (module diff --git a/tests/codegen-deno/wasm_exports_demo.harness.mjs b/tests/codegen-deno/wasm_exports_demo.harness.mjs index 4d8e4823..c54010de 100644 --- a/tests/codegen-deno/wasm_exports_demo.harness.mjs +++ b/tests/codegen-deno/wasm_exports_demo.harness.mjs @@ -11,7 +11,7 @@ import { add_i64_via_wasm, mul_f32_via_wasm, mul_f64_via_wasm, -} from "./wasm_exports_demo.deno.js"; +} from "./wasm_exports_demo.bun.js"; // Hand-built minimal wasm module: // (module diff --git a/tests/codegen-deno/wasm_wasi_instance.harness.mjs b/tests/codegen-deno/wasm_wasi_instance.harness.mjs index 7ea8e530..59b30c3e 100644 --- a/tests/codegen-deno/wasm_wasi_instance.harness.mjs +++ b/tests/codegen-deno/wasm_wasi_instance.harness.mjs @@ -10,7 +10,7 @@ // the fix this threw "Imports argument must be present and must be an object". import assert from "node:assert/strict"; -import { addViaWasiWasm } from "./wasm_wasi_instance.deno.js"; +import { addViaWasiWasm } from "./wasm_wasi_instance.bun.js"; // (module // (import "wasi_snapshot_preview1" "fd_write" diff --git a/tests/codegen/dom_pilot_startup_error.affine b/tests/codegen/dom_pilot_startup_error.affine new file mode 100644 index 00000000..642f813f --- /dev/null +++ b/tests/codegen/dom_pilot_startup_error.affine @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MPL-2.0 +// #56 — wasm compile-pass of the idaptik StartupError shape +// (in-file, no stdlib), matching tests/codegen/dom_pilot_surface.affine. + +pub enum VNode { + VText(String), + VElem(String, [(String, String)], [VNode]) +} + +pub fn text(content: String) -> VNode = VText(content); + +pub fn h(tag: String, attrs: [(String, String)], children: [VNode]) -> VNode = + VElem(tag, attrs, children); + +pub fn div(attrs: [(String, String)], children: [VNode]) -> VNode = + h("div", attrs, children); + +pub fn h1(attrs: [(String, String)], content: String) -> VNode = + h("h1", attrs, [text(content)]); + +pub fn p(attrs: [(String, String)], content: String) -> VNode = + h("p", attrs, [text(content)]); + +pub fn startupError(msg: String) -> VNode = + div([("class", "startup-error")], [h1([], "Startup error"), p([], msg)]); + +pub fn main() -> Int { + let _s = #{ bg: "crimson" }; + let _n = startupError("boom"); + 0 +} diff --git a/tests/codegen/test_dom_pilot_startup_error.mjs b/tests/codegen/test_dom_pilot_startup_error.mjs new file mode 100644 index 00000000..608bed5e --- /dev/null +++ b/tests/codegen/test_dom_pilot_startup_error.mjs @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MPL-2.0 +// #56 — wasm instantiate of the aspirational StartupError shape. +import assert from 'node:assert/strict'; +import { readFile } from 'node:fs/promises'; + +const buf = await readFile('./tests/codegen/dom_pilot_startup_error.wasm'); +const mod = new WebAssembly.Module(buf); +const inst = (await WebAssembly.instantiate(mod, { + wasi_snapshot_preview1: { fd_write: () => 0 }, +})).instance; +assert.equal(inst.exports.main(), 0, 'dom pilot startupError compiled and ran'); +console.log('test_dom_pilot_startup_error.mjs OK'); diff --git a/tools/run_codegen_bun_tests.sh b/tools/run_codegen_bun_tests.sh index 32e999c1..3393f8f5 100755 --- a/tools/run_codegen_bun_tests.sh +++ b/tools/run_codegen_bun_tests.sh @@ -31,22 +31,22 @@ second="$TEST_DIR/reproducibility.bun.js" "${COMPILE_CMD[@]}" "$src" -o "$second" --bun-esm cmp "$out" "$second" -conflict_log="$TEST_DIR/backend-conflict.log" -if "${COMPILE_CMD[@]}" "$src" -o "$out" --deno-esm --bun-esm \ - >"$conflict_log" 2>&1; then - echo "error: conflicting host-profile flags compiled successfully" >&2 +removed_log="$TEST_DIR/deno-removed.log" +if "${COMPILE_CMD[@]}" "$src" -o "$out" --deno-esm \ + >"$removed_log" 2>&1; then + echo "error: retired --deno-esm compiled successfully" >&2 exit 1 fi -grep -q -- '--deno-esm and --bun-esm are mutually exclusive' "$conflict_log" +grep -q 'Deno-ESM was removed' "$removed_log" -conflict_json="$TEST_DIR/backend-conflict.json" -if "${COMPILE_CMD[@]}" "$src" -o "$out" --deno-esm --bun-esm --json \ - >"$conflict_json" 2>&1; then - echo "error: conflicting host-profile flags passed in JSON mode" >&2 +removed_json="$TEST_DIR/deno-removed.json" +if "${COMPILE_CMD[@]}" "$src" -o "${out%.bun.js}.deno.js" --json \ + >"$removed_json" 2>&1; then + echo "error: retired .deno.js output compiled successfully" >&2 exit 1 fi -grep -q '"code":"E0826"' "$conflict_json" -grep -q '"success":false' "$conflict_json" +grep -q '"code":"E0826"' "$removed_json" +grep -q '"success":false' "$removed_json" for js in "$TEST_DIR"/*.harness.mjs; do (cd "$TEST_DIR" && AFFINESCRIPT_BUN_PROBE=estate bun "$(basename "$js")" alpha beta) diff --git a/tools/run_codegen_deno_tests.sh b/tools/run_codegen_deno_tests.sh index 2a06de8c..1e16f01e 100755 --- a/tools/run_codegen_deno_tests.sh +++ b/tools/run_codegen_deno_tests.sh @@ -1,15 +1,12 @@ #!/usr/bin/env bash # SPDX-License-Identifier: MPL-2.0 -# issue #122 — Deno-ESM backend regression runner. +# issue #122 corpus — now compiled with the Bun-ESM backend. # -# Mirrors tools/run_codegen_wasm_tests.sh: for every fixture in -# tests/codegen-deno/, compile FILE.affine -> FILE.deno.js with the -# --deno-esm backend, then run every *.harness.mjs with `node`. -# -# Node is used (not deno) deliberately: CI provisions Node 20 but not -# Deno, and the Phase 1 fixtures are pure logic — the generated module -# only references the `Deno` global lazily inside helper bodies that the -# harnesses never call, so plain Node ESM exercises them faithfully. +# Directory name `tests/codegen-deno/` is historical. Every fixture is +# compiled with `--bun-esm` to FILE.bun.js. Harnesses still run under +# `node` in CI (Node 20 is provisioned; these fixtures do not need the +# Bun binary — they mock host objects). Native Bun acceptance lives in +# tools/run_codegen_bun_tests.sh. set -euo pipefail ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)" @@ -26,16 +23,16 @@ fi echo "Using compiler: ${COMPILE_CMD[*]}" for src in "$TEST_DIR"/*.affine; do - out="${src%.affine}.deno.js" + out="${src%.affine}.bun.js" echo "Compiling $(basename "$src") -> $(basename "$out")" - "${COMPILE_CMD[@]}" "$src" -o "$out" --deno-esm + "${COMPILE_CMD[@]}" "$src" -o "$out" --bun-esm done echo "" -echo "Running Deno-ESM harnesses (node)" +echo "Running ESM harnesses (node, Bun-ESM artefacts)" for js in "$TEST_DIR"/*.harness.mjs; do echo "node $(basename "$js")" (cd "$TEST_DIR" && node "$(basename "$js")") done -echo "All codegen Deno-ESM tests passed." +echo "All codegen Bun-ESM (legacy codegen-deno corpus) tests passed."