Repository: denoland/deno
Pull request: fix(ext/node): use primordials in `ext/node/polyfills/internal_binding/stream_wrap.ts`

Towards #24236. Replaces JS builtins with equivalent primordials.

<!--
Before submitting a PR, please read https://docs.deno.com/runtime/manual/references/contributing

1. Give the PR a descriptive title.

  Examples of good title:
    - fix(std/http): Fix race condition in server
    - docs(console): Update docstrings
    - feat(doc): Handle nested reexports

  Examples of bad title:
    - fix #7123
    - update docs
    - fix bugs

2. Ensure there is a related issue and it is referenced in the PR text.
3. Ensure there are tests that cover the changes.
4. Ensure `cargo test` passes.
5. Ensure `./tools/format.js` passes without changing files.
6. Ensure `./tools/lint.js` passes.
7. Open as a draft PR if your work is still in progress. The CI won't run
   all steps, but you can add '[ci]' to a commit message to force it to.
8. If you would like to run the benchmarks on the CI, add the 'ci-bench' label.
-->


Changed files:
filename: ext/node/polyfills/internal_binding/stream_wrap.ts
patch: @@ -27,11 +27,17 @@
 // - https://github.com/nodejs/node/blob/master/src/stream_wrap.h
 // - https://github.com/nodejs/node/blob/master/src/stream_wrap.cc
 
-// TODO(petamoriken): enable prefer-primordials for node polyfills
-// deno-lint-ignore-file prefer-primordials
-
-import { core } from "ext:core/mod.js";
+import { core, primordials } from "ext:core/mod.js";
 const { internalRidSymbol } = core;
+const {
+  Array,
+  MapPrototypeGet,
+  ObjectPrototypeIsPrototypeOf,
+  PromisePrototypeThen,
+  Symbol,
+  TypedArrayPrototypeSlice,
+  Uint8Array,
+} = primordials;
 import { op_can_write_vectored, op_raw_write_vectored } from "ext:core/ops";
 
 import { TextEncoder } from "ext:deno_web/08_text_encoding.js";
@@ -222,20 +228,23 @@ export class LibuvStreamWrap extends HandleWrap {
       if (typeof chunks[0] === "string") chunks[0] = Buffer.from(chunks[0]);
       if (typeof chunks[1] === "string") chunks[1] = Buffer.from(chunks[1]);
 
-      op_raw_write_vectored(
-        rid,
-        chunks[0],
-        chunks[1],
-      ).then((nwritten) => {
-        try {
-          req.oncomplete(0);
-        } catch {
-          // swallow callback errors.
-        }
-
-        streamBaseState[kBytesWritten] = nwritten;
-        this.bytesWritten += nwritten;
-      });
+      PromisePrototypeThen(
+        op_raw_write_vectored(
+          rid,
+          chunks[0],
+          chunks[1],
+        ),
+        (nwritten) => {
+          try {
+            req.oncomplete(0);
+          } catch {
+            // swallow callback errors.
+          }
+
+          streamBaseState[kBytesWritten] = nwritten;
+          this.bytesWritten += nwritten;
+        },
+      );
 
       return 0;
     }
@@ -261,6 +270,9 @@ export class LibuvStreamWrap extends HandleWrap {
       }
     }
 
+    // Ignoring primordial lint here since the static method `concat` is invoked
+    // via the Node.js `Buffer` class instead of a JS builtin.
+    // deno-lint-ignore prefer-primordials
     return this.writeBuffer(req, Buffer.concat(buffers));
   }
 
@@ -308,7 +320,7 @@ export class LibuvStreamWrap extends HandleWrap {
     try {
       this[kStreamBaseField]?.close();
     } catch {
-      status = codeMap.get("ENOTCONN")!;
+      status = MapPrototypeGet(codeMap, "ENOTCONN")!;
     }
 
     return status;
@@ -359,30 +371,33 @@ export class LibuvStreamWrap extends HandleWrap {
       if (e.message === "cancelled") return null;
 
       if (
-        e instanceof Deno.errors.Interrupted ||
-        e instanceof Deno.errors.BadResource
+        ObjectPrototypeIsPrototypeOf(Deno.errors.Interrupted.prototype, e) ||
+        ObjectPrototypeIsPrototypeOf(Deno.errors.BadResource.prototype, e)
       ) {
-        nread = codeMap.get("EOF")!;
+        nread = MapPrototypeGet(codeMap, "EOF")!;
       } else if (
-        e instanceof Deno.errors.ConnectionReset ||
-        e instanceof Deno.errors.ConnectionAborted
+        ObjectPrototypeIsPrototypeOf(
+          Deno.errors.ConnectionReset.prototype,
+          e,
+        ) ||
+        ObjectPrototypeIsPrototypeOf(Deno.errors.ConnectionAborted.prototype, e)
       ) {
-        nread = codeMap.get("ECONNRESET")!;
+        nread = MapPrototypeGet(codeMap, "ECONNRESET")!;
       } else {
         this[ownerSymbol].destroy(e);
         return;
       }
     }
 
-    nread ??= codeMap.get("EOF")!;
+    nread ??= MapPrototypeGet(codeMap, "EOF")!;
 
     streamBaseState[kReadBytesOrError] = nread;
 
     if (nread > 0) {
       this.bytesRead += nread;
     }
 
-    buf = buf.slice(0, nread);
+    buf = TypedArrayPrototypeSlice(buf, 0, nread);
 
     streamBaseState[kArrayBufferOffset] = 0;
 
@@ -432,12 +447,12 @@ export class LibuvStreamWrap extends HandleWrap {
       let status: number;
       // TODO(cmorten): map err to status codes
       if (
-        e instanceof Deno.errors.BadResource ||
-        e instanceof Deno.errors.BrokenPipe
+        ObjectPrototypeIsPrototypeOf(Deno.errors.BadResource.prototype, e) ||
+        ObjectPrototypeIsPrototypeOf(Deno.errors.BrokenPipe.prototype, e)
       ) {
-        status = codeMap.get("EBADF")!;
+        status = MapPrototypeGet(codeMap, "EBADF")!;
       } else {
-        status = codeMap.get("UNKNOWN")!;
+        status = MapPrototypeGet(codeMap, "UNKNOWN")!;
       }
 
       try {