Files
scriptc/packages/cli/test/wasi-runtime-pack.test.ts
Chris Tate ee9f0d64eb feat: ship the self-hosted native scriptc CLI (#585)
* feat: ship the self-hosted native scriptc CLI

- Run the shared compiler and CLI natively, including library builds and compile-time evaluation.
- Install native platform packages and ship relocatable standalone distributions.
- Preserve program semantics and reuse validated build artifacts for fast rebuilds.

* fix: complete native CLI integration and validation

- Preserve library diagnostics and run recursive compiler work on the main stack.
- Restore packaged helper permissions and exercise native npm and Wasm library builds.
- Recover interrupted Sandbox status probes within the original command deadline.
2026-09-30 02:17:56 -05:00

71 lines
3.2 KiB
TypeScript

import { execFile } from "node:child_process";
import { existsSync } from "node:fs";
import { createRequire } from "node:module";
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { dirname, join } from "node:path";
import { promisify } from "node:util";
import { afterEach, expect, test } from "vitest";
const execFileAsync = promisify(execFile);
const require = createRequire(import.meta.url);
const repoRoot = join(import.meta.dirname, "../../..");
const cliEntry = join(repoRoot, "packages/cli/src/main.ts");
const tsxLoader = join(dirname(require.resolve("tsx/package.json")), "dist/loader.mjs");
const helperPackage = require.resolve("@scriptc/llvm-darwin-arm64/package.json");
const helper = join(dirname(helperPackage), "bin", "scriptc-llvm-codegen");
const runtimePackage = require.resolve("@scriptc/runtime-wasm32-wasi/package.json");
const runtimeManifest = join(dirname(runtimePackage), "runtime-pack.json");
const supported = existsSync(helper) && existsSync(runtimeManifest);
const dirs: string[] = [];
afterEach(async () => {
await Promise.all(dirs.splice(0).map((path) => rm(path, { recursive: true, force: true })));
});
test.runIf(supported)("WASI helper object plus runtime pack builds and runs without SCRIPTC_CC", async () => {
const dir = await mkdtemp(join(tmpdir(), "scriptc-wasi-runtime-pack-"));
dirs.push(dir);
const output = join(dir, "hello.wasm");
const zigCache = join(dir, "zig-cache");
await expect(execFileAsync(process.execPath, [
"--import", tsxLoader, cliEntry, "run", join(repoRoot, "tests/corpus/001-hello.ts"), "-o", output,
], {
env: {
...process.env,
SCRIPTC_TARGET: "wasm32-wasi",
SCRIPTC_NO_CACHE: "1",
ZIG_GLOBAL_CACHE_DIR: join(zigCache, "global"),
ZIG_LOCAL_CACHE_DIR: join(zigCache, "local"),
},
encoding: "utf8",
})).resolves.toMatchObject({ stdout: "hello world\n" });
});
test.runIf(supported)("switching WASI and native builds retains both executables", async () => {
const dir = await mkdtemp(join(tmpdir(), "scriptc-wasi-native-output-"));
dirs.push(dir);
const entry = join(dir, "hello.ts");
const outDir = join(dir, ".scriptc");
const nativeEnv = { ...process.env };
delete nativeEnv.SCRIPTC_TARGET;
const wasiEnv = { ...nativeEnv, SCRIPTC_TARGET: "wasm32-wasi" };
const build = (args: string[], env: NodeJS.ProcessEnv) => execFileAsync(process.execPath, [
"--import", tsxLoader, cliEntry, "build", entry, ...args,
], { env, maxBuffer: 4 * 1024 * 1024 });
await writeFile(entry, 'console.log("hello");\n');
await build([], wasiEnv);
const llvm = await readFile(join(outDir, "hello.ll"));
const wasm = await readFile(join(outDir, "hello.wasm"));
await build(["--backend=llvm", "--keep-llvm"], nativeEnv);
const native = await readFile(join(outDir, process.platform === "win32" ? "hello.exe" : "hello"));
const nativeLlvm = await readFile(join(outDir, "hello.ll"));
expect(nativeLlvm.equals(llvm)).toBe(false);
expect(await readFile(join(outDir, "hello.wasm"))).toEqual(wasm);
await build([], wasiEnv);
expect(await readFile(join(outDir, "hello.ll"))).toEqual(llvm);
expect(await readFile(join(outDir, process.platform === "win32" ? "hello.exe" : "hello"))).toEqual(native);
});