Repository: denoland/deno
Pull request: fix(ext/node): validate callback on `fs.mkdtemp` and `fs.stat`

This allows [parallel/test-fs-makeStatsCallback.js](https://github.com/nodejs/node/blob/v24.2.0/test/parallel/test-fs-makeStatsCallback.js) and [parallel/test-fs-make-callback.js](https://github.com/nodejs/node/blob/v24.2.0/test/parallel/test-fs-make-callback.js) tests to pass.

Changed files:
filename: ext/node/polyfills/_fs/_fs_mkdtemp.ts
patch: @@ -4,12 +4,10 @@
 import { TextDecoder, TextEncoder } from "ext:deno_web/08_text_encoding.js";
 import { existsSync } from "ext:deno_node/_fs/_fs_exists.ts";
 import { mkdir, mkdirSync } from "ext:deno_node/_fs/_fs_mkdir.ts";
-import {
-  ERR_INVALID_ARG_TYPE,
-  ERR_INVALID_OPT_VALUE_ENCODING,
-} from "ext:deno_node/internal/errors.ts";
+import { ERR_INVALID_OPT_VALUE_ENCODING } from "ext:deno_node/internal/errors.ts";
 import { promisify } from "ext:deno_node/internal/util.mjs";
 import { primordials } from "ext:core/mod.js";
+import { makeCallback } from "ext:deno_node/_fs/_fs_common.ts";
 
 const {
   ObjectPrototypeIsPrototypeOf,
@@ -36,16 +34,16 @@ export function mkdtemp(
 ): void;
 export function mkdtemp(
   prefix: string,
-  optionsOrCallback: { encoding: string } | string | mkdtempCallback,
-  maybeCallback?: mkdtempCallback,
+  options: { encoding: string } | string | mkdtempCallback | undefined,
+  callback?: mkdtempCallback,
 ) {
-  const callback: mkdtempCallback | undefined =
-    typeof optionsOrCallback == "function" ? optionsOrCallback : maybeCallback;
-  if (!callback) {
-    throw new ERR_INVALID_ARG_TYPE("callback", "function", callback);
+  if (typeof options === "function") {
+    callback = options;
+    options = undefined;
   }
+  callback = makeCallback(callback);
 
-  const encoding: string | undefined = parseEncoding(optionsOrCallback);
+  const encoding: string | undefined = parseEncoding(options);
   const path = tempDirPath(prefix);
 
   mkdir(

filename: ext/node/polyfills/_fs/_fs_stat.ts
patch: @@ -7,6 +7,7 @@ import { denoErrorToNodeError } from "ext:deno_node/internal/errors.ts";
 import { promisify } from "ext:deno_node/internal/util.mjs";
 import { primordials } from "ext:core/mod.js";
 import { getValidatedPath } from "ext:deno_node/internal/fs/utils.mjs";
+import { makeCallback } from "ext:deno_node/_fs/_fs_common.ts";
 
 const { ObjectCreate, ObjectAssign } = primordials;
 
@@ -354,6 +355,8 @@ export type statCallbackBigInt = (err: Error | null, stat: BigIntStats) => void;
 
 export type statCallback = (err: Error | null, stat: Stats) => void;
 
+const defaultOptions = { bigint: false };
+
 export function stat(path: string | URL, callback: statCallback): void;
 export function stat(
   path: string | URL,
@@ -367,21 +370,15 @@ export function stat(
 ): void;
 export function stat(
   path: string | URL,
-  optionsOrCallback: statCallback | statCallbackBigInt | statOptions,
-  maybeCallback?: statCallback | statCallbackBigInt,
+  options: statCallback | statCallbackBigInt | statOptions = defaultOptions,
+  callback?: statCallback | statCallbackBigInt,
 ) {
-  const callback =
-    (typeof optionsOrCallback === "function"
-      ? optionsOrCallback
-      : maybeCallback) as (
-        ...args: [Error] | [null, BigIntStats | Stats]
-      ) => void;
-  const options = typeof optionsOrCallback === "object"
-    ? optionsOrCallback
-    : { bigint: false };
-
+  if (typeof options === "function") {
+    callback = options;
+    options = defaultOptions;
+  }
+  callback = makeCallback(callback);
   path = getValidatedPath(path).toString();
-  if (!callback) throw new Error("No callback function supplied");
 
   Deno.stat(path).then(
     (stat) => callback(null, CFISBIS(stat, options.bigint)),
@@ -409,7 +406,7 @@ export function statSync(
 ): BigIntStats;
 export function statSync(
   path: string | URL,
-  options: statOptions = { bigint: false, throwIfNoEntry: true },
+  options: statOptions = { ...defaultOptions, throwIfNoEntry: true },
 ): Stats | BigIntStats | undefined {
   path = getValidatedPath(path).toString();
 

filename: tests/node_compat/config.toml
patch: @@ -436,6 +436,8 @@
 "parallel/test-fs-internal-assertencoding.js" = {}
 "parallel/test-fs-link.js" = { flaky = true }
 "parallel/test-fs-long-path.js" = {}
+"parallel/test-fs-make-callback.js" = {}
+"parallel/test-fs-makeStatsCallback.js" = {}
 "parallel/test-fs-open-flags.js" = {}
 "parallel/test-fs-open-no-close.js" = {}
 "parallel/test-fs-open-numeric-flags.js" = {}