Something went wrong. Try again.
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667// The browser entry (src/browser.js, the "default" export condition) must agree with the Node// entry on every input: it shares src/core.js and swaps only the host hooks (fetch +// instantiateStreaming, and TextDecoder-based isUtf8/isAscii for node:buffer's). Node's fetch// can't read file: URLs, so this stubs fetch to serve build/*.wasm as application/wasm. Also// proves transformSync refuses to run before transform has loaded the engine, then works after.// Usage: node test/browser-entry.mjsimport assert from "node:assert/strict";import { readFile } from "node:fs/promises";import { readFileSync } from "node:fs";
globalThis.fetch = async (url) => { assert.equal(new URL(url).protocol, "file:", `browser entry fetched ${url}, expected a file: URL next to src/`); return new Response(await readFile(url), { headers: { "content-type": "application/wasm" } });};
const web = await import("../src/browser.js");const node = await import("../src/index.js");
assert.throws(() => web.transformSync("let x: number = 1;"), /await transform\(\) once/);await web.transform("");await web.transform("", { mode: "downlevel" });
const run = (api, src, mode) => { const errors = []; try { const out = typeof src === "string" ? api.transformSync(src, { mode, onError: (e) => errors.push(e.start) }) : [...api.transformSync(src, { mode, onError: (e) => errors.push(e.start) })].join(""); return { out, errors: errors.join() }; } catch (e) { return { threw: e.message }; }};
const encoder = new TextEncoder();const sources = ["corpus/snippets.jsonl", "corpus/adversarial.jsonl", "corpus/regressions.jsonl", "corpus/downlevel.jsonl"] .flatMap((f) => readFileSync(new URL(`../${f}`, import.meta.url), "utf8").split("\n").filter(Boolean).map((l) => JSON.parse(l))) .filter((s) => typeof s === "string");sources.push("const s = '日本語 漢字 🎉🚀 café';", "const u = '😀😀';");
let cases = 0;let fail = 0;for (const mode of ["erase", "downlevel"]) { for (const src of sources) { const bytes = encoder.encode(src); // Whole string, whole bytes, and bytes split at every offset (so multi-byte splits hit // the browser entry's isUtf8/isAscii), plus a leading BOM and an invalid byte. const inputs = [src, [bytes], [Uint8Array.of(0xef, 0xbb, 0xbf, ...bytes)], [Uint8Array.of(0xff, ...bytes)]]; if (bytes.length !== src.length) for (let i = 1; i < bytes.length; i++) inputs.push([bytes.subarray(0, i), bytes.subarray(i)]); for (const input of inputs) { cases++; const a = run(web, input, mode); const b = run(node, input, mode); if (a.threw !== b.threw || a.out !== b.out || a.errors !== b.errors) { if (fail++ < 5) console.error(`mismatch (${mode}):`, JSON.stringify(src).slice(0, 80), { web: a, node: b }); } } }}
// A fetch-style Response body, the way a service worker hands it over.const body = new Response("let x: number = 1;\nlet s = '漢字';").body;let streamed = "";for await (const piece of web.transform(body)) streamed += piece;assert.equal(streamed, node.transformSync("let x: number = 1;\nlet s = '漢字';"));
console.log(`browser-entry: ${cases} input/mode pairs, ${fail} fail`);if (fail) process.exit(1);