atom.io 0.20.3 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/data/dist/index.cjs +1 -1
  2. package/data/dist/index.js +1 -1
  3. package/data/src/join.ts +2 -2
  4. package/dist/{chunk-SMZRGPN6.js → chunk-KGZGBCYS.js} +2 -2
  5. package/dist/chunk-PNIHPILQ.js +8 -0
  6. package/dist/{chunk-2AIFLP2B.js → chunk-RT43TVKP.js} +2 -2
  7. package/dist/index.cjs +4 -4
  8. package/dist/index.d.ts +2 -2
  9. package/dist/index.js +5 -7
  10. package/internal/dist/index.cjs +31 -26
  11. package/internal/dist/index.d.ts +10 -6
  12. package/internal/dist/index.js +30 -25
  13. package/internal/src/atom/create-regular-atom.ts +1 -1
  14. package/internal/src/atom/dispose-atom.ts +42 -0
  15. package/internal/src/atom/index.ts +1 -1
  16. package/internal/src/selector/{delete-selector.ts → dispose-selector.ts} +3 -2
  17. package/internal/src/selector/index.ts +1 -1
  18. package/internal/src/store/deposit.ts +5 -0
  19. package/internal/src/store/store.ts +5 -1
  20. package/introspection/dist/index.cjs +250 -106
  21. package/introspection/dist/index.d.ts +43 -6
  22. package/introspection/dist/index.js +225 -83
  23. package/introspection/src/attach-atom-index.ts +68 -47
  24. package/introspection/src/attach-selector-index.ts +76 -59
  25. package/introspection/src/auditor.ts +135 -0
  26. package/introspection/src/index.ts +8 -18
  27. package/package.json +9 -9
  28. package/react-devtools/dist/index.cjs +3 -3
  29. package/react-devtools/dist/index.d.ts +5 -5
  30. package/react-devtools/dist/index.js +4 -4
  31. package/react-devtools/src/StateIndex.tsx +8 -27
  32. package/realtime-client/dist/index.cjs +1 -1
  33. package/realtime-client/dist/index.js +1 -1
  34. package/realtime-client/src/sync-continuity.ts +2 -2
  35. package/realtime-react/dist/index.cjs +1 -1
  36. package/realtime-react/dist/index.js +1 -1
  37. package/realtime-server/dist/index.cjs +2 -2
  38. package/realtime-server/dist/index.js +1 -1
  39. package/realtime-testing/dist/index.cjs +4 -4
  40. package/realtime-testing/dist/index.js +1 -1
  41. package/src/dispose.ts +3 -3
  42. package/internal/src/atom/delete-atom.ts +0 -40
@@ -1,60 +1,85 @@
1
- import { __spreadValues, __spreadProps } from '../../dist/chunk-F2X4B4VY.js';
1
+ import { getState } from '../../dist/chunk-PNIHPILQ.js';
2
+ import { __spreadValues } from '../../dist/chunk-F2X4B4VY.js';
2
3
  import * as Internal from 'atom.io/internal';
3
- import { createRegularAtom, newest, createStandaloneSelector, IMPLICIT, createRegularAtomFamily, Subject, createSelectorFamily } from 'atom.io/internal';
4
+ import { createRegularAtom, deposit, createStandaloneSelector, IMPLICIT, createRegularAtomFamily, Subject, createSelectorFamily } from 'atom.io/internal';
4
5
 
5
6
  var attachAtomIndex = (store = IMPLICIT.STORE) => {
6
- console.log(store.config);
7
7
  const atomTokenIndexState__INTERNAL = createRegularAtom(
8
8
  {
9
9
  key: `\u{1F441}\u200D\u{1F5E8} Atom Token Index (Internal)`,
10
10
  default: () => {
11
- const defaultAtomIndex = [...store.atoms].filter(([key]) => !key.includes(`\u{1F441}\u200D\u{1F5E8}`)).reduce((acc, [key, atom]) => {
12
- acc[key] = { key, type: atom.type };
13
- return acc;
14
- }, {});
15
- return defaultAtomIndex;
11
+ const base = /* @__PURE__ */ new Map();
12
+ for (const [key, val] of store.atoms) {
13
+ if (!key.includes(`\u{1F441}\u200D\u{1F5E8}`)) {
14
+ const token = deposit(val);
15
+ if (val.family) {
16
+ let familyNode = base.get(val.family.key);
17
+ if (!familyNode || !(`familyMembers` in familyNode)) {
18
+ familyNode = {
19
+ key: val.family.key,
20
+ familyMembers: /* @__PURE__ */ new Map()
21
+ };
22
+ base.set(val.family.key, familyNode);
23
+ }
24
+ familyNode.familyMembers.set(val.family.subKey, token);
25
+ } else {
26
+ base.set(key, token);
27
+ }
28
+ }
29
+ }
30
+ return base;
16
31
  },
17
32
  effects: [
18
33
  ({ setSelf }) => {
19
- store.on.atomCreation.subscribe(`introspection`, (atomToken) => {
20
- if (atomToken.key.includes(`\u{1F441}\u200D\u{1F5E8}`)) {
21
- return;
22
- }
23
- const set = () => setSelf((state) => {
24
- const { key, family } = atomToken;
25
- if (family) {
26
- const { key: familyKey, subKey } = family;
27
- const current = state[familyKey];
28
- if (current === void 0 || `familyMembers` in current) {
29
- const familyKeyState = current || {
30
- key: familyKey,
31
- familyMembers: {}
32
- };
33
- return __spreadProps(__spreadValues({}, state), {
34
- [familyKey]: __spreadProps(__spreadValues({}, familyKeyState), {
35
- familyMembers: __spreadProps(__spreadValues({}, familyKeyState.familyMembers), {
36
- [subKey]: atomToken
37
- })
38
- })
39
- });
40
- }
34
+ const unsubscribeFromAtomCreation = store.on.atomCreation.subscribe(
35
+ `introspection`,
36
+ (atomToken) => {
37
+ if (atomToken.key.includes(`\u{1F441}\u200D\u{1F5E8}`)) {
38
+ return;
41
39
  }
42
- return __spreadProps(__spreadValues({}, state), {
43
- [key]: atomToken
40
+ setSelf((self) => {
41
+ if (atomToken.family) {
42
+ const { key: familyKey, subKey } = atomToken.family;
43
+ let familyNode = self.get(familyKey);
44
+ if (familyNode === void 0 || !(`familyMembers` in familyNode)) {
45
+ familyNode = {
46
+ key: familyKey,
47
+ familyMembers: /* @__PURE__ */ new Map()
48
+ };
49
+ self.set(familyKey, familyNode);
50
+ }
51
+ familyNode.familyMembers.set(subKey, atomToken);
52
+ } else {
53
+ self.set(atomToken.key, atomToken);
54
+ }
55
+ return self;
44
56
  });
45
- });
46
- if (newest(store).operation.open) {
47
- const unsubscribe = store.on.operationClose.subscribe(
48
- `introspection: waiting to update atom index`,
49
- () => {
50
- unsubscribe();
51
- set();
57
+ }
58
+ );
59
+ const unsubscribeFromAtomDisposal = store.on.atomDisposal.subscribe(
60
+ `introspection`,
61
+ (atomToken) => {
62
+ setSelf((self) => {
63
+ if (atomToken.family) {
64
+ const { key: familyKey, subKey } = atomToken.family;
65
+ const familyNode = self.get(familyKey);
66
+ if (familyNode && `familyMembers` in familyNode) {
67
+ familyNode.familyMembers.delete(subKey);
68
+ if (familyNode.familyMembers.size === 0) {
69
+ self.delete(familyKey);
70
+ }
71
+ }
72
+ } else {
73
+ self.delete(atomToken.key);
52
74
  }
53
- );
54
- } else {
55
- set();
75
+ return self;
76
+ });
56
77
  }
57
- });
78
+ );
79
+ return () => {
80
+ unsubscribeFromAtomCreation();
81
+ unsubscribeFromAtomDisposal();
82
+ };
58
83
  }
59
84
  ]
60
85
  },
@@ -73,60 +98,81 @@ var attachSelectorIndex = (store = IMPLICIT.STORE) => {
73
98
  const readonlySelectorTokenIndexState__INTERNAL = createRegularAtom(
74
99
  {
75
100
  key: `\u{1F441}\u200D\u{1F5E8} Selector Token Index (Internal)`,
76
- default: () => Object.assign(
77
- [...store.readonlySelectors].filter(([key]) => !key.includes(`\u{1F441}\u200D\u{1F5E8}`)).reduce((acc, [key]) => {
78
- acc[key] = { key, type: `readonly_selector` };
79
- return acc;
80
- }, {}),
81
- [...store.selectors].reduce((acc, [key]) => {
82
- acc[key] = { key, type: `selector` };
83
- return acc;
84
- }, {})
85
- ),
101
+ default: () => {
102
+ const base = /* @__PURE__ */ new Map();
103
+ for (const map of [store.readonlySelectors, store.selectors]) {
104
+ for (const [key, val] of map) {
105
+ if (!key.includes(`\u{1F441}\u200D\u{1F5E8}`)) {
106
+ const token = deposit(val);
107
+ if (val.family) {
108
+ let familyNode = base.get(val.family.key);
109
+ if (!familyNode || !(`familyMembers` in familyNode)) {
110
+ familyNode = {
111
+ key: val.family.key,
112
+ familyMembers: /* @__PURE__ */ new Map()
113
+ };
114
+ base.set(val.family.key, familyNode);
115
+ }
116
+ familyNode.familyMembers.set(val.family.subKey, token);
117
+ } else {
118
+ base.set(key, token);
119
+ }
120
+ }
121
+ }
122
+ }
123
+ return base;
124
+ },
86
125
  effects: [
87
126
  ({ setSelf }) => {
88
- store.on.selectorCreation.subscribe(
127
+ const unsubscribeFromSelectorCreation = store.on.selectorCreation.subscribe(
89
128
  `introspection`,
90
129
  (selectorToken) => {
91
130
  if (selectorToken.key.includes(`\u{1F441}\u200D\u{1F5E8}`)) {
92
131
  return;
93
132
  }
94
- const set = () => setSelf((state) => {
95
- const { key, family } = selectorToken;
96
- if (family) {
97
- const { key: familyKey, subKey } = family;
98
- const current = state[familyKey];
99
- if (current === void 0 || `familyMembers` in current) {
100
- const familyKeyState = current || {
133
+ setSelf((self) => {
134
+ if (selectorToken.family) {
135
+ const { key: familyKey, subKey } = selectorToken.family;
136
+ let familyNode = self.get(familyKey);
137
+ if (familyNode === void 0 || !(`familyMembers` in familyNode)) {
138
+ familyNode = {
101
139
  key: familyKey,
102
- familyMembers: {}
140
+ familyMembers: /* @__PURE__ */ new Map()
103
141
  };
104
- return __spreadProps(__spreadValues({}, state), {
105
- [familyKey]: __spreadProps(__spreadValues({}, familyKeyState), {
106
- familyMembers: __spreadProps(__spreadValues({}, familyKeyState.familyMembers), {
107
- [subKey]: selectorToken
108
- })
109
- })
110
- });
142
+ self.set(familyKey, familyNode);
111
143
  }
144
+ familyNode.familyMembers.set(subKey, selectorToken);
145
+ } else {
146
+ self.set(selectorToken.key, selectorToken);
112
147
  }
113
- return __spreadProps(__spreadValues({}, state), {
114
- [key]: selectorToken
115
- });
148
+ return self;
116
149
  });
117
- if (newest(store).operation.open) {
118
- const unsubscribe = store.on.operationClose.subscribe(
119
- `introspection: waiting to update selector index`,
120
- () => {
121
- unsubscribe();
122
- set();
150
+ }
151
+ );
152
+ const unsubscribeFromSelectorDisposal = store.on.selectorDisposal.subscribe(
153
+ `introspection`,
154
+ (selectorToken) => {
155
+ setSelf((self) => {
156
+ if (selectorToken.family) {
157
+ const { key: familyKey, subKey } = selectorToken.family;
158
+ const familyNode = self.get(familyKey);
159
+ if (familyNode && `familyMembers` in familyNode) {
160
+ familyNode.familyMembers.delete(subKey);
161
+ if (familyNode.familyMembers.size === 0) {
162
+ self.delete(familyKey);
163
+ }
123
164
  }
124
- );
125
- } else {
126
- set();
127
- }
165
+ } else {
166
+ self.delete(selectorToken.key);
167
+ }
168
+ return self;
169
+ });
128
170
  }
129
171
  );
172
+ return () => {
173
+ unsubscribeFromSelectorCreation();
174
+ unsubscribeFromSelectorDisposal();
175
+ };
130
176
  }
131
177
  ]
132
178
  },
@@ -291,5 +337,101 @@ var attachIntrospectionStates = (store = Internal.IMPLICIT.STORE) => {
291
337
  findTimelineState: attachTimelineFamily(store)
292
338
  };
293
339
  };
340
+ var _Auditor = class _Auditor {
341
+ /**
342
+ * @param {Store} store - The store to audit.
343
+ */
344
+ constructor(store = Internal.IMPLICIT.STORE) {
345
+ this.store = store;
346
+ this.auditorCreatedAt = performance.now();
347
+ this.statesCreatedAt = /* @__PURE__ */ new Map();
348
+ this.disposed = false;
349
+ this.atomIndex = attachAtomIndex(this.store);
350
+ this.selectorIndex = attachSelectorIndex(this.store);
351
+ this.unsubscribeFromAtomCreation = this.store.on.atomCreation.subscribe(
352
+ `auditor-${this.auditorCreatedAt}`,
353
+ ({ key }) => {
354
+ this.statesCreatedAt.set(key, performance.now() - this.auditorCreatedAt);
355
+ }
356
+ );
357
+ this.unsubscribeFromAtomDisposal = this.store.on.atomDisposal.subscribe(
358
+ `auditor-${this.auditorCreatedAt}`,
359
+ ({ key }) => {
360
+ this.statesCreatedAt.delete(key);
361
+ }
362
+ );
363
+ this.unsubscribeFromSelectorCreation = this.store.on.selectorCreation.subscribe(
364
+ `auditor-${this.auditorCreatedAt}`,
365
+ ({ key }) => {
366
+ this.statesCreatedAt.set(
367
+ key,
368
+ performance.now() - this.auditorCreatedAt
369
+ );
370
+ }
371
+ );
372
+ this.unsubscribeFromSelectorDisposal = this.store.on.selectorDisposal.subscribe(
373
+ `auditor-${this.auditorCreatedAt}`,
374
+ ({ key }) => {
375
+ this.statesCreatedAt.delete(key);
376
+ }
377
+ );
378
+ }
379
+ /**
380
+ * Lists all resources in the store, along with their creation time.
381
+ *
382
+ * @param {ListResourcesParam} [param] - Optional parameters for filtering the list of resources.
383
+ * @returns {readonly [ReadableToken<unknown>, number]}[] - An array of tuples, where each tuple contains a state token belonging to a family in the store and that state's creation time.
384
+ */
385
+ listResources(param = _Auditor.DEFAULT_LIST_RESOURCES_PARAM) {
386
+ if (this.disposed) {
387
+ throw new Error(`This Auditor has been disposed`);
388
+ }
389
+ const atoms = getState(this.atomIndex);
390
+ const selectors = getState(this.selectorIndex);
391
+ const atomFamilyNodes = [...atoms.values()].filter(
392
+ (node) => `familyMembers` in node
393
+ );
394
+ const selectorFamilyNodes = [...selectors.values()].filter(
395
+ (node) => `familyMembers` in node
396
+ );
397
+ const currentTime = performance.now();
398
+ const resources = [];
399
+ if (param.atomFamilies) {
400
+ for (const familyNode of atomFamilyNodes) {
401
+ const tokens = familyNode.familyMembers.values();
402
+ for (const token of tokens) {
403
+ const storedTime = this.statesCreatedAt.get(token.key);
404
+ const creationTime = storedTime != null ? storedTime : this.auditorCreatedAt;
405
+ const age = currentTime - creationTime;
406
+ resources.push([token, age]);
407
+ }
408
+ }
409
+ }
410
+ if (param.selectorFamilies) {
411
+ for (const familyNode of selectorFamilyNodes) {
412
+ const tokens = familyNode.familyMembers.values();
413
+ for (const token of tokens) {
414
+ const storedTime = this.statesCreatedAt.get(token.key);
415
+ const creationTime = storedTime != null ? storedTime : this.auditorCreatedAt;
416
+ const age = currentTime - creationTime;
417
+ resources.push([token, age]);
418
+ }
419
+ }
420
+ }
421
+ return resources;
422
+ }
423
+ [Symbol.dispose]() {
424
+ this.unsubscribeFromAtomCreation();
425
+ this.unsubscribeFromAtomDisposal();
426
+ this.unsubscribeFromSelectorCreation();
427
+ this.unsubscribeFromSelectorDisposal();
428
+ this.disposed = true;
429
+ }
430
+ };
431
+ _Auditor.DEFAULT_LIST_RESOURCES_PARAM = {
432
+ atomFamilies: true,
433
+ selectorFamilies: true
434
+ };
435
+ var Auditor = _Auditor;
294
436
 
295
- export { attachIntrospectionStates };
437
+ export { Auditor, attachIntrospectionStates };
@@ -3,8 +3,8 @@ import type { Store } from "atom.io/internal"
3
3
  import {
4
4
  createRegularAtom,
5
5
  createStandaloneSelector,
6
+ deposit,
6
7
  IMPLICIT,
7
- newest,
8
8
  } from "atom.io/internal"
9
9
 
10
10
  import type { WritableTokenIndex } from "."
@@ -14,65 +14,86 @@ export type AtomTokenIndex = WritableTokenIndex<AtomToken<unknown>>
14
14
  export const attachAtomIndex = (
15
15
  store: Store = IMPLICIT.STORE,
16
16
  ): ReadonlySelectorToken<AtomTokenIndex> => {
17
- console.log(store.config)
18
17
  const atomTokenIndexState__INTERNAL = createRegularAtom<AtomTokenIndex>(
19
18
  {
20
19
  key: `👁‍🗨 Atom Token Index (Internal)`,
21
20
  default: () => {
22
- const defaultAtomIndex = [...store.atoms]
23
- .filter(([key]) => !key.includes(`👁‍🗨`))
24
- .reduce<AtomTokenIndex>((acc, [key, atom]) => {
25
- acc[key] = { key, type: atom.type }
26
- return acc
27
- }, {})
28
- return defaultAtomIndex
21
+ const base: AtomTokenIndex = new Map()
22
+ for (const [key, val] of store.atoms) {
23
+ if (!key.includes(`👁‍🗨`)) {
24
+ const token = deposit(val)
25
+ if (val.family) {
26
+ let familyNode = base.get(val.family.key)
27
+ if (!familyNode || !(`familyMembers` in familyNode)) {
28
+ familyNode = {
29
+ key: val.family.key,
30
+ familyMembers: new Map(),
31
+ }
32
+ base.set(val.family.key, familyNode)
33
+ }
34
+ familyNode.familyMembers.set(val.family.subKey, token)
35
+ } else {
36
+ base.set(key, token)
37
+ }
38
+ }
39
+ }
40
+ return base
29
41
  },
30
42
  effects: [
31
43
  ({ setSelf }) => {
32
- store.on.atomCreation.subscribe(`introspection`, (atomToken) => {
33
- if (atomToken.key.includes(`👁‍🗨`)) {
34
- return
35
- }
36
- const set = () =>
37
- setSelf((state) => {
38
- const { key, family } = atomToken
39
- if (family) {
40
- const { key: familyKey, subKey } = family
41
- const current = state[familyKey]
42
- if (current === undefined || `familyMembers` in current) {
43
- const familyKeyState = current || {
44
+ const unsubscribeFromAtomCreation = store.on.atomCreation.subscribe(
45
+ `introspection`,
46
+ (atomToken) => {
47
+ if (atomToken.key.includes(`👁‍🗨`)) {
48
+ return
49
+ }
50
+
51
+ setSelf((self) => {
52
+ if (atomToken.family) {
53
+ const { key: familyKey, subKey } = atomToken.family
54
+ let familyNode = self.get(familyKey)
55
+ if (
56
+ familyNode === undefined ||
57
+ !(`familyMembers` in familyNode)
58
+ ) {
59
+ familyNode = {
44
60
  key: familyKey,
45
- familyMembers: {},
46
- }
47
- return {
48
- ...state,
49
- [familyKey]: {
50
- ...familyKeyState,
51
- familyMembers: {
52
- ...familyKeyState.familyMembers,
53
- [subKey]: atomToken,
54
- },
55
- },
61
+ familyMembers: new Map(),
56
62
  }
63
+ self.set(familyKey, familyNode)
57
64
  }
65
+ familyNode.familyMembers.set(subKey, atomToken)
66
+ } else {
67
+ self.set(atomToken.key, atomToken)
58
68
  }
59
- return {
60
- ...state,
61
- [key]: atomToken,
69
+ return self
70
+ })
71
+ },
72
+ )
73
+ const unsubscribeFromAtomDisposal = store.on.atomDisposal.subscribe(
74
+ `introspection`,
75
+ (atomToken) => {
76
+ setSelf((self) => {
77
+ if (atomToken.family) {
78
+ const { key: familyKey, subKey } = atomToken.family
79
+ const familyNode = self.get(familyKey)
80
+ if (familyNode && `familyMembers` in familyNode) {
81
+ familyNode.familyMembers.delete(subKey)
82
+ if (familyNode.familyMembers.size === 0) {
83
+ self.delete(familyKey)
84
+ }
85
+ }
86
+ } else {
87
+ self.delete(atomToken.key)
62
88
  }
89
+ return self
63
90
  })
64
- if (newest(store).operation.open) {
65
- const unsubscribe = store.on.operationClose.subscribe(
66
- `introspection: waiting to update atom index`,
67
- () => {
68
- unsubscribe()
69
- set()
70
- },
71
- )
72
- } else {
73
- set()
74
- }
75
- })
91
+ },
92
+ )
93
+ return () => {
94
+ unsubscribeFromAtomCreation()
95
+ unsubscribeFromAtomDisposal()
96
+ }
76
97
  },
77
98
  ],
78
99
  },
@@ -1,17 +1,15 @@
1
- import type { ReadonlySelectorToken, WritableSelectorToken } from "atom.io"
1
+ import type { ReadonlySelectorToken, SelectorToken } from "atom.io"
2
2
  import type { Store } from "atom.io/internal"
3
3
  import {
4
4
  createRegularAtom,
5
5
  createStandaloneSelector,
6
+ deposit,
6
7
  IMPLICIT,
7
- newest,
8
8
  } from "atom.io/internal"
9
9
 
10
10
  import type { WritableTokenIndex } from "."
11
11
 
12
- export type SelectorTokenIndex = WritableTokenIndex<
13
- ReadonlySelectorToken<unknown> | WritableSelectorToken<unknown>
14
- >
12
+ export type SelectorTokenIndex = WritableTokenIndex<SelectorToken<unknown>>
15
13
 
16
14
  export const attachSelectorIndex = (
17
15
  store: Store = IMPLICIT.STORE,
@@ -20,68 +18,87 @@ export const attachSelectorIndex = (
20
18
  createRegularAtom<SelectorTokenIndex>(
21
19
  {
22
20
  key: `👁‍🗨 Selector Token Index (Internal)`,
23
- default: () =>
24
- Object.assign(
25
- [...store.readonlySelectors]
26
- .filter(([key]) => !key.includes(`👁‍🗨`))
27
- .reduce<SelectorTokenIndex>((acc, [key]) => {
28
- acc[key] = { key, type: `readonly_selector` }
29
- return acc
30
- }, {}),
31
- [...store.selectors].reduce<SelectorTokenIndex>((acc, [key]) => {
32
- acc[key] = { key, type: `selector` }
33
- return acc
34
- }, {}),
35
- ),
21
+ default: () => {
22
+ const base: SelectorTokenIndex = new Map()
23
+ for (const map of [store.readonlySelectors, store.selectors]) {
24
+ for (const [key, val] of map) {
25
+ if (!key.includes(`👁‍🗨`)) {
26
+ const token = deposit(val)
27
+ if (val.family) {
28
+ let familyNode = base.get(val.family.key)
29
+ if (!familyNode || !(`familyMembers` in familyNode)) {
30
+ familyNode = {
31
+ key: val.family.key,
32
+ familyMembers: new Map(),
33
+ }
34
+ base.set(val.family.key, familyNode)
35
+ }
36
+ familyNode.familyMembers.set(val.family.subKey, token)
37
+ } else {
38
+ base.set(key, token)
39
+ }
40
+ }
41
+ }
42
+ }
43
+ return base
44
+ },
36
45
  effects: [
37
46
  ({ setSelf }) => {
38
- store.on.selectorCreation.subscribe(
39
- `introspection`,
40
- (selectorToken) => {
41
- if (selectorToken.key.includes(`👁‍🗨`)) {
42
- return
43
- }
44
- const set = () =>
45
- setSelf((state) => {
46
- const { key, family } = selectorToken
47
- if (family) {
48
- const { key: familyKey, subKey } = family
49
- const current = state[familyKey]
50
- if (current === undefined || `familyMembers` in current) {
51
- const familyKeyState = current || {
47
+ const unsubscribeFromSelectorCreation =
48
+ store.on.selectorCreation.subscribe(
49
+ `introspection`,
50
+ (selectorToken) => {
51
+ if (selectorToken.key.includes(`👁‍🗨`)) {
52
+ return
53
+ }
54
+
55
+ setSelf((self) => {
56
+ if (selectorToken.family) {
57
+ const { key: familyKey, subKey } = selectorToken.family
58
+ let familyNode = self.get(familyKey)
59
+ if (
60
+ familyNode === undefined ||
61
+ !(`familyMembers` in familyNode)
62
+ ) {
63
+ familyNode = {
52
64
  key: familyKey,
53
- familyMembers: {},
54
- }
55
- return {
56
- ...state,
57
- [familyKey]: {
58
- ...familyKeyState,
59
- familyMembers: {
60
- ...familyKeyState.familyMembers,
61
- [subKey]: selectorToken,
62
- },
63
- },
65
+ familyMembers: new Map(),
64
66
  }
67
+ self.set(familyKey, familyNode)
65
68
  }
69
+ familyNode.familyMembers.set(subKey, selectorToken)
70
+ } else {
71
+ self.set(selectorToken.key, selectorToken)
66
72
  }
67
- return {
68
- ...state,
69
- [key]: selectorToken,
73
+ return self
74
+ })
75
+ },
76
+ )
77
+ const unsubscribeFromSelectorDisposal =
78
+ store.on.selectorDisposal.subscribe(
79
+ `introspection`,
80
+ (selectorToken) => {
81
+ setSelf((self) => {
82
+ if (selectorToken.family) {
83
+ const { key: familyKey, subKey } = selectorToken.family
84
+ const familyNode = self.get(familyKey)
85
+ if (familyNode && `familyMembers` in familyNode) {
86
+ familyNode.familyMembers.delete(subKey)
87
+ if (familyNode.familyMembers.size === 0) {
88
+ self.delete(familyKey)
89
+ }
90
+ }
91
+ } else {
92
+ self.delete(selectorToken.key)
70
93
  }
94
+ return self
71
95
  })
72
- if (newest(store).operation.open) {
73
- const unsubscribe = store.on.operationClose.subscribe(
74
- `introspection: waiting to update selector index`,
75
- () => {
76
- unsubscribe()
77
- set()
78
- },
79
- )
80
- } else {
81
- set()
82
- }
83
- },
84
- )
96
+ },
97
+ )
98
+ return () => {
99
+ unsubscribeFromSelectorCreation()
100
+ unsubscribeFromSelectorDisposal()
101
+ }
85
102
  },
86
103
  ],
87
104
  },