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