aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Colin McDonnell <colinmcd94@gmail.com> 2023-10-05 17:19:33 -0700
committerGravatar Colin McDonnell <colinmcd94@gmail.com> 2023-10-05 17:19:33 -0700
commit16cf1fe5f3f643514098ea31f125244c6c4edbfd (patch)
treeaa7118c826a4174b68ceac79219c97c0997d7b98
parente0e9bc16bffb7fe331b85de607235168b553d6e5 (diff)
downloadbun-16cf1fe5f3f643514098ea31f125244c6c4edbfd.tar.gz
bun-16cf1fe5f3f643514098ea31f125244c6c4edbfd.tar.zst
bun-16cf1fe5f3f643514098ea31f125244c6c4edbfd.zip
Generate compat docs (wip)
-rw-r--r--misctools/nodejs-compat.ts210
1 files changed, 210 insertions, 0 deletions
diff --git a/misctools/nodejs-compat.ts b/misctools/nodejs-compat.ts
new file mode 100644
index 000000000..92d865ee5
--- /dev/null
+++ b/misctools/nodejs-compat.ts
@@ -0,0 +1,210 @@
+const nodejsBuiltinModules = [
+ "assert",
+ "async_hooks",
+ "buffer",
+ "child_process",
+ "cluster",
+ "console",
+ "constants",
+ "crypto",
+ "dgram",
+ "diagnostics_channel",
+ "dns",
+ "domain",
+ "events",
+ "fs",
+ "http",
+ "http2",
+ "https",
+ "inspector",
+ "module",
+ "net",
+ "os",
+ "path",
+ "perf_hooks",
+ "process",
+ "punycode",
+ "querystring",
+ "readline",
+ "repl",
+ "stream",
+ "string_decoder",
+ "timers",
+ "tls",
+ "trace_events",
+ "tty",
+ "url",
+ "util",
+ "v8",
+ "vm",
+ "wasi",
+ "worker_threads",
+ "zlib",
+];
+
+function getModuleKeys(moduleName: string): string[] {
+ const script = `import('${moduleName}').then(mod=>console.log(JSON.stringify(Object.keys(mod))))`;
+ const nodeProc = Bun.spawnSync(["node", "-e", script], {
+ stderr: "ignore",
+ });
+ const nodeKeys: string[] = JSON.parse(nodeProc.stdout.toString());
+ return nodeKeys;
+}
+function getAllProperties(obj = {}) {
+ const allKeys = new Set();
+ do {
+ Reflect.ownKeys(obj).forEach(key => allKeys.add(key));
+ } while ((obj = Object.getPrototypeOf(obj)));
+ return [...allKeys];
+}
+
+function getPrototypeKeys(moduleName: string, className: string): string[] {
+ // const script = `import('${moduleName}').then(mod=>console.log(JSON.stringify(Object.keys(mod.${className}.prototype))))`;
+ const script = `
+ import("${moduleName}").then((mod) => {
+ const lines = new Set();
+ let obj = mod.${className}.prototype;
+ do {
+ Reflect.ownKeys(obj).forEach((key) => lines.add(key));
+ } while ((obj = Object.getPrototypeOf(obj)));
+ console.log("[", [...lines].map(k => \`"\${String(k)}"\`).join(","), "]");
+});`.replace(/\n/g, "");
+ // remove whitespace
+ // .replace(/\s+/g, "");
+ // console.log(script);
+ const nodeProc = Bun.spawnSync(["node", "-e", script], {
+ // stderr: "inherit",
+ // stdout: "inherit",
+ });
+ // console.log(nodeProc.stdout.toString());
+ const nodeKeys: string[] = JSON.parse(nodeProc.stdout.toString());
+
+ return nodeKeys;
+}
+const SKIP: Record<string, boolean> = {
+ "buffer.File": true,
+ "process.abort": true,
+ "process.exit": true,
+ "process.kill": true,
+ "process.reallyExit": true,
+ "vm.Script": true,
+ "zlib.deflate": true,
+ "zlib.inflate": true,
+ "zlib.unzip": true,
+ "zlib.deflateRaw": true,
+ "zlib.gunzip": true,
+ "zlib.gzip": true,
+ "zlib.inflateRaw": true,
+ "console.assert": true,
+ "console.count": true,
+ // "fs.mkdtempSync": true,
+ // "fs.read": true,
+ // "fs.readv": true,
+ // "fs.writev": true,
+ // "fs.writeSync": true,
+ // "fs.writeFileSync": true,
+ // "fs.writeFile": true,
+ // "fs.write": true,
+ // "fs.writevSync": true,
+ // "fs.watchFile": true,
+ // "fs.watch": true,
+ // "fs.utimesSync": true,
+ // "fs.utimes": true,
+ // "fs.unwatchFile": true,
+ // "fs.unlinkSync": true,
+ // "fs.unlink": true,
+ // "fs.truncateSync": true,
+ // "fs.truncate": true,
+ // "fs.symlinkSync": true,
+};
+
+for (const moduleName of nodejsBuiltinModules) {
+ const heading = `======== ${moduleName} ========`;
+
+ // print equals sign to match the length of heading
+ console.log("\n\n" + "=".repeat(heading.length));
+ console.log(heading);
+ console.log("=".repeat(heading.length));
+ const mod = await import(moduleName);
+ const bunKeys: string[] = Object.keys(mod);
+ const nodeKeys = getModuleKeys(moduleName);
+
+ // print top-level elements that are missing
+ // const missingKeys = nodeKeys
+ // .filter((key) => !bunKeys.includes(key))
+ // .filter((k) => !k.startsWith("_"));
+ // const notMissing = nodeKeys.filter((key) => bunKeys.includes(key));
+
+ // if (missingKeys.length === 0) {
+ // console.log(`Fully implemented.`);
+ // } else {
+ // console.log(`Missing ${missingKeys.map((k) => `\`${k}\``).join(" ")}`);
+ // }
+ console.log();
+
+ // check for prototype compatibility
+ let missing = false;
+ for (const k of nodeKeys) {
+ if (k.startsWith("_")) continue;
+ if (!bunKeys.includes(k)) {
+ missing = true;
+ console.log(` [${moduleName}.${k}] Not implemented.`);
+ continue;
+ }
+ if (mod[k] && typeof mod[k] === "function") {
+ if (!!mod[k].prototype) {
+ const className = `${moduleName}.${k}`;
+
+ const bunProtoKeys = getAllProperties(mod[k].prototype);
+ // console.log(mod[k].prototype);
+ // getAllProperties;
+ // for (const l in mod[k].prototype) {
+ // bunProtoKeys.push(l);
+ // }
+
+ const nodeProtoKeys = getPrototypeKeys(moduleName, k);
+ // console.log("nodeProtoKeys", nodeProtoKeys);
+ // console.log("bunProtoKeys", bunProtoKeys);
+
+ // console.log("nodeProtoKeys", nodeProtoKeys);
+ // console.log("bunProtoKeys", bunProtoKeys);
+ const missingProtoKeys = nodeProtoKeys.filter(key => !bunProtoKeys.includes(key));
+ // const notMissingProtoKeys = nodeProtoKeys.filter((key) =>
+ // bunProtoKeys.includes(key)
+ // );
+ if (missingProtoKeys.length === 0) {
+ console.log(` [${className}] Fully implemented.`);
+ } else {
+ missing = true;
+ console.log(
+ ` [${className}] Missing ${missingProtoKeys
+ .filter(k => !k.startsWith("_"))
+ .map(k => `\`${k}\``)
+ .join(" ")}`,
+ );
+ }
+ } else {
+ if (moduleName === "console") continue;
+ if (moduleName === "fs") continue;
+ if (SKIP[`${moduleName}.${k}`]) continue;
+ try {
+ // console.log(`trying ${moduleName}.${k}...`);
+ await mod[k]();
+ await Bun.sleep(1);
+ } catch (err: any) {
+ if ((err?.message as string).includes("not yet implemented")) {
+ missing = true;
+ console.log(` [${moduleName}.${k}] Not implemented.`);
+ }
+ }
+ }
+ }
+ }
+
+ if (!missing) {
+ console.log(`[${moduleName}] Fully implemented.`);
+ }
+}
+
+console.log("\n\n================\nDONE.");
+process.exit();