77
88import { ArrayPush , ArraySplice , isUndefined } from '@lwc/shared' ;
99
10- const supportsWeakRefs =
11- typeof WeakRef === 'function' && typeof FinalizationRegistry === 'function' ;
12-
1310/**
1411 * A map where the keys are weakly held and the values are a Set that are also each weakly held.
1512 * The goal is to avoid leaking the values, which is what would happen with a WeakMap<K, Set<V>>.
1613 *
1714 * Note that this is currently only intended to be used in dev/PRODDEBUG environments.
1815 * It leaks in legacy browsers, which may be undesired.
16+ *
17+ * This implementation relies on the WeakRef/FinalizationRegistry proposal.
18+ * For some background, see: https://github.com/tc39/proposal-weakrefs
1919 */
20- export interface WeakMultiMap < T extends object , V extends object > {
21- get ( key : T ) : ReadonlySet < V > ;
22- add ( key : T , vm : V ) : void ;
23- delete ( key : T ) : void ;
24- }
25-
26- // In browsers that doesn't support WeakRefs, the values will still leak, but at least the keys won't
27- class LegacyWeakMultiMap < K extends object , V extends object > implements WeakMultiMap < K , V > {
28- private _map : WeakMap < K , Set < V > > = new WeakMap ( ) ;
29-
30- private _getValues ( key : K ) : Set < V > {
31- let values = this . _map . get ( key ) ;
32- if ( isUndefined ( values ) ) {
33- values = new Set ( ) ;
34- this . _map . set ( key , values ) ;
35- }
36- return values ;
37- }
38-
39- get ( key : K ) : ReadonlySet < V > {
40- return this . _getValues ( key ) ;
41- }
42- add ( key : K , vm : V ) {
43- const set = this . _getValues ( key ) ;
44- set . add ( vm ) ;
45- }
46- delete ( key : K ) {
47- this . _map . delete ( key ) ;
48- }
49- }
50-
51- // This implementation relies on the WeakRef/FinalizationRegistry proposal.
52- // For some background, see: https://github.com/tc39/proposal-weakrefs
53- class ModernWeakMultiMap < K extends object , V extends object > implements WeakMultiMap < K , V > {
20+ export class WeakMultimap < K extends object , V extends object > {
5421 private _map = new WeakMap < K , WeakRef < V > [ ] > ( ) ;
5522
5623 private _registry = new FinalizationRegistry ( ( weakRefs : WeakRef < V > [ ] ) => {
@@ -88,8 +55,12 @@ class ModernWeakMultiMap<K extends object, V extends object> implements WeakMult
8855 }
8956 add ( key : K , value : V ) {
9057 const weakRefs = this . _getWeakRefs ( key ) ;
91- // We could check for duplicate values here, but it doesn't seem worth it.
92- // We transform the output into a Set anyway
58+ // Skip adding if already present
59+ for ( const weakRef of weakRefs ) {
60+ if ( weakRef . deref ( ) === value ) {
61+ return ;
62+ }
63+ }
9364 ArrayPush . call ( weakRefs , new WeakRef < V > ( value ) ) ;
9465
9566 // It's important here not to leak the second argument, which is the "held value." The FinalizationRegistry
@@ -105,5 +76,3 @@ class ModernWeakMultiMap<K extends object, V extends object> implements WeakMult
10576 this . _map . delete ( key ) ;
10677 }
10778}
108-
109- export const WeakMultiMap = supportsWeakRefs ? ModernWeakMultiMap : LegacyWeakMultiMap ;
0 commit comments