Skip to content

Latest commit

 

History

History
364 lines (258 loc) · 15.1 KB

File metadata and controls

364 lines (258 loc) · 15.1 KB

Node.js compatibility

Detailed per-module status for Home's node:* namespace. This is the drill-down view; the at-a-glance row is in the README parity status section.

Status: The JS-callable bridge is live. A require() (CommonJS) of the node:* modules below works through Home's own JavaScriptCore realm — exercised today by home eval and HOME_NATIVE_RUN=1 home run, NOT by delegating to system bun. 24 modules are JS-callable (🟡) as behavioral subsets, each unit-tested in packages/runtime/src/jsc/node_modules.zig (+ jsc/spawn_global.zig for child_process). Several are backed by native Zig: node:zlib (std.compress.flate), node:crypto HMAC/pbkdf2 (std.crypto), node:fs/child_process (std.process / native fs).

Scope caveat: 🟡 here means "callable through Home's realm as a useful subset", NOT "passes the Node test suite" (we don't run it yet) and NOT "wired into the bun-corpus gate" (that still routes through the separate bootstrap harness). The remaining 🔴 are server-side sockets and heavy runtime (tls/http2/dgram/worker_threads/cluster/…); client networking (dns/net/http/https) is now 🟡 (client-only).

Legend:

  • 🟢 Fully implemented — JS-callable today, passes its slice of the Node test suite at the rate noted.
  • 🟡 Partially implemented — JS-callable (through Home's realm), with missing APIs / caveats noted inline.
  • 🔴 Not implemented — no JS surface yet; Zig substrate may exist.
  • Won't implement — explicitly out of scope (no Node-only internals like node:wasi legacy quirks).

Built-in modules

🟡 JS-callable. ok/equal/notEqual/strictEqual/notStrictEqual, deepEqual/deepStrictEqual/notDeepStrictEqual, throws/doesNotThrow, rejects/doesNotReject, match/doesNotMatch, ifError, fail, AssertionError (code ERR_ASSERTION), assert.strict. Missing: full AssertionError diff formatting (the myers_diff.zig substrate isn't wired to messages yet).

🔴 Not implemented.

🟡 JS-callable (Buffer extends Uint8Array, also a global). from (utf8/hex/base64/base64url/latin1/array/ArrayBuffer/view), alloc/ allocUnsafe, isBuffer, byteLength, concat, compare (static + instance), equals, toString (utf8/hex/base64/base64url/latin1/ascii), toJSON, subarray (memory-sharing view), and read/write UInt8/Int8, UInt16/Int16 LE+BE, UInt32/Int32 LE+BE, BigUInt64 LE/BE, Float/Double LE. Missing: Blob, File, the full read/write variant matrix, SlowBuffer, transcode. Zig substrate: node/buffer.zig.

🟡 JS-callable, mapped onto Home's native Bun.spawnSync: spawnSync/execSync/execFileSync (Node result shapes) + exec/ execFile (async callback) + spawn (EventEmitter emitting stdout/stderr data/end and exit/close). Caveat: eager — children run to completion synchronously under the hood (no live streaming / interactive stdin yet). fork/IPC not implemented.

🔴 Not implemented.

🟡 JS-callable — require("node:console") returns the realm's console global (log/info/debug/error/warn/trace/dir).

🟡 JS-callable — POSIX/Darwin subset: O_* open flags, F_OK/R_OK/ W_OK/X_OK, S_IF* mode bits, SIG* signal numbers. Zig substrate: packages/runtime/src/node/os_constants.zig.

🟡 JS-callable. createHash (sha256/sha512/sha1/md5), createHmac (HMAC over native hash), pbkdf2/pbkdf2Sync (native std.crypto.pwhash, sha1/256/512 — RFC 6070 verified), hkdf/hkdfSync (native std.crypto.kdf.hkdf, sha256/512 — RFC 5869 verified), scrypt/scryptSync (native std.crypto.pwhash.scrypt, N/r/p — RFC 7914 verified), randomBytes, randomFillSync, randomInt, randomUUID (v4), timingSafeEqual, getHashes. Missing: createCipheriv/createDecipheriv, createSign/verify, KeyObject, X.509 — the OpenSSL/BoringSSL-backed surfaces. Zig substrate: node/crypto.zig.

🔴 Not implemented (needs UDP sockets).

🔴 Not implemented.

🔴 Not implemented (needs resolver bindings).

🟡 JS-callable. EventEmitter (on/once/off/emit/addListener/ prependListener/removeListener/removeAllListeners/listeners/ listenerCount/eventNames/setMaxListeners), events.once(emitter,name) → Promise, events.getEventListeners. Missing: events.on async iterator, captureRejections, EventTarget interop. Zig substrate: node/events.zig.

🟡 JS-callable, backed by Home's native fs. Sync: readFileSync/writeFileSync/existsSync/statSync/mkdirSync/ appendFileSync. Callback: readFile/writeFile. Streams: createReadStream/createWriteStream (on node:stream), readdirSync/readdir (+withFileTypes), unlinkSync/unlink, renameSync/rename, rmSync/rmdirSync (recursive). fs.promises (see below). Missing: copyFile/watch/open/readSync/writeSync, full Stats instances, most async callback variants. Zig substrate: node/fs.zig, Stat.zig, StatFS.zig, dir_iterator.zig, fs_events.zig, node_fs_constant.zig, time_like.zig.

🟡 JS-callable (require("node:fs/promises") or fs.promises): readFile/writeFile/appendFile/mkdir/stat/access/readdir/ unlink/rm/rename. Missing: open/FileHandle/copyFile/cp/watch.

🔴 Not implemented (needs the socket/server stack).

🔴 Not implemented.

🔴 Not implemented.

🔴 Not implemented.

🔴 Not implemented (the realm exposes a CommonJS require global, but the node:module API — createRequire/Module/builtinModules — is not).

🔴 Not implemented (needs TCP/IPC sockets). Zig substrate: packages/runtime/src/node/node_net_binding.zig.

🟡 JS-callable. platform/arch/type/release/machine/version, EOL, homedir/tmpdir/hostname, cpus/totalmem/freemem (placeholder values), endianness, loadavg, uptime, availableParallelism, networkInterfaces ({}), userInfo, constants.signals, getPriority/setPriority, devNull. Several derive from process/navigator rather than syscalls. Zig substrate: node/os.zig, os_constants.zig.

🟡 JS-callable. Full POSIX surface (join/normalize/resolve/ dirname/basename/extname/isAbsolute/relative/parse/format/ sep/delimiter), plus path.posix/path.win32 namespaces, path.matchesGlob, path.toNamespacedPath. Win32 is a backslash-aware subset. (The verbatim Bun Zig port at node/path.zig is not yet the backing impl — the current impl is the realm's JS port.)

🟡 JS-callable — { performance, PerformanceObserver (stub) }. Missing PerformanceObserver actually observing, performance.mark/measure entries.

🟡 JS-callable — require("node:process") returns the realm's process global: argv, env, platform, arch, version/versions, pid, cwd(), exit(), nextTick(), stdout/stderr .write. Missing: EventEmitter surface, hrtime, memoryUsage/cpuUsage, signal handlers, process.binding. Zig substrate: node/process.zig.

🔴 Not implemented.

🟡 JS-callable — parse/stringify/escape/unescape (duplicate keys preserved as arrays). Zig substrate: node/querystring.zig.

🟡 JS-callable — createInterface({ input }) reads lines from a Readable input, emitting line/close (CRLF-trimmed). question is a stub. Missing: interactive/output mode, history, cursor control.

🔴 Not implemented.

🔴 Not implemented.

🟡 JS-callable, flowing-mode on EventEmitter: Readable (push/read/ resume/pause/pipe/Readable.from/[Symbol.asyncIterator]), Writable, Transform, PassThrough, Duplex, and stream.finished/ stream.pipeline (callback). Missing: object-mode nuances, backpressure, highWaterMark, cork/uncork, the web-streams bridge. Zig substrate: node/stream.zig.

🔴 Not implemented.

🟡 JS-callable — stream.promises.pipeline / finished (also via require("node:stream/promises")).

🔴 Not implemented (no WHATWG ReadableStream/WritableStream/ TransformStream yet).

🟡 JS-callable — StringDecoder with UTF-8 chunk-boundary handling (buffers an incomplete trailing multibyte sequence between writes); non-utf8 encodings fall back to whole-chunk Buffer.toString. Zig substrate: node/string_decoder.zig.

🔴 Not implemented. Will land as part of home test (Phase 12.8).

🟡 JS-callable — setTimeout/clearTimeout/setInterval/clearInterval/ setImmediate/clearImmediate (re-exporting the realm's event-loop timers) + timers.promises.setTimeout.

🟡 JS-callable — setTimeout(ms, value) → Promise (via require("node:timers/promises")). Missing setInterval/setImmediate async-iterator forms.

🔴 Not implemented (needs TLS sockets).

🔴 Not implemented.

🟡 JS-callable — isatty() (returns false for now), ReadStream/ WriteStream stubs. Missing real tty detection / window-size / raw mode. Zig substrate: node/tty.zig, core/tty.zig.

🟡 JS-callable — URL/URLSearchParams (the realm's WHATWG globals), fileURLToPath/pathToFileURL, format. Missing legacy url.parse/ resolve (the old Url object shape). Zig substrate: node/url.zig.

🟡 JS-callable — inspect, format, promisify, callbackify, inherits, deprecate, isDeepStrictEqual, stripVTControlCharacters, toUSVString, debuglog, TextEncoder/TextDecoder, parseArgs (long/short/=value/clustered/boolean+string/multiple/defaults/ positionals/--), and types.* (isDate/isRegExp/isPromise/isMap/isSet/ isArrayBuffer/isTypedArray/isAsyncFunction/isNativeError/isAnyArrayBuffer). Zig substrate: node/util.zig, util/parse_args_utils.zig, types.zig.

❌ Won't implement. Home runs on JavaScriptCore, not V8 — the serializer and heap-snapshot APIs are V8-specific and have no equivalent in JSC.

🟡 JS-callable — vm.runInThisContext(code) + vm.Script(code).runInThisContext() evaluate in the realm's current global via JSC (JSEvaluateScript). createContext/isContext present; runInNewContext/compileFunction throw ENOSYS (no context isolation yet).

🔴 Not implemented.

🔴 Not implemented.

🟡 JS-callable, native (Zig std.compress.flate): gzipSync/ gunzipSync/deflateSync/inflateSync/deflateRawSync/inflateRawSync

  • async (callback) gzip/gunzip/deflate/inflate. Missing: brotli, streaming Gzip/Gunzip transform classes, options (level/strategy).

Node.js globals

🟡 JS-callable in the realm: process, Buffer, console, the timer functions (setTimeout/setInterval/setImmediate + clearX), queueMicrotask, fetch (data:/file:/http(s)), URL, URLSearchParams, TextEncoder/TextDecoder, crypto (getRandomValues/randomUUID), performance, structuredClone, atob/btoa, global/self. Missing: WebSocket, the WHATWG *Stream family, navigator (intentionally absent to prove non-delegation).

Summary

Status Count %
🟢 Fully implemented 0 0%
🟡 Partially implemented (JS-callable subset) 36 ~77%
🔴 Not implemented 10 ~21%
❌ Won't implement 1 ~2%

🟡 modules (JS-callable via Home's realm — home eval / HOME_NATIVE_RUN): assert, async_hooks, buffer, child_process, console, constants, crypto, diagnostics_channel, dns, events, fs, fs/promises, http, https, module, net, os, path, perf_hooks, process, punycode, querystring, readline, readline/promises, stream, stream/consumers, stream/promises, stream/web, string_decoder, timers, timers/promises, tty, url, util, vm, zlib.

Still 🔴 (the next frontier — server-side sockets + heavy runtime): http2, tls, dgram, worker_threads, cluster, repl, wasi, inspector, trace_events, test.

Honest caveats: (1) 🟡 = a useful subset callable through Home's own JSC realm, not a full module nor Node-test-suite-verified — e.g. net/http are client-only (real net.connect via std.Io.net; http/https request/get over the realm's fetch), with createServer/duplex streaming still parked on the event loop; (2) these are not yet wired into the bun-corpus gate (which still routes through the bootstrap text-rewrite harness), so they do not yet move the corpus pass-count — that needs the loader/runtime convergence work tracked in BUN_PARITY_PLAN.md.