Something went wrong. Try again.
Monorepo for the nibling.run platform
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081// Node API surface manifests. The compat target is the repo's .node-version.//// node scripts/surface.mjs record [--node=<bin>]// Run surface-walk.cjs under real Node and write compat/node-<version>.json.// Without --node it uses this Node, which must be the pinned version.// node scripts/surface.mjs delta <from> <to>// What Node added, changed or removed between two recorded versions// (e.g. `delta 24.16.0 24.17.0`): the checklist for a version bump.// node scripts/surface.mjs baseline// Rewrite compat/divergences.json from the last tests/surface.spec.ts run// (compat/observed.json): keep existing reasons, add new gaps as "untriaged"// (or "refuse: <reason>" when every gap an entry covers is a marked refusal),// drop entries the kernel now satisfies.import { spawnSync } from "node:child_process";import { existsSync, readFileSync, writeFileSync } from "node:fs";import { resolve } from "node:path";import { fileURLToPath } from "node:url";import { compact, compare, covers, delta, gaps } from "./surface-compare.ts";import { oracleEnv, PINNED } from "./pinned-node.mjs";
const ROOT = resolve(fileURLToPath(new URL("..", import.meta.url)));const GUESTS = resolve(ROOT, "tests/fixtures/guests");const COMPAT = resolve(ROOT, "compat");
const manifestPath = (version) => resolve(COMPAT, `node-${version.replace(/^v/, "")}.json`);const readJson = (path) => JSON.parse(readFileSync(path, "utf8"));const writeJson = (path, value) => writeFileSync(path, JSON.stringify(value, null, 2) + "\n");
function record(args) { const bin = args.find((a) => a.startsWith("--node="))?.slice("--node=".length) ?? process.execPath; const info = spawnSync(bin, ["-p", "JSON.stringify([process.version, process.platform, process.arch])"], { encoding: "utf8" }); if (info.status !== 0) throw new Error(`${bin}: ${info.stderr}`); const [version, platform, arch] = JSON.parse(info.stdout); if (bin === process.execPath && version !== `v${PINNED}`) { throw new Error(`this is node ${version}, .node-version pins ${PINNED}; pass --node=<bin> to record another version`); } const r = spawnSync(bin, ["surface-walk.cjs"], { cwd: GUESTS, encoding: "utf8", maxBuffer: 64 << 20, env: oracleEnv() }); if (r.status !== 0) throw new Error(`surface-walk.cjs exited ${r.status}: ${r.stderr}`); const surface = JSON.parse(r.stdout); writeJson(manifestPath(version), { node: version, platform, arch, surface }); console.log(`${manifestPath(version)}: ${Object.keys(surface).length} paths`);}
function printDelta([from, to]) { if (!from || !to) throw new Error("usage: surface.mjs delta <from-version> <to-version>"); const d = delta(readJson(manifestPath(from)).surface, readJson(manifestPath(to)).surface); for (const g of d.added) console.log(g.actual === undefined ? `+ ${g.path} ${g.expected}` : `~ ${g.path} ${g.actual} -> ${g.expected}`); for (const g of d.removed) console.log(`- ${g.path}`); console.log(`\n${d.added.length} added or changed, ${d.removed.length} removed (outermost paths)`);}
function baseline() { const observedPath = resolve(COMPAT, "observed.json"); if (!existsSync(observedPath)) throw new Error("no compat/observed.json; run `playwright test surface` first"); const node = readJson(manifestPath(PINNED)).surface; const observed = readJson(observedPath); const divergencesPath = resolve(COMPAT, "divergences.json"); const old = existsSync(divergencesPath) ? readJson(divergencesPath) : {}; const { stale } = compare(node, observed, old); const kept = Object.fromEntries(Object.entries(old).filter(([d]) => !stale.includes(d))); const open = gaps(node, observed).filter((g) => !Object.keys(kept).some((d) => covers(d, g.path))); const added = compact(node, open); const REFUSED = "refused: "; for (const path of added) { const under = open.filter((g) => covers(path, g.path)); const reasons = [...new Set(under.map((g) => g.actual?.startsWith(REFUSED) ? g.actual.slice(REFUSED.length) : null))]; kept[path] = under.length && !reasons.includes(null) ? `refuse: ${reasons.join("; ")}` : "untriaged"; } writeJson(divergencesPath, Object.fromEntries(Object.keys(kept).sort().map((k) => [k, kept[k]]))); console.log(`divergences.json: ${Object.keys(kept).length} entries (+${added.length}, -${stale.length})`);}
const [command, ...rest] = process.argv.slice(2);if (command === "record") record(rest);else if (command === "delta") printDelta(rest);else if (command === "baseline") baseline();else { console.error("usage: surface.mjs record [--node=<bin>] | delta <from> <to> | baseline"); process.exit(1);}