1'use strict'; 2 3const { 4 makeSafe, 5 ObjectFreeze, 6 SafeSet, 7 SafeWeakMap, 8 SymbolIterator, 9 globalThis, 10} = primordials; 11 12// TODO(aduh95): Add FinalizationRegistry to primordials 13const SafeFinalizationRegistry = makeSafe( 14 globalThis.FinalizationRegistry, 15 class SafeFinalizationRegistry extends globalThis.FinalizationRegistry {} 16); 17 18// TODO(aduh95): Add WeakRef to primordials 19const SafeWeakRef = makeSafe( 20 globalThis.WeakRef, 21 class SafeWeakRef extends globalThis.WeakRef {} 22); 23 24// This class is modified from the example code in the WeakRefs specification: 25// https://github.com/tc39/proposal-weakrefs 26// Licensed under ECMA's MIT-style license, see: 27// https://github.com/tc39/ecma262/blob/HEAD/LICENSE.md 28class IterableWeakMap { 29 #weakMap = new SafeWeakMap(); 30 #refSet = new SafeSet(); 31 #finalizationGroup = new SafeFinalizationRegistry(cleanup); 32 33 set(key, value) { 34 const entry = this.#weakMap.get(key); 35 if (entry) { 36 // If there's already an entry for the object represented by "key", 37 // the value can be updated without creating a new WeakRef: 38 this.#weakMap.set(key, { value, ref: entry.ref }); 39 } else { 40 const ref = new SafeWeakRef(key); 41 this.#weakMap.set(key, { value, ref }); 42 this.#refSet.add(ref); 43 this.#finalizationGroup.register(key, { 44 set: this.#refSet, 45 ref 46 }, ref); 47 } 48 } 49 50 get(key) { 51 return this.#weakMap.get(key)?.value; 52 } 53 54 has(key) { 55 return this.#weakMap.has(key); 56 } 57 58 delete(key) { 59 const entry = this.#weakMap.get(key); 60 if (!entry) { 61 return false; 62 } 63 this.#weakMap.delete(key); 64 this.#refSet.delete(entry.ref); 65 this.#finalizationGroup.unregister(entry.ref); 66 return true; 67 } 68 69 [SymbolIterator]() { 70 const iterator = this.#refSet[SymbolIterator](); 71 72 const next = () => { 73 const result = iterator.next(); 74 if (result.done) return result; 75 const key = result.value.deref(); 76 if (key == null) return next(); 77 const { value } = this.#weakMap.get(key); 78 return { done: false, value }; 79 }; 80 81 return { 82 [SymbolIterator]() { return this; }, 83 next, 84 }; 85 } 86} 87 88function cleanup({ set, ref }) { 89 set.delete(ref); 90} 91 92ObjectFreeze(IterableWeakMap.prototype); 93 94module.exports = { 95 IterableWeakMap, 96}; 97