Skip to content

Commit ed58065

Browse files
ExE-Bosstargos
authored andcommitted
lib: add bound apply variants of varargs primordials
Co-authored-by: Antoine du Hamel <duhamelantoine1995@gmail.com> PR-URL: #37005 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com>
1 parent 67b58f6 commit ed58065

File tree

3 files changed

+60
-10
lines changed

3 files changed

+60
-10
lines changed

lib/internal/per_context/primordials.js

+56-8
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,36 @@ const {
2121
// `uncurryThis` is equivalent to `func => Function.prototype.call.bind(func)`.
2222
// It is using `bind.bind(call)` to avoid using `Function.prototype.bind`
2323
// and `Function.prototype.call` after it may have been mutated by users.
24-
const { bind, call } = Function.prototype;
24+
const { apply, bind, call } = Function.prototype;
2525
const uncurryThis = bind.bind(call);
2626
primordials.uncurryThis = uncurryThis;
2727

28+
// `applyBind` is equivalent to `func => Function.prototype.apply.bind(func)`.
29+
// It is using `bind.bind(apply)` to avoid using `Function.prototype.bind`
30+
// and `Function.prototype.apply` after it may have been mutated by users.
31+
const applyBind = bind.bind(apply);
32+
primordials.applyBind = applyBind;
33+
34+
// Methods that accept a variable number of arguments, and thus it's useful to
35+
// also create `${prefix}${key}Apply`, which uses `Function.prototype.apply`,
36+
// instead of `Function.prototype.call`, and thus doesn't require iterator
37+
// destructuring.
38+
const varargsMethods = [
39+
// 'ArrayPrototypeConcat' is omitted, because it performs the spread
40+
// on its own for arrays and array-likes with a truthy
41+
// @@isConcatSpreadable symbol property.
42+
'ArrayOf',
43+
'ArrayPrototypePush',
44+
'ArrayPrototypeUnshift',
45+
// 'FunctionPrototypeCall' is omitted, since there's 'ReflectApply'
46+
// and 'FunctionPrototypeApply'.
47+
'MathHypot',
48+
'MathMax',
49+
'MathMin',
50+
'StringPrototypeConcat',
51+
'TypedArrayOf',
52+
];
53+
2854
function getNewKey(key) {
2955
return typeof key === 'symbol' ?
3056
`Symbol${key.description[7].toUpperCase()}${key.description.slice(8)}` :
@@ -51,7 +77,13 @@ function copyPropsRenamed(src, dest, prefix) {
5177
if ('get' in desc) {
5278
copyAccessor(dest, prefix, newKey, desc);
5379
} else {
54-
ReflectDefineProperty(dest, `${prefix}${newKey}`, desc);
80+
const name = `${prefix}${newKey}`;
81+
ReflectDefineProperty(dest, name, desc);
82+
if (varargsMethods.includes(name)) {
83+
ReflectDefineProperty(dest, `${name}Apply`, {
84+
value: applyBind(desc.value, src),
85+
});
86+
}
5587
}
5688
}
5789
}
@@ -63,10 +95,18 @@ function copyPropsRenamedBound(src, dest, prefix) {
6395
if ('get' in desc) {
6496
copyAccessor(dest, prefix, newKey, desc);
6597
} else {
66-
if (typeof desc.value === 'function') {
67-
desc.value = desc.value.bind(src);
98+
const { value } = desc;
99+
if (typeof value === 'function') {
100+
desc.value = value.bind(src);
101+
}
102+
103+
const name = `${prefix}${newKey}`;
104+
ReflectDefineProperty(dest, name, desc);
105+
if (varargsMethods.includes(name)) {
106+
ReflectDefineProperty(dest, `${name}Apply`, {
107+
value: applyBind(value, src),
108+
});
68109
}
69-
ReflectDefineProperty(dest, `${prefix}${newKey}`, desc);
70110
}
71111
}
72112
}
@@ -78,10 +118,18 @@ function copyPrototype(src, dest, prefix) {
78118
if ('get' in desc) {
79119
copyAccessor(dest, prefix, newKey, desc);
80120
} else {
81-
if (typeof desc.value === 'function') {
82-
desc.value = uncurryThis(desc.value);
121+
const { value } = desc;
122+
if (typeof value === 'function') {
123+
desc.value = uncurryThis(value);
124+
}
125+
126+
const name = `${prefix}${newKey}`;
127+
ReflectDefineProperty(dest, name, desc);
128+
if (varargsMethods.includes(name)) {
129+
ReflectDefineProperty(dest, `${name}Apply`, {
130+
value: applyBind(value),
131+
});
83132
}
84-
ReflectDefineProperty(dest, `${prefix}${newKey}`, desc);
85133
}
86134
}
87135
}

lib/internal/util/inspect.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const {
66
ArrayPrototypeFilter,
77
ArrayPrototypeForEach,
88
ArrayPrototypePush,
9+
ArrayPrototypePushApply,
910
ArrayPrototypeSort,
1011
ArrayPrototypeUnshift,
1112
BigIntPrototypeValueOf,
@@ -665,7 +666,7 @@ function getKeys(value, showHidden) {
665666
if (showHidden) {
666667
keys = ObjectGetOwnPropertyNames(value);
667668
if (symbols.length !== 0)
668-
ArrayPrototypePush(keys, ...symbols);
669+
ArrayPrototypePushApply(keys, symbols);
669670
} else {
670671
// This might throw if `value` is a Module Namespace Object from an
671672
// unevaluated module, but we don't want to perform the actual type
@@ -681,7 +682,7 @@ function getKeys(value, showHidden) {
681682
}
682683
if (symbols.length !== 0) {
683684
const filter = (key) => ObjectPrototypePropertyIsEnumerable(value, key);
684-
ArrayPrototypePush(keys, ...ArrayPrototypeFilter(symbols, filter));
685+
ArrayPrototypePushApply(keys, ArrayPrototypeFilter(symbols, filter));
685686
}
686687
}
687688
return keys;

lib/repl.js

+1
Original file line numberDiff line numberDiff line change
@@ -1313,6 +1313,7 @@ function complete(line, callback) {
13131313
if (!this.useGlobal) {
13141314
// When the context is not `global`, builtins are not own
13151315
// properties of it.
1316+
// `globalBuiltins` is a `SafeSet`, not an Array-like.
13161317
ArrayPrototypePush(contextOwnNames, ...globalBuiltins);
13171318
}
13181319
ArrayPrototypePush(completionGroups, contextOwnNames);

0 commit comments

Comments
 (0)