mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-20 05:40:17 +08:00
* feat: support static buffer constructors and prototype methods - Preserve typed-array constructor identity and shared storage across JavaScript class APIs. - Support chained indexed assignments and mutable prototype methods with native receiver dispatch. - Compile Three.js geometry merging, instancing, and keyframe interpolation without a JavaScript engine. * fix: preserve native collection and dispatch semantics - Preserve typed-array identity in collections and JavaScript argument evaluation. - Keep symbol-backed fields and unreachable methods on their existing static paths. - Restore compiler bootstrapping and deferred class diagnostics. * fix: preserve inferred returns in native compilation - Update recorded return statements in place so native compilation preserves mixed JavaScript return values. * test: update inferred array coverage expectations - Recognize heterogeneous writes supported by shared JavaScript array storage.
59 lines
3.6 KiB
TypeScript
59 lines
3.6 KiB
TypeScript
import { spawnSync } from "node:child_process";
|
|
import { mkdtemp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { createRequire } from "node:module";
|
|
import { rollup } from "rollup";
|
|
import { expect, test } from "vitest";
|
|
import { compile } from "@scriptc/compiler";
|
|
|
|
const hasZig = spawnSync("zig", ["version"], { stdio: "ignore" }).status === 0;
|
|
const require = createRequire(import.meta.url);
|
|
const wasiRunner = `const {WASI}=require('node:wasi'); const {readFileSync}=require('node:fs');
|
|
const wasi=new WASI({version:'preview1',args:[process.argv[1]],returnOnExit:true});
|
|
const instance=new WebAssembly.Instance(new WebAssembly.Module(readFileSync(process.argv[1])),wasi.getImportObject());
|
|
process.exitCode=wasi.start(instance);`;
|
|
function run(command: string, args: string[]) {
|
|
const result = spawnSync(command,args,{encoding:"utf8",timeout:30_000});
|
|
if (result.error) throw result.error;
|
|
const stderr = result.stderr.split("\n").filter(line => !line.startsWith("scriptc RC audit skipped:")).join("\n");
|
|
return { stdout: result.stdout, stderr, status: result.status, signal: result.signal };
|
|
}
|
|
|
|
const cases = ["three/collision.mjs", "three/buffers-animation.mjs", "npm-static/array-output-parameters.mjs"].flatMap((fixture) =>
|
|
["native", "wasm32-wasi"].map((target) => ({ fixture, target })));
|
|
test.for(cases)("published $fixture runs statically on $target", async ({ fixture, target }, context) => {
|
|
if (target === "wasm32-wasi" && !hasZig) context.skip();
|
|
const dir = await mkdtemp("/tmp/scriptc-spatial-");
|
|
const previousTarget = process.env["SCRIPTC_TARGET"], previousCc = process.env["SCRIPTC_CC"];
|
|
try {
|
|
if(target === "wasm32-wasi") { process.env["SCRIPTC_TARGET"] = target; process.env["SCRIPTC_CC"] = "zigcc"; }
|
|
const pkg = join(dir,"node_modules","spatial-fixture");
|
|
await mkdir(pkg,{recursive:true});
|
|
await writeFile(join(pkg,"package.json"),'{"name":"spatial-fixture","type":"module","main":"index.js"}');
|
|
const entry = join(dir,"main.mjs");
|
|
await writeFile(entry,'import "spatial-fixture";');
|
|
const source = join(import.meta.dirname,"../fixtures",fixture);
|
|
const bundle = await rollup({ input:source, plugins:[{name:"three-cpu-entry",resolveId(id) {
|
|
if(id === "three") return require.resolve("three/src/Three.Core.js");
|
|
if(id.startsWith("three/")) return require.resolve(id);
|
|
return null;
|
|
}}] });
|
|
try { await bundle.write({file:join(pkg,"index.js"),format:"es"}); }
|
|
finally { await bundle.close(); }
|
|
const wasm = target === "wasm32-wasi";
|
|
const output = join(dir,wasm ? "program.wasm" : "program");
|
|
const result = await compile(entry,{outDir:dir,outPath:output,backend:"llvm",dynamic:false,npmStatic:["spatial-fixture"],
|
|
sanitize:!wasm && process.env["SCRIPTC_SAN"] === "1"});
|
|
if(!result.ok) throw new Error(result.diagnostics.map(d=>`${d.code}: ${d.message}`).join("\n"));
|
|
if(wasm) expect([...(await readFile(output)).subarray(0,4)]).toEqual([0,97,115,109]);
|
|
const reference = run(process.execPath,["--no-warnings",source]);
|
|
expect(reference.status).toBe(0);
|
|
expect(run(process.execPath,["--no-warnings",entry])).toEqual(reference);
|
|
expect(wasm ? run(process.execPath,["--no-warnings","-e",wasiRunner,output]) : run(output,[])).toEqual(reference);
|
|
} finally {
|
|
if(previousTarget === undefined) delete process.env["SCRIPTC_TARGET"]; else process.env["SCRIPTC_TARGET"] = previousTarget;
|
|
if(previousCc === undefined) delete process.env["SCRIPTC_CC"]; else process.env["SCRIPTC_CC"] = previousCc;
|
|
await rm(dir,{recursive:true,force:true});
|
|
}
|
|
});
|