• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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