From d139b6d04d206aba18a4c67a54c413b34d59d4dc Mon Sep 17 00:00:00 2001 From: LiviaMedeiros Date: Fri, 18 Apr 2025 01:14:24 +0800 Subject: [PATCH 1/3] util: add internal `assignFunctionName()` function --- lib/internal/util.js | 28 ++++++++++++++++++++ test/parallel/test-internal-util-helpers.js | 29 ++++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/lib/internal/util.js b/lib/internal/util.js index e7c9c3c9c0be2c..fdddda17724853 100644 --- a/lib/internal/util.js +++ b/lib/internal/util.js @@ -38,6 +38,7 @@ const { StringPrototypeToUpperCase, Symbol, SymbolFor, + SymbolPrototypeGetDescription, SymbolReplace, SymbolSplit, } = primordials; @@ -850,10 +851,37 @@ const encodingsMap = { __proto__: null }; for (let i = 0; i < encodings.length; ++i) encodingsMap[encodings[i]] = i; +/** + * Reassigns the .name property of a function. + * Should be used when function can't be initially defined with desired name + * or when desired name should include `#`, `[`, `]`, etc. + * @param {string | symbol} name + * @param {Function} fn + * @param {object} [descriptor] + * @returns {Function} the same function, renamed + */ +function assignFunctionName(name, fn, descriptor = kEmptyObject) { + if (typeof name !== 'string') { + const symbolDescription = SymbolPrototypeGetDescription(name); + assert(symbolDescription !== undefined, 'Attempted to name function after descriptionless Symbol'); + name = `[${symbolDescription}]`; + } + return ObjectDefineProperty(fn, 'name', { + __proto__: null, + writable: false, + enumerable: false, + configurable: true, + ...ObjectGetOwnPropertyDescriptor(fn, 'name'), + ...descriptor, + value: name, + }); +} + module.exports = { getLazy, assertCrypto, assertTypeScript, + assignFunctionName, cachedResult, convertToValidSignal, createClassWrapper, diff --git a/test/parallel/test-internal-util-helpers.js b/test/parallel/test-internal-util-helpers.js index bf60cff9bda4be..01e99d52420d40 100644 --- a/test/parallel/test-internal-util-helpers.js +++ b/test/parallel/test-internal-util-helpers.js @@ -4,7 +4,7 @@ require('../common'); const assert = require('assert'); const { types } = require('util'); -const { isError } = require('internal/util'); +const { assignFunctionName, isError } = require('internal/util'); const vm = require('vm'); // Special cased errors. Test the internal function which is used in @@ -35,3 +35,30 @@ const vm = require('vm'); assert(!(differentRealmErr instanceof Error)); assert(isError(differentRealmErr)); } + +{ + const nameMap = new Map([ + [ 'meaningfulName', 'meaningfulName' ], + [ '', '' ], + [ Symbol.asyncIterator, '[Symbol.asyncIterator]' ], + [ Symbol('notWellKnownSymbol'), '[notWellKnownSymbol]' ], + ]); + for (const fn of [ + () => {}, + function() {}, + function value() {}, + ({ value() {} }).value, + new Function(), + Function(), + function() {}.bind(null), + class {}, + class value {}, + ]) { + for (const [ stringOrSymbol, expectedName ] of nameMap) { + const namedFn = assignFunctionName(stringOrSymbol, fn); + assert.strictEqual(fn, namedFn); + assert.strictEqual(namedFn.name, expectedName); + assert.strictEqual(namedFn.bind(null).name, `bound ${expectedName}`); + } + } +} From f43b61e691735e2ba0d8b69e70bfa84355ef67ae Mon Sep 17 00:00:00 2001 From: LiviaMedeiros Date: Fri, 18 Apr 2025 03:05:42 +0800 Subject: [PATCH 2/3] child_process: give names to promisified `exec()` and `execFile()` --- lib/child_process.js | 5 +++-- test/parallel/test-util-promisify-custom-names.mjs | 10 ++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/child_process.js b/lib/child_process.js index 5c853716a26a4e..21616c69f877ec 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -47,6 +47,7 @@ const { } = primordials; const { + assignFunctionName, convertToValidSignal, getSystemErrorName, kEmptyObject, @@ -236,7 +237,7 @@ function exec(command, options, callback) { } const customPromiseExecFunction = (orig) => { - return (...args) => { + return assignFunctionName(orig.name, function(...args) { const { promise, resolve, reject } = PromiseWithResolvers(); promise.child = orig(...args, (err, stdout, stderr) => { @@ -250,7 +251,7 @@ const customPromiseExecFunction = (orig) => { }); return promise; - }; + }); }; ObjectDefineProperty(exec, promisify.custom, { diff --git a/test/parallel/test-util-promisify-custom-names.mjs b/test/parallel/test-util-promisify-custom-names.mjs index 3ff05d907b5060..79da972ae20d60 100644 --- a/test/parallel/test-util-promisify-custom-names.mjs +++ b/test/parallel/test-util-promisify-custom-names.mjs @@ -9,6 +9,7 @@ import fs from 'node:fs'; import readline from 'node:readline'; import stream from 'node:stream'; import timers from 'node:timers'; +import child_process from 'node:child_process'; assert.strictEqual( @@ -38,3 +39,12 @@ assert.strictEqual( promisify(timers.setTimeout).name, 'setTimeout' ); + +assert.strictEqual( + promisify(child_process.exec).name, + 'exec' +); +assert.strictEqual( + promisify(child_process.execFile).name, + 'execFile' +); From 5292de99e077f3b11e16b4723d8ed5221674bf70 Mon Sep 17 00:00:00 2001 From: LiviaMedeiros Date: Fri, 18 Apr 2025 04:15:17 +0800 Subject: [PATCH 3/3] http2: give name to promisified `connect()` --- lib/internal/http2/core.js | 5 +++-- test/parallel/test-util-promisify-custom-names.mjs | 10 +++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js index 8f14780739d72c..732e1fa6d1e972 100644 --- a/lib/internal/http2/core.js +++ b/lib/internal/http2/core.js @@ -26,6 +26,7 @@ const { } = primordials; const { + assignFunctionName, assertCrypto, customInspectSymbol: kInspect, kEmptyObject, @@ -3405,7 +3406,7 @@ function connect(authority, options, listener) { // Support util.promisify ObjectDefineProperty(connect, promisify.custom, { __proto__: null, - value: (authority, options) => { + value: assignFunctionName('connect', function(authority, options) { return new Promise((resolve, reject) => { const server = connect(authority, options, () => { server.removeListener('error', reject); @@ -3414,7 +3415,7 @@ ObjectDefineProperty(connect, promisify.custom, { server.once('error', reject); }); - }, + }), }); function createSecureServer(options, handler) { diff --git a/test/parallel/test-util-promisify-custom-names.mjs b/test/parallel/test-util-promisify-custom-names.mjs index 79da972ae20d60..3540d20e262e0c 100644 --- a/test/parallel/test-util-promisify-custom-names.mjs +++ b/test/parallel/test-util-promisify-custom-names.mjs @@ -1,4 +1,4 @@ -import '../common/index.mjs'; +import { hasCrypto } from '../common/index.mjs'; import assert from 'node:assert'; import { promisify } from 'node:util'; @@ -48,3 +48,11 @@ assert.strictEqual( promisify(child_process.execFile).name, 'execFile' ); + +if (hasCrypto) { + const http2 = await import('node:http2'); + assert.strictEqual( + promisify(http2.connect).name, + 'connect' + ); +}