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
4 changes: 2 additions & 2 deletions packages/cli/src/bun.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { main } from "effection";
import { fileURLToPath } from "node:url";
import process from "node:process";
import { API, useHostFiles } from "@executablemd/runtime";
import { compileDataUri } from "@executablemd/core";
import { compileTempFile } from "@executablemd/core";
import { runXmd } from "./cli.ts";
import { unassembledMachineSessions } from "./session-coordinator.ts";
import { unsupportedWorkflowHost } from "./workflow.ts";
Expand All @@ -27,7 +27,7 @@ await main(function* (args) {
},

*compile([source, options]) {
return yield* compileDataUri(source, options);
return yield* compileTempFile(source, options);
},
},
{ at: "min" },
Expand Down
10 changes: 9 additions & 1 deletion packages/cli/tests/value-root.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,18 @@
*/
import { describe, it } from "@executablemd/test-support/bdd";
import { expect } from "@executablemd/test-support/expect";
import { ensure, scoped } from "effection";
import { ensure, scoped, until } from "effection";
import type { Operation } from "effection";
import { ensureDir, readTextFile, rm, writeTextFile } from "@effectionx/fs";
import { randomUUID } from "node:crypto";
import { symlink } from "node:fs/promises";
import * as os from "node:os";
import * as path from "node:path";
import { fileURLToPath } from "node:url";
import { runCli } from "@executablemd/test-support/launch";

const ROOT = fileURLToPath(new URL("../../../", import.meta.url));

function* useFixture<T>(
files: Record<string, string>,
body: (dir: string) => Operation<T>,
Expand All @@ -23,6 +27,10 @@ function* useFixture<T>(
yield* ensureDir(dir);
return yield* scoped(function* () {
yield* ensure(() => rm(dir, { recursive: true, force: true }));
yield* writeTextFile(path.join(dir, "package.json"), JSON.stringify({ type: "module" }));
// The child compiles beside the document, so its authored imports resolve
// through the fixture's explicit project dependencies.
yield* until(symlink(path.join(ROOT, "node_modules"), path.join(dir, "node_modules"), "dir"));
for (const [name, content] of Object.entries(files)) {
yield* writeTextFile(path.join(dir, name), content);
}
Expand Down
6 changes: 4 additions & 2 deletions packages/core/src/data-uri-compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
* data: URI eval block compiler middleware.
*
* Compiles eval block source into generator functions by importing a data:
* URI, which leaves nothing on disk. Deno and Bun load one; Node's tsx loader
* rejects it, so the Node entrypoint installs the temp-file compiler instead.
* URI, which leaves nothing on disk. Deno and the compiled binary load one.
* Node's tsx loader rejects it, and Bun does not preserve the generated
* module's exports when it imports a filesystem-backed dependency, so those
* entrypoints install the temp-file compiler instead.
* Standard imports (Effection, executable.md APIs) are captured in the middleware
* closure β€” they are not part of the `API.Env.compile` interface.
*
Expand Down Expand Up @@ -44,7 +46,7 @@
const moduleSource = [importLines, `export default function*(env) {`, source, `}`].join("\n");

const dataUri = `data:application/typescript,${encodeURIComponent(moduleSource)}`;
const mod: { default: EvalBlock } = yield* until(import(dataUri));

Check warning on line 49 in packages/core/src/data-uri-compiler.ts

View workflow job for this annotation

GitHub Actions / jsr

unable to analyze dynamic import

Check warning on line 49 in packages/core/src/data-uri-compiler.ts

View workflow job for this annotation

GitHub Actions / jsr

unable to analyze dynamic import

if (typeof mod.default !== "function") {
throw new Error(
Expand Down
11 changes: 6 additions & 5 deletions specs/executable-mdx-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -1456,13 +1456,14 @@ suggested:

| Middleware | Mechanism | Hosts |
| --- | --- | --- |
| `useDataUriCompiler()` | imports a `data:` URI; touches no disk | Deno, Bun, the compiled binary |
| `useTempFileCompiler()` | writes `.xmd-eval/<uuid>.ts` and imports `file://` | any host, and the only one Node's tsx loader accepts |
| `useDataUriCompiler()` | imports a `data:` URI; touches no disk | Deno and the compiled binary |
| `useTempFileCompiler()` | writes `.xmd-eval/<uuid>.ts` and imports `file://` | any host; the Bun and Node entrypoints use it |

An entrypoint installs whichever its host can load, with `{ at: "min" }`, so
it sits at the base of the middleware chain. Where the two disagree β€” Node's
tsx loader rejects `data:` URI imports β€” that is a property of the loader, not
of the eval block.
tsx loader rejects `data:` URI imports, while Bun loses the generated module's
exports when it imports a filesystem-backed dependency β€” that is a property of
the loader, not of the eval block.

Because the entrypoint's compiler is a base provider, ordinary middleware
wraps it rather than racing it. The behavior-document policy in
Expand Down Expand Up @@ -8427,7 +8428,7 @@ Argument placement belongs to the adapter, because it differs per host:
| --- | --- | --- |
| `deno.ts` | `[execPath, "run", "--allow-all", entry, ...args]` | `compileDataUri` |
| `node.ts` | `[execPath, ...execArgv-minus-inspect, entry, ...args]` | `compileTempFile` |
| `bun.ts` | `[execPath, entry, ...args]` | `compileDataUri` |
| `bun.ts` | `[execPath, entry, ...args]` | `compileTempFile` |
| `compiled.ts` | `[execPath, ...args]` | `compileDataUri` |

**There is no inferred default.** With no adapter installed the operation
Expand Down
Loading