Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions src/js/internal/promisify.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const kCustomPromisifiedSymbol = Symbol.for("nodejs.util.promisify.custom");
const kCustomPromisifyArgsSymbol = Symbol("customPromisifyArgs");

const { validateFunction } = require("internal/validators");

function defineCustomPromisify(target, callback) {
Object.defineProperty(target, kCustomPromisifiedSymbol, {
value: callback,
Expand All @@ -19,12 +21,10 @@ function defineCustomPromisifyArgs(target, args) {
}

var promisify = function promisify(original) {
if (typeof original !== "function") throw new TypeError('The "original" argument must be of type Function');
validateFunction(original, "original");
const custom = original[kCustomPromisifiedSymbol];
if (custom) {
if (typeof custom !== "function") {
throw new TypeError('The "util.promisify.custom" argument must be of type Function');
}
validateFunction(custom, "custom");
// ensure that we don't create another promisified function wrapper
return defineCustomPromisify(custom, custom);
}
Expand All @@ -33,7 +33,7 @@ var promisify = function promisify(original) {
function fn(...originalArgs) {
const { promise, resolve, reject } = Promise.withResolvers();
try {
original.$apply(this, [
const maybePromise = original.$apply(this, [
...originalArgs,
function (err, ...values) {
if (err) {
Expand All @@ -57,6 +57,14 @@ var promisify = function promisify(original) {
}
},
]);

if ($isPromise(maybePromise)) {
process.emitWarning(
"Calling promisify on a function that returns a Promise is likely a mistake.",
"DeprecationWarning",
"DEP0174",
);
}
} catch (err) {
reject(err);
}
Expand Down
7 changes: 6 additions & 1 deletion src/js/node/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,12 @@ var access = function access(path, mode, callback) {

const { defineCustomPromisifyArgs } = require("internal/promisify");
var kCustomPromisifiedSymbol = Symbol.for("nodejs.util.promisify.custom");
exists[kCustomPromisifiedSymbol] = path => new Promise(resolve => exists(path, resolve));
{
const existsCb = exists;
exists[kCustomPromisifiedSymbol] = function exists(path) {
return new Promise(resolve => existsCb(path, resolve));
};
}
defineCustomPromisifyArgs(read, ["bytesRead", "buffer"]);
defineCustomPromisifyArgs(readv, ["bytesRead", "buffers"]);
defineCustomPromisifyArgs(write, ["bytesWritten", "buffer"]);
Expand Down
50 changes: 26 additions & 24 deletions src/js/node/readline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2268,32 +2268,34 @@ Interface.prototype.question = function question(query, options, cb) {
}
};

Interface.prototype.question[promisify.custom] = function question(query, options) {
if (options === null || typeof options !== "object") {
options = kEmptyObject;
}

var signal = options?.signal;
{
Interface.prototype.question[promisify.custom] = function question(query, options) {
if (options === null || typeof options !== "object") {
options = kEmptyObject;
}

if (signal && signal.aborted) {
return PromiseReject($makeAbortError(undefined, { cause: signal.reason }));
}
var signal = options?.signal;

return new Promise((resolve, reject) => {
var cb = resolve;
if (signal) {
var onAbort = () => {
reject($makeAbortError(undefined, { cause: signal.reason }));
};
signal.addEventListener("abort", onAbort, { once: true });
cb = answer => {
signal.removeEventListener("abort", onAbort);
resolve(answer);
};
}
this.question(query, options, cb);
});
};
if (signal && signal.aborted) {
return PromiseReject($makeAbortError(undefined, { cause: signal.reason }));
}

return new Promise((resolve, reject) => {
var cb = resolve;
if (signal) {
var onAbort = () => {
reject($makeAbortError(undefined, { cause: signal.reason }));
};
signal.addEventListener("abort", onAbort, { once: true });
cb = answer => {
signal.removeEventListener("abort", onAbort);
resolve(answer);
};
}
this.question(query, options, cb);
});
};
}

/**
* Creates a new `readline.Interface` instance.
Expand Down
25 changes: 14 additions & 11 deletions src/js/node/timers.promises.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
const { validateBoolean, validateAbortSignal, validateObject, validateNumber } = require("internal/validators");

const symbolAsyncIterator = Symbol.asyncIterator;
const setImmediateGlobal = globalThis.setImmediate;
const setTimeoutGlobal = globalThis.setTimeout;
const setIntervalGlobal = globalThis.setInterval;

function asyncIterator({ next: nextFunction, return: returnFunction }) {
const result = {};
Expand All @@ -20,7 +23,7 @@ function asyncIterator({ next: nextFunction, return: returnFunction }) {
return result;
}

function setTimeoutPromise(after = 1, value, options = {}) {
function setTimeout(after = 1, value, options = {}) {
const arguments_ = [].concat(value ?? []);
try {
// If after is a number, but an invalid one (too big, Infinity, NaN), we only want to emit a
Expand Down Expand Up @@ -53,7 +56,7 @@ function setTimeoutPromise(after = 1, value, options = {}) {
}
let onCancel;
const returnValue = new Promise((resolve, reject) => {
const timeout = setTimeout(() => resolve(value), after, ...arguments_);
const timeout = setTimeoutGlobal(() => resolve(value), after, ...arguments_);
if (!reference) {
timeout?.unref?.();
}
Expand All @@ -70,7 +73,7 @@ function setTimeoutPromise(after = 1, value, options = {}) {
: returnValue;
}

function setImmediatePromise(value, options = {}) {
function setImmediate(value, options = {}) {
try {
validateObject(options, "options");
} catch (error) {
Expand All @@ -92,7 +95,7 @@ function setImmediatePromise(value, options = {}) {
}
let onCancel;
const returnValue = new Promise((resolve, reject) => {
const immediate = setImmediate(() => resolve(value));
const immediate = setImmediateGlobal(() => resolve(value));
if (!reference) {
immediate?.unref?.();
}
Expand All @@ -109,7 +112,7 @@ function setImmediatePromise(value, options = {}) {
: returnValue;
}

function setIntervalPromise(after = 1, value, options = {}) {
function setInterval(after = 1, value, options = {}) {
/* eslint-disable no-undefined, no-unreachable-loop, no-loop-func */
try {
// If after is a number, but an invalid one (too big, Infinity, NaN), we only want to emit a
Expand Down Expand Up @@ -166,7 +169,7 @@ function setIntervalPromise(after = 1, value, options = {}) {
try {
let notYielded = 0;
let callback;
interval = setInterval(() => {
interval = setIntervalGlobal(() => {
notYielded++;
if (callback) {
callback();
Expand Down Expand Up @@ -228,11 +231,11 @@ function setIntervalPromise(after = 1, value, options = {}) {
}

export default {
setTimeout: setTimeoutPromise,
setImmediate: setImmediatePromise,
setInterval: setIntervalPromise,
setTimeout,
setImmediate,
setInterval,
scheduler: {
wait: (delay, options) => setTimeoutPromise(delay, undefined, options),
yield: setImmediatePromise,
wait: (delay, options) => setTimeout(delay, undefined, options),
yield: setImmediate,
},
};
40 changes: 40 additions & 0 deletions test/js/node/test/parallel/test-util-promisify-custom-names.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import '../common/index.mjs';
import assert from 'node:assert';
import { promisify } from 'node:util';

// Test that customly promisified methods in [util.promisify.custom]
// have appropriate names

import fs from 'node:fs';
import readline from 'node:readline';
import stream from 'node:stream';
import timers from 'node:timers';


assert.strictEqual(
promisify(fs.exists).name,
'exists'
);

assert.strictEqual(
promisify(readline.Interface.prototype.question).name,
'question',
);

assert.strictEqual(
promisify(stream.finished).name,
'finished'
);
assert.strictEqual(
promisify(stream.pipeline).name,
'pipeline'
);

assert.strictEqual(
promisify(timers.setImmediate).name,
'setImmediate'
);
assert.strictEqual(
promisify(timers.setTimeout).name,
'setTimeout'
);
Loading