// The pure-JS shim tier in one differential sweep: querystring (Node's // '+'-is-a-space parse and %20 stringify), punycode (RFC 3492 both // directions), the legacy constants module, timers/promises, the // async_hooks two-class slice (sync-frame semantics — the parts Node // agrees on), readline's Interface over a stream with the cursor-control // writers, node:url (WHATWG components off the static parser, the file // converters, legacy parse/format/resolve), path's full surface both // families, os identity answers, module.builtinModules/isBuiltin, // process odds and ends, and console.Console over custom streams. import querystring from "node:querystring"; import punycode from "node:punycode"; import constants from "node:constants"; import { setTimeout as delay } from "node:timers/promises"; import timers from "node:timers"; import { AsyncLocalStorage, AsyncResource } from "node:async_hooks"; import readline from "node:readline"; import url, { fileURLToPath, pathToFileURL, URL as NodeURL } from "node:url"; import path from "node:path"; import posixPath from "node:path/posix"; import os from "node:os"; import { builtinModules, isBuiltin } from "node:module"; import { Console } from "node:console"; import { PassThrough, Writable } from "node:stream"; import process from "node:process"; import v8, { startupSnapshot } from "node:v8"; export async function report() { const lines = []; const push = (label, v) => lines.push(label + " " + v); // querystring push("qs-parse:", JSON.stringify(querystring.parse("a=1&a=2&b=x%20y+z&c"))); push("qs-parse-sep:", JSON.stringify(querystring.parse("a:1;b:2", ";", ":"))); push("qs-str:", querystring.stringify({ a: 1, arr: [1, "x", true], u: "héllo ☃", s: "a b", e: "" })); push("qs-escape:", querystring.escape("héllo ☃ a+b!'()*~") + "|" + querystring.unescape("a+b%20c%E2%98%83%zz")); // punycode push("puny:", punycode.encode("mañana") + "|" + punycode.decode("maana-pta") + "|" + punycode.toASCII("bücher.example") + "|" + punycode.toUnicode("xn--bcher-kva.example")); push("puny-ucs2:", JSON.stringify(punycode.ucs2.decode("a𝌆b")) + "|" + punycode.ucs2.encode([97, 119558, 98])); // constants (legacy merge) push("constants:", [constants.F_OK, constants.R_OK, constants.W_OK, constants.SIGINT > 0, constants.O_CREAT > 0, constants.RSA_PKCS1_PADDING].join(",")); // timers const t0 = Date.now(); const v = await delay(10, "delivered"); push("timers-promise:", v + "|" + (Date.now() - t0 >= 5)); push("timers-module:", (timers.setTimeout === setTimeout) + "|" + (typeof setImmediate === "function")); const im = await new Promise((res) => setImmediate((x) => res("imm:" + x), 7)); push("set-immediate:", im); // async_hooks: the sync-frame semantics both sides agree on const als = new AsyncLocalStorage(); const inRun = als.run({ user: "ada" }, () => JSON.stringify(als.getStore())); const nested = als.run({ a: 1 }, () => als.run({ b: 2 }, () => JSON.stringify(als.getStore())) + "|" + JSON.stringify(als.getStore())); push("als:", inRun + "|" + nested + "|" + String(als.getStore())); const res = new AsyncResource("demo"); push("async-resource:", res.runInAsyncScope(function scoped(x) { return "scope:" + x + ":" + (this === undefined || this === null ? "no-this" : "this"); }, undefined, 5)); const bound = AsyncResource.bind(function bfn(y) { return "bound:" + y; }); push("async-bind:", bound(3)); // readline over a stream const input = new PassThrough(); const outChunks = []; const output = new Writable({ write(c, e, cb) { outChunks.push(c.toString("utf8")); cb(); }, }); const rl = readline.createInterface({ input, output }); const got = []; rl.on("line", (l) => got.push(l)); input.write("first\nsecond\r\npart"); input.write("ial\n"); await new Promise((r) => setTimeout(r, 5)); const answered = new Promise((r) => rl.question("q? ", (ans) => r(ans))); input.write("the answer\n"); push("readline-lines:", got.join(",") + "|" + (await answered)); rl.close(); readline.cursorTo(output, 3); readline.clearLine(output, 0); readline.moveCursor(output, 2, -1); push("readline-codes:", JSON.stringify(outChunks.join(""))); // url const u = new NodeURL("https://user:pw@example.com:8080/a/b?x=1&y=2#frag"); push("url:", [u.protocol, u.host, u.hostname, u.port, u.pathname, u.search, u.hash, u.username, u.password, u.origin].join("|")); push("url-sp:", u.searchParams.get("y") + "|" + (NodeURL === globalThis.URL)); push("url-file:", fileURLToPath("file:///tmp/some%20dir/f.txt") + "|" + pathToFileURL("/tmp/some dir/f.txt").href); const parsed = url.parse("https://example.com:8080/p?q=1#h"); push("url-parse:", [parsed.protocol, parsed.host, parsed.port, parsed.pathname, parsed.search, parsed.hash, parsed.path].join("|")); push("url-parse-rel:", JSON.stringify(url.parse("/just/a/path?x=1"))); push("url-format:", url.format({ protocol: "https", hostname: "h.example", port: 444, pathname: "/p", search: "?a=1" })); push("url-resolve:", url.resolve("https://example.com/a/b", "../c") + "|" + url.resolve("https://example.com/a/", "d")); // path (both families; parse/format are the JS ports, the rest is C) push("path:", [path.normalize("/a//b/../c/"), path.relative("/a/b/c", "/a/d"), path.join("a", "", "b", "c/"), path.resolve("/x", "y", "../z")].join("|")); push("path-parse:", JSON.stringify(path.parse("/home/user/file.tar.gz"))); push("path-parse-rel:", JSON.stringify(posixPath.parse("dir/file.txt"))); push("path-format:", path.format({ dir: "/a/b", name: "f", ext: ".t" }) + "|" + path.format({ root: "/", base: "x" })); push("path-win32:", [path.win32.join("C:\\a", "b"), path.win32.isAbsolute("C:\\x"), path.win32.basename("C:\\a\\b.txt"), JSON.stringify(path.win32.parse("C:\\dir\\f.txt"))].join("|")); push("path-posix-mod:", (posixPath === path.posix) + "|" + posixPath.join("q", "r")); // os / module / process odds push("os:", [os.type(), os.endianness(), os.EOL === "\n", typeof os.userInfo().username, os.constants.signals.SIGINT > 0, Array.isArray(os.cpus())].join(",")); push("module:", [builtinModules.includes("fs"), builtinModules.includes("nope"), isBuiltin("node:path"), isBuiltin("lodash")].join(",")); push("process:", [typeof process.version === "string" && process.version.startsWith("v"), typeof process.versions.node, process.pid > 0, typeof process.hrtime()[0], typeof process.hrtime.bigint()].join(",")); const prev = process.hrtime(); const dt = process.hrtime(prev); push("hrtime-pair:", (dt[0] >= 0) + "," + (dt[1] >= 0)); // console.Console over custom streams const outBuf = []; const errBuf = []; const mkStream = (buf) => new Writable({ write(c, e, cb) { buf.push(c.toString("utf8")); cb(); }, }); const c = new Console(mkStream(outBuf), mkStream(errBuf)); c.log("obj: %o and %s and %d", { a: 1 }, "str", 4.5); c.log({ deep: { nested: true } }); c.error("to stderr"); c.count("k"); c.count("k"); push("console-out:", JSON.stringify(outBuf.join(""))); push("console-err:", JSON.stringify(errBuf.join(""))); // process.stdin — a REAL Readable in the island: the harness closes // the pipe at spawn, so async iteration (get-stdin's read path) sees // EOF-empty identically on both sides, and the TTY probe stays absent. process.stdin.setEncoding("utf8"); let stdinData = ""; for await (const chunk of process.stdin) stdinData += chunk; push("stdin:", JSON.stringify(stdinData) + "|" + String(process.stdin.isTTY) + "|" + (typeof process.stdin.setRawMode === "function")); // node:v8 — the loadable slice: startupSnapshot answers for real (never // building), the mutators throw Node's ERR_NOT_BUILDING_SNAPSHOT, heap // statistics carry Node's keys, and the coverage/flag entries are no-ops. push("v8-snapshot:", !!startupSnapshot.isBuildingSnapshot() + "," + (startupSnapshot === v8.startupSnapshot)); let snapErr = "no-throw"; try { v8.startupSnapshot.addSerializeCallback(() => {}); } catch (e) { snapErr = e.code; } let snapErr2 = "no-throw"; try { v8.startupSnapshot.setDeserializeMainFunction(() => {}); } catch (e) { snapErr2 = e.code; } push("v8-snapshot-mutators:", snapErr + "," + snapErr2); const heap = v8.getHeapStatistics(); push("v8-heap:", [typeof heap.used_heap_size, typeof heap.heap_size_limit, typeof heap.external_memory, Array.isArray(v8.getHeapSpaceStatistics()), typeof v8.getHeapCodeStatistics().code_and_metadata_size].join(",")); push("v8-misc:", [Number.isInteger(v8.cachedDataVersionTag()), v8.setFlagsFromString("--stack-size=1000"), v8.takeCoverage(), v8.stopCoverage(), typeof v8.serialize, typeof v8.Serializer, typeof v8.promiseHooks.createHook].join(",")); // the upgraded GLOBAL console formats like Node now console.log("global: %s %d %j", { g: 1 }, "42", { j: [1] }); return lines.join("\n"); }