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;
1925const uncurryThis = bind.bind(call);
2026primordials.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-
3328function 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
3934function 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
5247function 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
6459function 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
7974function 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+
259207primordials.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