atom.io 0.21.1 → 0.23.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 (116) hide show
  1. package/data/dist/index.cjs +152 -63
  2. package/data/dist/index.d.ts +6 -0
  3. package/data/dist/index.js +3 -3
  4. package/data/src/join.ts +164 -51
  5. package/data/src/struct-family.ts +2 -2
  6. package/dist/chunk-6MLFYN32.js +18 -0
  7. package/dist/{chunk-HITX3MO4.js → chunk-7DT3PVS3.js} +151 -62
  8. package/dist/{chunk-RT43TVKP.js → chunk-GVHKIJ3G.js} +1 -1
  9. package/dist/chunk-OAYGID5B.js +27 -0
  10. package/dist/index.cjs +4 -18
  11. package/dist/index.d.ts +71 -28
  12. package/dist/index.js +6 -19
  13. package/ephemeral/dist/index.cjs +11 -0
  14. package/ephemeral/dist/index.js +9 -0
  15. package/ephemeral/package.json +16 -0
  16. package/ephemeral/src/index.ts +1 -0
  17. package/eslint-plugin/dist/index.cjs +155 -1
  18. package/eslint-plugin/dist/index.js +155 -1
  19. package/eslint-plugin/src/rules/index.ts +1 -0
  20. package/eslint-plugin/src/rules/lifespan.ts +203 -0
  21. package/eslint-plugin/src/rules/synchronous-selector-dependencies.ts +1 -65
  22. package/eslint-plugin/src/walk.ts +73 -0
  23. package/immortal/dist/index.cjs +260 -0
  24. package/immortal/dist/index.js +212 -0
  25. package/immortal/package.json +16 -0
  26. package/immortal/src/index.ts +3 -0
  27. package/immortal/src/make-molecule.ts +222 -0
  28. package/immortal/src/molecule.ts +167 -0
  29. package/immortal/src/seek-state.ts +73 -0
  30. package/internal/dist/index.cjs +1242 -837
  31. package/internal/dist/index.d.ts +135 -22
  32. package/internal/dist/index.js +1215 -838
  33. package/internal/src/atom/create-regular-atom.ts +0 -2
  34. package/internal/src/atom/create-standalone-atom.ts +6 -2
  35. package/internal/src/atom/dispose-atom.ts +26 -3
  36. package/internal/src/families/create-readonly-selector-family.ts +15 -10
  37. package/internal/src/families/create-regular-atom-family.ts +20 -21
  38. package/internal/src/families/create-writable-selector-family.ts +13 -9
  39. package/{src/dispose.ts → internal/src/families/dispose-from-store.ts} +7 -4
  40. package/internal/src/families/find-in-store.ts +11 -6
  41. package/internal/src/families/index.ts +3 -0
  42. package/internal/src/families/init-family-member.ts +112 -0
  43. package/internal/src/families/seek-in-store.ts +123 -0
  44. package/internal/src/get-state/get-from-store.ts +2 -2
  45. package/internal/src/ingest-updates/index.ts +1 -0
  46. package/internal/src/ingest-updates/ingest-creation-disposal.ts +104 -0
  47. package/internal/src/ingest-updates/ingest-transaction-update.ts +26 -4
  48. package/internal/src/mutable/create-mutable-atom-family.ts +22 -24
  49. package/internal/src/mutable/create-mutable-atom.ts +3 -3
  50. package/internal/src/mutable/get-json-family.ts +2 -2
  51. package/internal/src/mutable/get-json-token.ts +26 -12
  52. package/internal/src/mutable/tracker-family.ts +21 -19
  53. package/internal/src/not-found-error.ts +16 -3
  54. package/internal/src/selector/create-readonly-selector.ts +2 -3
  55. package/internal/src/selector/create-standalone-selector.ts +6 -2
  56. package/internal/src/selector/create-writable-selector.ts +2 -3
  57. package/internal/src/selector/dispose-selector.ts +68 -24
  58. package/internal/src/selector/register-selector.ts +10 -5
  59. package/internal/src/set-state/set-into-store.ts +2 -2
  60. package/internal/src/set-state/stow-update.ts +5 -1
  61. package/internal/src/store/deposit.ts +41 -7
  62. package/internal/src/store/index.ts +0 -1
  63. package/internal/src/store/store.ts +29 -5
  64. package/internal/src/store/withdraw.ts +28 -1
  65. package/internal/src/subscribe/subscribe-to-state.ts +2 -2
  66. package/internal/src/timeline/add-atom-to-timeline.ts +206 -182
  67. package/internal/src/timeline/create-timeline.ts +181 -60
  68. package/internal/src/timeline/time-travel.ts +20 -0
  69. package/internal/src/transaction/apply-transaction.ts +2 -12
  70. package/internal/src/transaction/build-transaction.ts +16 -2
  71. package/introspection/dist/index.cjs +40 -53
  72. package/introspection/dist/index.js +40 -53
  73. package/introspection/src/attach-atom-index.ts +38 -48
  74. package/introspection/src/attach-selector-index.ts +45 -50
  75. package/introspection/src/attach-timeline-family.ts +1 -0
  76. package/json/dist/index.cjs +40 -6
  77. package/json/dist/index.js +44 -9
  78. package/json/src/select-json-family.ts +47 -9
  79. package/package.json +30 -10
  80. package/react/dist/index.cjs +1 -1
  81. package/react/dist/index.js +1 -1
  82. package/react/src/use-json.ts +1 -1
  83. package/react-devtools/dist/index.cjs +69 -57
  84. package/react-devtools/dist/index.js +62 -49
  85. package/react-devtools/src/StateIndex.tsx +2 -1
  86. package/react-devtools/src/TimelineIndex.tsx +17 -14
  87. package/react-devtools/src/TransactionIndex.tsx +7 -7
  88. package/react-devtools/src/Updates.tsx +41 -32
  89. package/realtime-client/dist/index.cjs +3 -3
  90. package/realtime-client/dist/index.js +3 -3
  91. package/realtime-client/src/pull-mutable-atom-family-member.ts +1 -1
  92. package/realtime-client/src/pull-mutable-atom.ts +1 -1
  93. package/realtime-client/src/sync-continuity.ts +1 -2
  94. package/realtime-react/dist/index.cjs +1 -1
  95. package/realtime-react/dist/index.js +1 -1
  96. package/realtime-server/dist/index.cjs +39 -27
  97. package/realtime-server/dist/index.d.ts +1 -1
  98. package/realtime-server/dist/index.js +27 -16
  99. package/realtime-server/src/realtime-continuity-synchronizer.ts +5 -3
  100. package/realtime-server/src/realtime-mutable-family-provider.ts +2 -1
  101. package/realtime-server/src/realtime-mutable-provider.ts +1 -1
  102. package/realtime-server/src/realtime-server-stores/server-sync-store.ts +21 -11
  103. package/realtime-testing/dist/index.cjs +7 -2
  104. package/realtime-testing/dist/index.js +8 -5
  105. package/realtime-testing/src/setup-realtime-test.tsx +5 -2
  106. package/src/atom.ts +19 -7
  107. package/src/dispose-state.ts +10 -0
  108. package/src/index.ts +5 -2
  109. package/src/selector.ts +13 -7
  110. package/src/silo.ts +3 -3
  111. package/src/subscribe.ts +8 -4
  112. package/src/timeline.ts +18 -1
  113. package/src/transaction.ts +59 -4
  114. package/dist/chunk-BF4MVQF6.js +0 -44
  115. package/internal/src/store/withdraw-new-family-member.ts +0 -69
  116. /package/{src → ephemeral/src}/find-state.ts +0 -0
@@ -0,0 +1,212 @@
1
+ import { __spreadProps, __spreadValues } from '../../dist/chunk-F2X4B4VY.js';
2
+ import * as Internal from 'atom.io/internal';
3
+ import { Subject, initFamilyMember, getJsonFamily, disposeFromStore, newest, seekInStore, IMPLICIT } from 'atom.io/internal';
4
+ import { stringifyJson } from 'atom.io/json';
5
+ import { getJoin } from 'atom.io/data';
6
+
7
+ var Molecule = class _Molecule {
8
+ constructor(store, above, token) {
9
+ this.store = store;
10
+ this.token = token;
11
+ this.type = `molecule`;
12
+ this.below = [];
13
+ this.tokens = [];
14
+ this.joins = [];
15
+ this.subject = new Subject();
16
+ this.dispose = this[Symbol.dispose];
17
+ if (above) {
18
+ if (Array.isArray(above)) {
19
+ this.above = above;
20
+ for (const parent of above) {
21
+ parent.below.push(this);
22
+ }
23
+ } else {
24
+ this.above = [above];
25
+ above.below.push(this);
26
+ }
27
+ } else {
28
+ this.above = [];
29
+ }
30
+ }
31
+ get key() {
32
+ return this.token.key;
33
+ }
34
+ bond(token) {
35
+ const state = initFamilyMember(token, this.token.key, this.store);
36
+ if (token.type === `mutable_atom_family`) {
37
+ const jsonFamily = getJsonFamily(token, this.store);
38
+ const jsonState = initFamilyMember(jsonFamily, this.token.key, this.store);
39
+ this.tokens.push(jsonState);
40
+ }
41
+ this.tokens.push(state);
42
+ this.subject.next({ type: `state_creation`, token: state });
43
+ return state;
44
+ }
45
+ spawn(key) {
46
+ const child = new _Molecule(this.store, this, { key, type: `molecule` });
47
+ return child;
48
+ }
49
+ with(molecule) {
50
+ return (key) => {
51
+ const child = new _Molecule(this.store, [this, molecule], {
52
+ key,
53
+ type: `molecule`
54
+ });
55
+ return child;
56
+ };
57
+ }
58
+ detach(child) {
59
+ const childIndex = this.below.indexOf(child);
60
+ if (childIndex !== void 0) {
61
+ this.below.splice(childIndex, 1);
62
+ }
63
+ const parentIndex = child.above.indexOf(this);
64
+ if (parentIndex !== void 0) {
65
+ child.above.splice(parentIndex, 1);
66
+ }
67
+ }
68
+ claim(child) {
69
+ if (child === this) {
70
+ return;
71
+ }
72
+ for (const parent of child.above) {
73
+ parent.detach(child);
74
+ }
75
+ this.below.push(child);
76
+ child.above.push(this);
77
+ }
78
+ clear() {
79
+ var _a;
80
+ while (this.below.length > 0) {
81
+ (_a = this.below.pop()) == null ? void 0 : _a.dispose();
82
+ }
83
+ while (this.tokens.length > 0) {
84
+ const token = this.tokens.pop();
85
+ if (token) {
86
+ disposeFromStore(token, this.store);
87
+ }
88
+ }
89
+ while (this.joins.length > 0) {
90
+ const join = this.joins.pop();
91
+ if (join) {
92
+ join.molecules.delete(stringifyJson(this.token.key));
93
+ }
94
+ }
95
+ }
96
+ join(token) {
97
+ const join = getJoin(token, this.store);
98
+ join.molecules.set(stringifyJson(this.token.key), this);
99
+ this.joins.push(join);
100
+ }
101
+ [Symbol.dispose]() {
102
+ this.clear();
103
+ const target = newest(this.store);
104
+ target.molecules.delete(stringifyJson(this.token.key));
105
+ for (const parent of this.above) {
106
+ parent.detach(this);
107
+ }
108
+ }
109
+ };
110
+
111
+ // immortal/src/make-molecule.ts
112
+ function createMoleculeFamily(options, store) {
113
+ const subject = new Internal.Subject();
114
+ const token = {
115
+ key: options.key,
116
+ type: `molecule_family`
117
+ };
118
+ const family = Object.assign(options.new(store), __spreadProps(__spreadValues({}, token), { subject }));
119
+ store.moleculeFamilies.set(options.key, family);
120
+ return token;
121
+ }
122
+ function moleculeFamily(options) {
123
+ return createMoleculeFamily(options, Internal.IMPLICIT.STORE);
124
+ }
125
+ function makeMoleculeInStore(store, context, family, key, ...params) {
126
+ const target = Internal.newest(store);
127
+ const token = {
128
+ type: `molecule`,
129
+ key,
130
+ family
131
+ };
132
+ const contextArray = Array.isArray(context) ? context : [context];
133
+ const owners = contextArray.map((ctx) => store.molecules.get(stringifyJson(ctx.key))).filter((m) => m !== void 0);
134
+ const Formula = Internal.withdraw(family, store);
135
+ const molecule = new Formula(owners, token, ...params);
136
+ target.molecules.set(stringifyJson(key), molecule);
137
+ const update = {
138
+ type: `molecule_creation`,
139
+ token,
140
+ family,
141
+ context: contextArray,
142
+ params
143
+ };
144
+ const isTransaction = Internal.isChildStore(target) && target.transactionMeta.phase === `building`;
145
+ if (isTransaction) {
146
+ target.transactionMeta.update.updates.push(update);
147
+ } else {
148
+ Formula.subject.next(update);
149
+ }
150
+ return token;
151
+ }
152
+ function makeMolecule(context, family, key, ...params) {
153
+ return makeMoleculeInStore(
154
+ Internal.IMPLICIT.STORE,
155
+ context,
156
+ family,
157
+ key,
158
+ ...params
159
+ );
160
+ }
161
+ function useMoleculeFromStore(token, store) {
162
+ const molecule = store.molecules.get(stringifyJson(token.key));
163
+ return molecule;
164
+ }
165
+ function useMolecule(token) {
166
+ return useMoleculeFromStore(token, Internal.IMPLICIT.STORE);
167
+ }
168
+ function disposeMolecule(token, store) {
169
+ const mole = useMoleculeFromStore(token, store);
170
+ if (!mole || !token.family) {
171
+ return;
172
+ }
173
+ const { family } = token;
174
+ const Formula = Internal.withdraw(family, store);
175
+ const disposalEvent = {
176
+ type: `molecule_disposal`,
177
+ token,
178
+ family,
179
+ context: mole.above,
180
+ familyKeys: mole.tokens.map((t) => {
181
+ var _a;
182
+ return (_a = t.family) == null ? void 0 : _a.key;
183
+ }).filter((k) => typeof k === `string`)
184
+ };
185
+ if (token.family) {
186
+ disposalEvent.family = token.family;
187
+ }
188
+ const isTransaction = Internal.isChildStore(store) && store.transactionMeta.phase === `building`;
189
+ if (isTransaction) {
190
+ store.transactionMeta.update.updates.push(disposalEvent);
191
+ } else {
192
+ Formula.subject.next(disposalEvent);
193
+ }
194
+ mole.dispose();
195
+ }
196
+ function makeRootMolecule(key, store = Internal.IMPLICIT.STORE) {
197
+ const molecule = new Molecule(store, void 0, { key, type: `molecule` });
198
+ store.molecules.set(stringifyJson(key), molecule);
199
+ return {
200
+ key,
201
+ type: `molecule`
202
+ };
203
+ }
204
+ function seekState(token, key) {
205
+ if (token.type === `molecule_family`) {
206
+ return seekInStore(token, key, IMPLICIT.STORE);
207
+ }
208
+ const state = seekInStore(token, key, IMPLICIT.STORE);
209
+ return state;
210
+ }
211
+
212
+ export { Molecule, createMoleculeFamily, disposeMolecule, makeMolecule, makeMoleculeInStore, makeRootMolecule, moleculeFamily, seekState, useMolecule, useMoleculeFromStore };
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "atom.io-immortal",
3
+ "type": "module",
4
+ "private": true,
5
+ "main": "dist/index.cjs",
6
+ "module": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "browser": "./dist/index.js",
12
+ "require": "./dist/index.cjs",
13
+ "types": "./dist/index.d.ts"
14
+ }
15
+ }
16
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./make-molecule"
2
+ export * from "./molecule"
3
+ export * from "./seek-state"
@@ -0,0 +1,222 @@
1
+ import type { Flat, MoleculeCreation, MoleculeDisposal } from "atom.io"
2
+ import * as Internal from "atom.io/internal"
3
+ import { type Json, stringifyJson } from "atom.io/json"
4
+
5
+ import { Molecule } from "./molecule"
6
+
7
+ export type MoleculeConstructor<
8
+ Key extends Json.Serializable,
9
+ Struct extends { [key: string]: any },
10
+ Params extends any[],
11
+ > = new (
12
+ context: Molecule<any>[],
13
+ token: MoleculeToken<Key, Struct, Params>,
14
+ ...params: Params
15
+ ) => Molecule<Key> & Struct
16
+
17
+ export type MoleculeFamilyToken<
18
+ Key extends Json.Serializable,
19
+ Struct extends { [key: string]: any },
20
+ Params extends any[],
21
+ > = {
22
+ key: string
23
+ type: `molecule_family`
24
+ __K?: Key
25
+ __S?: Struct
26
+ __P?: Params
27
+ }
28
+ export type MoleculeFamily<
29
+ Key extends Json.Serializable,
30
+ Struct extends { [key: string]: any },
31
+ Params extends any[],
32
+ > = Flat<
33
+ MoleculeFamilyToken<Key, Struct, Params> & {
34
+ subject: Internal.Subject<MoleculeCreation<Key> | MoleculeDisposal<Key>>
35
+ }
36
+ > &
37
+ MoleculeConstructor<Key, Struct, Params>
38
+
39
+ export type MoleculeToken<
40
+ Key extends Json.Serializable,
41
+ Struct extends { [key: string]: any },
42
+ Params extends any[],
43
+ > = {
44
+ key: Key
45
+ type: `molecule`
46
+ family?: MoleculeFamilyToken<Key, Struct, Params>
47
+ __S?: Struct
48
+ __P?: Params
49
+ }
50
+
51
+ export type MoleculeFamilyOptions<
52
+ Key extends Json.Serializable,
53
+ Struct extends { [key: string]: any },
54
+ Params extends any[],
55
+ > = {
56
+ key: string
57
+ new: (store: Internal.Store) => MoleculeConstructor<Key, Struct, Params>
58
+ }
59
+
60
+ export function createMoleculeFamily<
61
+ Key extends Json.Serializable,
62
+ Struct extends { [key: string]: any },
63
+ Params extends any[],
64
+ >(
65
+ options: MoleculeFamilyOptions<Key, Struct, Params>,
66
+ store: Internal.Store,
67
+ ): MoleculeFamilyToken<Key, Struct, Params> {
68
+ const subject = new Internal.Subject<
69
+ MoleculeCreation<Key> | MoleculeDisposal<Key>
70
+ >()
71
+ const token = {
72
+ key: options.key,
73
+ type: `molecule_family`,
74
+ } as const satisfies MoleculeFamilyToken<Key, Struct, Params>
75
+ const family = Object.assign(options.new(store), { ...token, subject })
76
+ store.moleculeFamilies.set(options.key, family)
77
+ return token
78
+ }
79
+
80
+ export function moleculeFamily<
81
+ Key extends Json.Serializable,
82
+ Struct extends { [key: string]: any },
83
+ Params extends any[],
84
+ >(
85
+ options: MoleculeFamilyOptions<Key, Struct, Params>,
86
+ ): MoleculeFamilyToken<Key, Struct, Params> {
87
+ return createMoleculeFamily(options, Internal.IMPLICIT.STORE)
88
+ }
89
+
90
+ export function makeMoleculeInStore<
91
+ Key extends Json.Serializable,
92
+ Struct extends { [key: string]: any },
93
+ Params extends any[],
94
+ >(
95
+ store: Internal.Store,
96
+ context: MoleculeToken<any, any, any> | MoleculeToken<any, any, any>[],
97
+ family: MoleculeFamilyToken<Key, Struct, Params>,
98
+ key: Key,
99
+ ...params: Params
100
+ ): MoleculeToken<Key, Struct, Params> {
101
+ const target = Internal.newest(store)
102
+
103
+ const token = {
104
+ type: `molecule`,
105
+ key,
106
+ family,
107
+ } as const satisfies MoleculeToken<Key, Struct, Params>
108
+
109
+ const contextArray = Array.isArray(context) ? context : [context]
110
+ const owners = contextArray
111
+ .map((ctx) => store.molecules.get(stringifyJson(ctx.key)))
112
+ .filter((m): m is Molecule<Key> => m !== undefined)
113
+ const Formula = Internal.withdraw(family, store)
114
+ const molecule = new Formula(owners, token, ...params)
115
+ target.molecules.set(stringifyJson(key), molecule)
116
+
117
+ const update = {
118
+ type: `molecule_creation`,
119
+ token,
120
+ family,
121
+ context: contextArray,
122
+ params,
123
+ } satisfies MoleculeCreation<Key>
124
+
125
+ const isTransaction =
126
+ Internal.isChildStore(target) && target.transactionMeta.phase === `building`
127
+ if (isTransaction) {
128
+ target.transactionMeta.update.updates.push(update)
129
+ } else {
130
+ Formula.subject.next(update)
131
+ }
132
+
133
+ return token
134
+ }
135
+ export function makeMolecule<
136
+ Key extends Json.Serializable,
137
+ Struct extends { [key: string]: any },
138
+ Params extends any[],
139
+ >(
140
+ context: MoleculeToken<any, any, any> | MoleculeToken<any, any, any>[],
141
+ family: MoleculeFamilyToken<Key, Struct, Params>,
142
+ key: Key,
143
+ ...params: Params
144
+ ): MoleculeToken<Key, Struct, Params> {
145
+ return makeMoleculeInStore(
146
+ Internal.IMPLICIT.STORE,
147
+ context,
148
+ family,
149
+ key,
150
+ ...params,
151
+ )
152
+ }
153
+
154
+ export function useMoleculeFromStore<
155
+ Key extends Json.Serializable,
156
+ Struct extends { [key: string]: any },
157
+ Params extends any[],
158
+ >(
159
+ token: MoleculeToken<Key, Struct, Params>,
160
+ store: Internal.Store,
161
+ ): (Molecule<Key> & Struct) | undefined {
162
+ const molecule = store.molecules.get(stringifyJson(token.key))
163
+ return molecule as Molecule<Key> & Struct
164
+ }
165
+ export function useMolecule<
166
+ Key extends Json.Serializable,
167
+ Struct extends { [key: string]: any },
168
+ Params extends any[],
169
+ >(
170
+ token: MoleculeToken<Key, Struct, Params>,
171
+ ): (Molecule<Key> & Struct) | undefined {
172
+ return useMoleculeFromStore(token, Internal.IMPLICIT.STORE)
173
+ }
174
+
175
+ export function disposeMolecule<
176
+ Key extends Json.Serializable,
177
+ Struct extends { [key: string]: any },
178
+ Params extends any[],
179
+ >(token: MoleculeToken<Key, Struct, Params>, store: Internal.Store): void {
180
+ const mole = useMoleculeFromStore(token, store)
181
+ if (!mole || !token.family) {
182
+ return // add error log
183
+ }
184
+ const { family } = token
185
+ const Formula = Internal.withdraw(family, store)
186
+ const disposalEvent: MoleculeDisposal<Key> = {
187
+ type: `molecule_disposal`,
188
+ token,
189
+ family,
190
+ context: mole.above,
191
+ familyKeys: mole.tokens
192
+ .map((t) => t.family?.key)
193
+ .filter((k): k is string => typeof k === `string`),
194
+ }
195
+ if (token.family) {
196
+ disposalEvent.family = token.family
197
+ }
198
+ const isTransaction =
199
+ Internal.isChildStore(store) && store.transactionMeta.phase === `building`
200
+ if (isTransaction) {
201
+ store.transactionMeta.update.updates.push(disposalEvent)
202
+ } else {
203
+ Formula.subject.next(disposalEvent)
204
+ }
205
+
206
+ mole.dispose()
207
+ }
208
+
209
+ export type MoleculeType<M extends MoleculeFamilyToken<any, any, any>> =
210
+ M extends MoleculeFamilyToken<any, infer T, any> ? T : never
211
+
212
+ export function makeRootMolecule(
213
+ key: Json.Serializable,
214
+ store: Internal.Store = Internal.IMPLICIT.STORE,
215
+ ): MoleculeToken<Json.Serializable, { [key: string]: unknown }, []> {
216
+ const molecule = new Molecule(store, undefined, { key, type: `molecule` })
217
+ store.molecules.set(stringifyJson(key), molecule)
218
+ return {
219
+ key,
220
+ type: `molecule`,
221
+ } as const
222
+ }
@@ -0,0 +1,167 @@
1
+ import type {
2
+ MutableAtomFamilyToken,
3
+ MutableAtomToken,
4
+ ReadableFamilyToken,
5
+ ReadableToken,
6
+ ReadonlySelectorFamilyToken,
7
+ ReadonlySelectorToken,
8
+ RegularAtomFamilyToken,
9
+ RegularAtomToken,
10
+ StateCreation,
11
+ StateDisposal,
12
+ WritableFamilyToken,
13
+ WritableSelectorFamilyToken,
14
+ WritableSelectorToken,
15
+ WritableToken,
16
+ } from "atom.io"
17
+ import type { Join, JoinToken } from "atom.io/data"
18
+ import { getJoin } from "atom.io/data"
19
+ import type { Store, Transceiver } from "atom.io/internal"
20
+ import {
21
+ disposeFromStore,
22
+ getJsonFamily,
23
+ initFamilyMember,
24
+ newest,
25
+ Subject,
26
+ } from "atom.io/internal"
27
+ import { type Json, stringifyJson } from "atom.io/json"
28
+
29
+ import type { MoleculeFamilyToken, MoleculeToken } from "./make-molecule"
30
+
31
+ export class Molecule<Key extends Json.Serializable> {
32
+ public readonly type = `molecule`
33
+ public get key(): Key {
34
+ return this.token.key
35
+ }
36
+ public readonly family?: MoleculeFamilyToken<Key, any, any>
37
+ public readonly above: Molecule<any>[]
38
+ public readonly below: Molecule<any>[] = []
39
+ public readonly tokens: ReadableToken<any>[] = []
40
+ public readonly joins: Join<any, any, any, any>[] = []
41
+ public readonly subject = new Subject<
42
+ StateCreation<any> | StateDisposal<any>
43
+ >()
44
+ public constructor(
45
+ public readonly store: Store,
46
+ above: Molecule<any> | Molecule<any>[] | undefined,
47
+ public readonly token: MoleculeToken<Key, any, any>,
48
+ ) {
49
+ // store.molecules.set(stringifyJson(key), this) // consider removing this
50
+ if (above) {
51
+ if (Array.isArray(above)) {
52
+ this.above = above
53
+ for (const parent of above) {
54
+ parent.below.push(this)
55
+ }
56
+ } else {
57
+ this.above = [above]
58
+ above.below.push(this)
59
+ }
60
+ } else {
61
+ this.above = []
62
+ }
63
+ }
64
+
65
+ public bond<
66
+ T extends Transceiver<any>,
67
+ J extends Json.Serializable,
68
+ K extends string,
69
+ >(token: MutableAtomFamilyToken<T, J, K>): MutableAtomToken<T, J>
70
+ public bond<T, K extends Key>(
71
+ token: RegularAtomFamilyToken<T, K>,
72
+ ): RegularAtomToken<T>
73
+ public bond<T, K extends Json.Serializable>(
74
+ token: WritableSelectorFamilyToken<T, K>,
75
+ ): WritableSelectorToken<T>
76
+ public bond<T, K extends Json.Serializable>(
77
+ token: ReadonlySelectorFamilyToken<T, K>,
78
+ ): ReadonlySelectorToken<T>
79
+ public bond<T, K extends Json.Serializable>(
80
+ token: WritableFamilyToken<T, K>,
81
+ ): WritableToken<T>
82
+ public bond<T, K extends Json.Serializable>(
83
+ token: ReadableFamilyToken<T, K>,
84
+ ): ReadableToken<T>
85
+ public bond(token: ReadableFamilyToken<any, any>): ReadableToken<any> {
86
+ const state = initFamilyMember(token, this.token.key, this.store)
87
+ if (token.type === `mutable_atom_family`) {
88
+ const jsonFamily = getJsonFamily(token, this.store)
89
+ const jsonState = initFamilyMember(jsonFamily, this.token.key, this.store)
90
+ this.tokens.push(jsonState)
91
+ }
92
+ this.tokens.push(state)
93
+ this.subject.next({ type: `state_creation`, token: state })
94
+ return state
95
+ }
96
+
97
+ public spawn<K extends Json.Serializable>(key: K): Molecule<K> {
98
+ const child = new Molecule(this.store, this, { key, type: `molecule` })
99
+ return child
100
+ }
101
+
102
+ public with(molecule: Molecule<any>): (key: string) => Molecule<any> {
103
+ return (key) => {
104
+ const child = new Molecule(this.store, [this, molecule], {
105
+ key,
106
+ type: `molecule`,
107
+ })
108
+ return child
109
+ }
110
+ }
111
+
112
+ public detach(child: Molecule<any>): void {
113
+ const childIndex = this.below.indexOf(child)
114
+ if (childIndex !== undefined) {
115
+ this.below.splice(childIndex, 1)
116
+ }
117
+ const parentIndex = child.above.indexOf(this)
118
+ if (parentIndex !== undefined) {
119
+ child.above.splice(parentIndex, 1)
120
+ }
121
+ }
122
+
123
+ public claim(child: Molecule<any>): void {
124
+ if (child === this) {
125
+ return
126
+ }
127
+ for (const parent of child.above) {
128
+ parent.detach(child)
129
+ }
130
+ this.below.push(child)
131
+ child.above.push(this)
132
+ }
133
+
134
+ public clear(): void {
135
+ while (this.below.length > 0) {
136
+ this.below.pop()?.dispose()
137
+ }
138
+ while (this.tokens.length > 0) {
139
+ const token = this.tokens.pop()
140
+ if (token) {
141
+ disposeFromStore(token, this.store)
142
+ }
143
+ }
144
+ while (this.joins.length > 0) {
145
+ const join = this.joins.pop()
146
+ if (join) {
147
+ join.molecules.delete(stringifyJson(this.token.key))
148
+ }
149
+ }
150
+ }
151
+
152
+ public join(token: JoinToken<any, any, any, any>): void {
153
+ const join = getJoin(token, this.store)
154
+ join.molecules.set(stringifyJson(this.token.key), this)
155
+ this.joins.push(join)
156
+ }
157
+
158
+ private [Symbol.dispose](): void {
159
+ this.clear()
160
+ const target = newest(this.store)
161
+ target.molecules.delete(stringifyJson(this.token.key))
162
+ for (const parent of this.above) {
163
+ parent.detach(this)
164
+ }
165
+ }
166
+ public dispose = this[Symbol.dispose]
167
+ }
@@ -0,0 +1,73 @@
1
+ import type {
2
+ MutableAtomFamilyToken,
3
+ MutableAtomToken,
4
+ ReadableFamilyToken,
5
+ ReadableToken,
6
+ ReadonlySelectorFamilyToken,
7
+ ReadonlySelectorToken,
8
+ RegularAtomFamilyToken,
9
+ RegularAtomToken,
10
+ WritableFamilyToken,
11
+ WritableSelectorFamilyToken,
12
+ WritableSelectorToken,
13
+ WritableToken,
14
+ } from "atom.io"
15
+ import type { Transceiver } from "atom.io/internal"
16
+ import { IMPLICIT, seekInStore } from "atom.io/internal"
17
+ import type { Json } from "atom.io/json"
18
+
19
+ import type { MoleculeFamilyToken, MoleculeToken } from "./make-molecule"
20
+
21
+ export function seekState<
22
+ T extends Transceiver<any>,
23
+ J extends Json.Serializable,
24
+ K extends Json.Serializable,
25
+ Key extends K,
26
+ >(
27
+ token: MutableAtomFamilyToken<T, J, K>,
28
+ key: Key,
29
+ ): MutableAtomToken<T, J> | undefined
30
+
31
+ export function seekState<T, K extends Json.Serializable, Key extends K>(
32
+ token: RegularAtomFamilyToken<T, K>,
33
+ key: Key,
34
+ ): RegularAtomToken<T> | undefined
35
+
36
+ export function seekState<T, K extends Json.Serializable, Key extends K>(
37
+ token: WritableSelectorFamilyToken<T, K>,
38
+ key: Key,
39
+ ): WritableSelectorToken<T> | undefined
40
+
41
+ export function seekState<T, K extends Json.Serializable, Key extends K>(
42
+ token: ReadonlySelectorFamilyToken<T, K>,
43
+ key: Key,
44
+ ): ReadonlySelectorToken<T> | undefined
45
+
46
+ export function seekState<T, K extends Json.Serializable, Key extends K>(
47
+ token: WritableFamilyToken<T, K>,
48
+ key: Key,
49
+ ): WritableToken<T> | undefined
50
+
51
+ export function seekState<T, K extends Json.Serializable, Key extends K>(
52
+ token: ReadableFamilyToken<T, K>,
53
+ key: Key,
54
+ ): ReadableToken<T> | undefined
55
+
56
+ export function seekState<
57
+ K extends Json.Serializable,
58
+ S extends { [key: string]: any },
59
+ >(
60
+ token: MoleculeFamilyToken<K, S, any[]>,
61
+ key: K,
62
+ ): MoleculeToken<K, S, any[]> | undefined
63
+
64
+ export function seekState(
65
+ token: MoleculeFamilyToken<any, any, any> | ReadableFamilyToken<any, any>,
66
+ key: Json.Serializable,
67
+ ): MoleculeToken<any, any, any> | ReadableToken<any> | undefined {
68
+ if (token.type === `molecule_family`) {
69
+ return seekInStore(token, key, IMPLICIT.STORE)
70
+ }
71
+ const state = seekInStore(token, key, IMPLICIT.STORE)
72
+ return state
73
+ }