Skip to content

Commit 94c720c

Browse files
LiviaMedeirostargos
authored andcommitted
util: add internal assignFunctionName() function
PR-URL: #57916 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Vinícius Lourenço Claro Cardoso <contact@viniciusl.com.br> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 4c6f73c commit 94c720c

File tree

2 files changed

+56
-1
lines changed

2 files changed

+56
-1
lines changed

lib/internal/util.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ const {
4141
StringPrototypeToUpperCase,
4242
Symbol,
4343
SymbolFor,
44+
SymbolPrototypeGetDescription,
4445
SymbolReplace,
4546
SymbolSplit,
4647
} = primordials;
@@ -906,10 +907,37 @@ const encodingsMap = { __proto__: null };
906907
for (let i = 0; i < encodings.length; ++i)
907908
encodingsMap[encodings[i]] = i;
908909

910+
/**
911+
* Reassigns the .name property of a function.
912+
* Should be used when function can't be initially defined with desired name
913+
* or when desired name should include `#`, `[`, `]`, etc.
914+
* @param {string | symbol} name
915+
* @param {Function} fn
916+
* @param {object} [descriptor]
917+
* @returns {Function} the same function, renamed
918+
*/
919+
function assignFunctionName(name, fn, descriptor = kEmptyObject) {
920+
if (typeof name !== 'string') {
921+
const symbolDescription = SymbolPrototypeGetDescription(name);
922+
assert(symbolDescription !== undefined, 'Attempted to name function after descriptionless Symbol');
923+
name = `[${symbolDescription}]`;
924+
}
925+
return ObjectDefineProperty(fn, 'name', {
926+
__proto__: null,
927+
writable: false,
928+
enumerable: false,
929+
configurable: true,
930+
...ObjectGetOwnPropertyDescriptor(fn, 'name'),
931+
...descriptor,
932+
value: name,
933+
});
934+
}
935+
909936
module.exports = {
910937
getLazy,
911938
assertCrypto,
912939
assertTypeScript,
940+
assignFunctionName,
913941
cachedResult,
914942
convertToValidSignal,
915943
createClassWrapper,

test/parallel/test-internal-util-helpers.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
require('../common');
55
const assert = require('assert');
66
const { types } = require('util');
7-
const { isError } = require('internal/util');
7+
const { assignFunctionName, isError } = require('internal/util');
88
const vm = require('vm');
99

1010
// Special cased errors. Test the internal function which is used in
@@ -35,3 +35,30 @@ const vm = require('vm');
3535
assert(!(differentRealmErr instanceof Error));
3636
assert(isError(differentRealmErr));
3737
}
38+
39+
{
40+
const nameMap = new Map([
41+
[ 'meaningfulName', 'meaningfulName' ],
42+
[ '', '' ],
43+
[ Symbol.asyncIterator, '[Symbol.asyncIterator]' ],
44+
[ Symbol('notWellKnownSymbol'), '[notWellKnownSymbol]' ],
45+
]);
46+
for (const fn of [
47+
() => {},
48+
function() {},
49+
function value() {},
50+
({ value() {} }).value,
51+
new Function(),
52+
Function(),
53+
function() {}.bind(null),
54+
class {},
55+
class value {},
56+
]) {
57+
for (const [ stringOrSymbol, expectedName ] of nameMap) {
58+
const namedFn = assignFunctionName(stringOrSymbol, fn);
59+
assert.strictEqual(fn, namedFn);
60+
assert.strictEqual(namedFn.name, expectedName);
61+
assert.strictEqual(namedFn.bind(null).name, `bound ${expectedName}`);
62+
}
63+
}
64+
}

0 commit comments

Comments
 (0)