Skip to content

Commit 850d357

Browse files
ExE-Bossruyadorno
authored andcommitted
lib: refactor primordials.makeSafe to use more primordials
PR-URL: #36865 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
1 parent 64fed31 commit 850d357

File tree

1 file changed

+129
-106
lines changed

1 file changed

+129
-106
lines changed

lib/internal/per_context/primordials.js

+129-106
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
// so that Node.js's builtin modules do not need to later look these up from
77
// the global proxy, which can be mutated by users.
88

9+
const {
10+
defineProperty: ReflectDefineProperty,
11+
getOwnPropertyDescriptor: ReflectGetOwnPropertyDescriptor,
12+
ownKeys: ReflectOwnKeys,
13+
} = Reflect;
14+
915
// TODO(joyeecheung): we can restrict access to these globals in builtin
1016
// modules through the JS linter, for example: ban access such as `Object`
1117
// (which falls back to a lookup in the global proxy) in favor of
@@ -19,159 +25,66 @@ const { bind, call } = Function.prototype;
1925
const uncurryThis = bind.bind(call);
2026
primordials.uncurryThis = uncurryThis;
2127

22-
function copyProps(src, dest) {
23-
for (const key of Reflect.ownKeys(src)) {
24-
if (!Reflect.getOwnPropertyDescriptor(dest, key)) {
25-
Reflect.defineProperty(
26-
dest,
27-
key,
28-
Reflect.getOwnPropertyDescriptor(src, key));
29-
}
30-
}
31-
}
32-
3328
function getNewKey(key) {
3429
return typeof key === 'symbol' ?
3530
`Symbol${key.description[7].toUpperCase()}${key.description.slice(8)}` :
3631
`${key[0].toUpperCase()}${key.slice(1)}`;
3732
}
3833

3934
function copyAccessor(dest, prefix, key, { enumerable, get, set }) {
40-
Reflect.defineProperty(dest, `${prefix}Get${key}`, {
35+
ReflectDefineProperty(dest, `${prefix}Get${key}`, {
4136
value: uncurryThis(get),
4237
enumerable
4338
});
4439
if (set !== undefined) {
45-
Reflect.defineProperty(dest, `${prefix}Set${key}`, {
40+
ReflectDefineProperty(dest, `${prefix}Set${key}`, {
4641
value: uncurryThis(set),
4742
enumerable
4843
});
4944
}
5045
}
5146

5247
function copyPropsRenamed(src, dest, prefix) {
53-
for (const key of Reflect.ownKeys(src)) {
48+
for (const key of ReflectOwnKeys(src)) {
5449
const newKey = getNewKey(key);
55-
const desc = Reflect.getOwnPropertyDescriptor(src, key);
50+
const desc = ReflectGetOwnPropertyDescriptor(src, key);
5651
if ('get' in desc) {
5752
copyAccessor(dest, prefix, newKey, desc);
5853
} else {
59-
Reflect.defineProperty(dest, `${prefix}${newKey}`, desc);
54+
ReflectDefineProperty(dest, `${prefix}${newKey}`, desc);
6055
}
6156
}
6257
}
6358

6459
function copyPropsRenamedBound(src, dest, prefix) {
65-
for (const key of Reflect.ownKeys(src)) {
60+
for (const key of ReflectOwnKeys(src)) {
6661
const newKey = getNewKey(key);
67-
const desc = Reflect.getOwnPropertyDescriptor(src, key);
62+
const desc = ReflectGetOwnPropertyDescriptor(src, key);
6863
if ('get' in desc) {
6964
copyAccessor(dest, prefix, newKey, desc);
7065
} else {
7166
if (typeof desc.value === 'function') {
7267
desc.value = desc.value.bind(src);
7368
}
74-
Reflect.defineProperty(dest, `${prefix}${newKey}`, desc);
69+
ReflectDefineProperty(dest, `${prefix}${newKey}`, desc);
7570
}
7671
}
7772
}
7873

7974
function copyPrototype(src, dest, prefix) {
80-
for (const key of Reflect.ownKeys(src)) {
75+
for (const key of ReflectOwnKeys(src)) {
8176
const newKey = getNewKey(key);
82-
const desc = Reflect.getOwnPropertyDescriptor(src, key);
77+
const desc = ReflectGetOwnPropertyDescriptor(src, key);
8378
if ('get' in desc) {
8479
copyAccessor(dest, prefix, newKey, desc);
8580
} else {
8681
if (typeof desc.value === 'function') {
8782
desc.value = uncurryThis(desc.value);
8883
}
89-
Reflect.defineProperty(dest, `${prefix}${newKey}`, desc);
90-
}
91-
}
92-
}
93-
94-
const createSafeIterator = (factory, next) => {
95-
class SafeIterator {
96-
constructor(iterable) {
97-
this._iterator = factory(iterable);
98-
}
99-
next() {
100-
return next(this._iterator);
101-
}
102-
[Symbol.iterator]() {
103-
return this;
104-
}
105-
}
106-
Object.setPrototypeOf(SafeIterator.prototype, null);
107-
Object.freeze(SafeIterator.prototype);
108-
Object.freeze(SafeIterator);
109-
return SafeIterator;
110-
};
111-
112-
function makeSafe(unsafe, safe) {
113-
if (Symbol.iterator in unsafe.prototype) {
114-
const dummy = new unsafe();
115-
let next; // We can reuse the same `next` method.
116-
117-
for (const key of Reflect.ownKeys(unsafe.prototype)) {
118-
if (!Reflect.getOwnPropertyDescriptor(safe.prototype, key)) {
119-
const desc = Reflect.getOwnPropertyDescriptor(unsafe.prototype, key);
120-
if (
121-
typeof desc.value === 'function' &&
122-
desc.value.length === 0 &&
123-
Symbol.iterator in (desc.value.call(dummy) ?? {})
124-
) {
125-
const createIterator = uncurryThis(desc.value);
126-
next ??= uncurryThis(createIterator(dummy).next);
127-
const SafeIterator = createSafeIterator(createIterator, next);
128-
desc.value = function() {
129-
return new SafeIterator(this);
130-
};
131-
}
132-
Reflect.defineProperty(safe.prototype, key, desc);
133-
}
84+
ReflectDefineProperty(dest, `${prefix}${newKey}`, desc);
13485
}
135-
} else {
136-
copyProps(unsafe.prototype, safe.prototype);
13786
}
138-
copyProps(unsafe, safe);
139-
140-
Object.setPrototypeOf(safe.prototype, null);
141-
Object.freeze(safe.prototype);
142-
Object.freeze(safe);
143-
return safe;
14487
}
145-
primordials.makeSafe = makeSafe;
146-
147-
// Subclass the constructors because we need to use their prototype
148-
// methods later.
149-
// Defining the `constructor` is necessary here to avoid the default
150-
// constructor which uses the user-mutable `%ArrayIteratorPrototype%.next`.
151-
primordials.SafeMap = makeSafe(
152-
Map,
153-
class SafeMap extends Map {
154-
constructor(i) { super(i); } // eslint-disable-line no-useless-constructor
155-
}
156-
);
157-
primordials.SafeWeakMap = makeSafe(
158-
WeakMap,
159-
class SafeWeakMap extends WeakMap {
160-
constructor(i) { super(i); } // eslint-disable-line no-useless-constructor
161-
}
162-
);
163-
primordials.SafeSet = makeSafe(
164-
Set,
165-
class SafeSet extends Set {
166-
constructor(i) { super(i); } // eslint-disable-line no-useless-constructor
167-
}
168-
);
169-
primordials.SafeWeakSet = makeSafe(
170-
WeakSet,
171-
class SafeWeakSet extends WeakSet {
172-
constructor(i) { super(i); } // eslint-disable-line no-useless-constructor
173-
}
174-
);
17588

17689
// Create copies of the namespace objects
17790
[
@@ -256,6 +169,41 @@ primordials.SafeWeakSet = makeSafe(
256169
copyPrototype(original.prototype, primordials, `${name}Prototype`);
257170
});
258171

172+
/* eslint-enable node-core/prefer-primordials */
173+
174+
const {
175+
ArrayPrototypeForEach,
176+
FunctionPrototypeCall,
177+
Map,
178+
ObjectFreeze,
179+
ObjectSetPrototypeOf,
180+
Set,
181+
SymbolIterator,
182+
WeakMap,
183+
WeakSet,
184+
} = primordials;
185+
186+
// Because these functions are used by `makeSafe`, which is exposed
187+
// on the `primordials` object, it's important to use const references
188+
// to the primordials that they use:
189+
const createSafeIterator = (factory, next) => {
190+
class SafeIterator {
191+
constructor(iterable) {
192+
this._iterator = factory(iterable);
193+
}
194+
next() {
195+
return next(this._iterator);
196+
}
197+
[SymbolIterator]() {
198+
return this;
199+
}
200+
}
201+
ObjectSetPrototypeOf(SafeIterator.prototype, null);
202+
ObjectFreeze(SafeIterator.prototype);
203+
ObjectFreeze(SafeIterator);
204+
return SafeIterator;
205+
};
206+
259207
primordials.SafeArrayIterator = createSafeIterator(
260208
primordials.ArrayPrototypeSymbolIterator,
261209
primordials.ArrayIteratorPrototypeNext
@@ -265,5 +213,80 @@ primordials.SafeStringIterator = createSafeIterator(
265213
primordials.StringIteratorPrototypeNext
266214
);
267215

268-
Object.setPrototypeOf(primordials, null);
269-
Object.freeze(primordials);
216+
const copyProps = (src, dest) => {
217+
ArrayPrototypeForEach(ReflectOwnKeys(src), (key) => {
218+
if (!ReflectGetOwnPropertyDescriptor(dest, key)) {
219+
ReflectDefineProperty(
220+
dest,
221+
key,
222+
ReflectGetOwnPropertyDescriptor(src, key));
223+
}
224+
});
225+
};
226+
227+
const makeSafe = (unsafe, safe) => {
228+
if (SymbolIterator in unsafe.prototype) {
229+
const dummy = new unsafe();
230+
let next; // We can reuse the same `next` method.
231+
232+
ArrayPrototypeForEach(ReflectOwnKeys(unsafe.prototype), (key) => {
233+
if (!ReflectGetOwnPropertyDescriptor(safe.prototype, key)) {
234+
const desc = ReflectGetOwnPropertyDescriptor(unsafe.prototype, key);
235+
if (
236+
typeof desc.value === 'function' &&
237+
desc.value.length === 0 &&
238+
SymbolIterator in (FunctionPrototypeCall(desc.value, dummy) ?? {})
239+
) {
240+
const createIterator = uncurryThis(desc.value);
241+
next ??= uncurryThis(createIterator(dummy).next);
242+
const SafeIterator = createSafeIterator(createIterator, next);
243+
desc.value = function() {
244+
return new SafeIterator(this);
245+
};
246+
}
247+
ReflectDefineProperty(safe.prototype, key, desc);
248+
}
249+
});
250+
} else {
251+
copyProps(unsafe.prototype, safe.prototype);
252+
}
253+
copyProps(unsafe, safe);
254+
255+
ObjectSetPrototypeOf(safe.prototype, null);
256+
ObjectFreeze(safe.prototype);
257+
ObjectFreeze(safe);
258+
return safe;
259+
};
260+
primordials.makeSafe = makeSafe;
261+
262+
// Subclass the constructors because we need to use their prototype
263+
// methods later.
264+
// Defining the `constructor` is necessary here to avoid the default
265+
// constructor which uses the user-mutable `%ArrayIteratorPrototype%.next`.
266+
primordials.SafeMap = makeSafe(
267+
Map,
268+
class SafeMap extends Map {
269+
constructor(i) { super(i); } // eslint-disable-line no-useless-constructor
270+
}
271+
);
272+
primordials.SafeWeakMap = makeSafe(
273+
WeakMap,
274+
class SafeWeakMap extends WeakMap {
275+
constructor(i) { super(i); } // eslint-disable-line no-useless-constructor
276+
}
277+
);
278+
primordials.SafeSet = makeSafe(
279+
Set,
280+
class SafeSet extends Set {
281+
constructor(i) { super(i); } // eslint-disable-line no-useless-constructor
282+
}
283+
);
284+
primordials.SafeWeakSet = makeSafe(
285+
WeakSet,
286+
class SafeWeakSet extends WeakSet {
287+
constructor(i) { super(i); } // eslint-disable-line no-useless-constructor
288+
}
289+
);
290+
291+
ObjectSetPrototypeOf(primordials, null);
292+
ObjectFreeze(primordials);

0 commit comments

Comments
 (0)