atom.io 0.22.0 → 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 (79) hide show
  1. package/data/dist/index.cjs +17 -1
  2. package/data/dist/index.js +1 -1
  3. package/data/src/join.ts +30 -1
  4. package/dist/chunk-6MLFYN32.js +18 -0
  5. package/dist/{chunk-JA4V7TJY.js → chunk-7DT3PVS3.js} +18 -2
  6. package/dist/chunk-OAYGID5B.js +27 -0
  7. package/dist/index.cjs +2 -11
  8. package/dist/index.d.ts +51 -23
  9. package/dist/index.js +2 -11
  10. package/eslint-plugin/dist/index.cjs +0 -1
  11. package/eslint-plugin/dist/index.js +0 -1
  12. package/eslint-plugin/src/rules/lifespan.ts +0 -1
  13. package/immortal/dist/index.cjs +180 -20
  14. package/immortal/dist/index.js +134 -19
  15. package/immortal/src/index.ts +1 -0
  16. package/immortal/src/make-molecule.ts +222 -0
  17. package/immortal/src/molecule.ts +49 -16
  18. package/immortal/src/seek-state.ts +15 -2
  19. package/internal/dist/index.cjs +1119 -754
  20. package/internal/dist/index.d.ts +109 -12
  21. package/internal/dist/index.js +1098 -760
  22. package/internal/src/atom/create-regular-atom.ts +0 -2
  23. package/internal/src/atom/create-standalone-atom.ts +6 -2
  24. package/internal/src/atom/dispose-atom.ts +22 -2
  25. package/internal/src/families/create-readonly-selector-family.ts +7 -2
  26. package/internal/src/families/create-regular-atom-family.ts +6 -2
  27. package/internal/src/families/create-writable-selector-family.ts +7 -2
  28. package/internal/src/families/dispose-from-store.ts +22 -0
  29. package/internal/src/families/find-in-store.ts +0 -1
  30. package/internal/src/families/index.ts +1 -0
  31. package/internal/src/families/init-family-member.ts +22 -1
  32. package/internal/src/families/seek-in-store.ts +23 -6
  33. package/internal/src/ingest-updates/index.ts +1 -0
  34. package/internal/src/ingest-updates/ingest-creation-disposal.ts +104 -0
  35. package/internal/src/ingest-updates/ingest-transaction-update.ts +26 -4
  36. package/internal/src/mutable/create-mutable-atom-family.ts +6 -2
  37. package/internal/src/mutable/create-mutable-atom.ts +0 -2
  38. package/internal/src/mutable/get-json-token.ts +0 -1
  39. package/internal/src/mutable/tracker-family.ts +7 -7
  40. package/internal/src/not-found-error.ts +5 -0
  41. package/internal/src/selector/create-readonly-selector.ts +2 -3
  42. package/internal/src/selector/create-standalone-selector.ts +6 -2
  43. package/internal/src/selector/create-writable-selector.ts +2 -3
  44. package/internal/src/selector/dispose-selector.ts +32 -5
  45. package/internal/src/selector/register-selector.ts +2 -0
  46. package/internal/src/set-state/stow-update.ts +5 -1
  47. package/internal/src/store/deposit.ts +41 -7
  48. package/internal/src/store/store.ts +11 -0
  49. package/internal/src/store/withdraw.ts +28 -1
  50. package/internal/src/timeline/add-atom-to-timeline.ts +206 -182
  51. package/internal/src/timeline/create-timeline.ts +181 -60
  52. package/internal/src/timeline/time-travel.ts +20 -0
  53. package/internal/src/transaction/apply-transaction.ts +2 -12
  54. package/internal/src/transaction/build-transaction.ts +11 -2
  55. package/introspection/dist/index.cjs +2 -1
  56. package/introspection/dist/index.js +2 -1
  57. package/introspection/src/attach-timeline-family.ts +1 -0
  58. package/json/dist/index.cjs +3 -3
  59. package/json/dist/index.js +6 -5
  60. package/json/src/select-json-family.ts +3 -4
  61. package/package.json +5 -5
  62. package/react-devtools/dist/index.cjs +58 -47
  63. package/react-devtools/dist/index.js +60 -48
  64. package/react-devtools/src/TimelineIndex.tsx +15 -13
  65. package/react-devtools/src/Updates.tsx +41 -32
  66. package/realtime-server/dist/index.cjs +21 -10
  67. package/realtime-server/dist/index.d.ts +1 -1
  68. package/realtime-server/dist/index.js +21 -11
  69. package/realtime-server/src/realtime-server-stores/server-sync-store.ts +21 -11
  70. package/realtime-testing/dist/index.cjs +1 -0
  71. package/realtime-testing/dist/index.js +1 -1
  72. package/src/atom.ts +9 -3
  73. package/src/dispose-state.ts +3 -12
  74. package/src/index.ts +4 -0
  75. package/src/selector.ts +3 -3
  76. package/src/subscribe.ts +8 -4
  77. package/src/timeline.ts +18 -1
  78. package/src/transaction.ts +56 -4
  79. package/dist/chunk-BF4MVQF6.js +0 -44
@@ -1,42 +1,96 @@
1
1
  'use strict';
2
2
 
3
- var atom_io = require('atom.io');
4
- var data = require('atom.io/data');
5
- var internal = require('atom.io/internal');
3
+ var Internal = require('atom.io/internal');
6
4
  var json = require('atom.io/json');
5
+ var data = require('atom.io/data');
6
+
7
+ function _interopNamespace(e) {
8
+ if (e && e.__esModule) return e;
9
+ var n = Object.create(null);
10
+ if (e) {
11
+ Object.keys(e).forEach(function (k) {
12
+ if (k !== 'default') {
13
+ var d = Object.getOwnPropertyDescriptor(e, k);
14
+ Object.defineProperty(n, k, d.get ? d : {
15
+ enumerable: true,
16
+ get: function () { return e[k]; }
17
+ });
18
+ }
19
+ });
20
+ }
21
+ n.default = e;
22
+ return Object.freeze(n);
23
+ }
24
+
25
+ var Internal__namespace = /*#__PURE__*/_interopNamespace(Internal);
7
26
 
8
- // immortal/src/molecule.ts
27
+ var __defProp = Object.defineProperty;
28
+ var __defProps = Object.defineProperties;
29
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
30
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
31
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
32
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
33
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
34
+ var __spreadValues = (a, b) => {
35
+ for (var prop in b || (b = {}))
36
+ if (__hasOwnProp.call(b, prop))
37
+ __defNormalProp(a, prop, b[prop]);
38
+ if (__getOwnPropSymbols)
39
+ for (var prop of __getOwnPropSymbols(b)) {
40
+ if (__propIsEnum.call(b, prop))
41
+ __defNormalProp(a, prop, b[prop]);
42
+ }
43
+ return a;
44
+ };
45
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
9
46
  var Molecule = class _Molecule {
10
- constructor(key, above = [], store = internal.IMPLICIT.STORE) {
11
- this.key = key;
12
- this.above = above;
47
+ constructor(store, above, token) {
13
48
  this.store = store;
49
+ this.token = token;
50
+ this.type = `molecule`;
14
51
  this.below = [];
15
52
  this.tokens = [];
16
53
  this.joins = [];
54
+ this.subject = new Internal.Subject();
17
55
  this.dispose = this[Symbol.dispose];
18
- store.molecules.set(json.stringifyJson(key), this);
19
- for (const parent of above) {
20
- parent.below.push(this);
56
+ if (above) {
57
+ if (Array.isArray(above)) {
58
+ this.above = above;
59
+ for (const parent of above) {
60
+ parent.below.push(this);
61
+ }
62
+ } else {
63
+ this.above = [above];
64
+ above.below.push(this);
65
+ }
66
+ } else {
67
+ this.above = [];
21
68
  }
22
69
  }
70
+ get key() {
71
+ return this.token.key;
72
+ }
23
73
  bond(token) {
24
- const state = internal.initFamilyMember(token, this.key, this.store);
74
+ const state = Internal.initFamilyMember(token, this.token.key, this.store);
25
75
  if (token.type === `mutable_atom_family`) {
26
- const jsonFamily = internal.getJsonFamily(token, this.store);
27
- const jsonState = internal.initFamilyMember(jsonFamily, this.key, this.store);
76
+ const jsonFamily = Internal.getJsonFamily(token, this.store);
77
+ const jsonState = Internal.initFamilyMember(jsonFamily, this.token.key, this.store);
28
78
  this.tokens.push(jsonState);
29
79
  }
30
80
  this.tokens.push(state);
81
+ this.subject.next({ type: `state_creation`, token: state });
31
82
  return state;
32
83
  }
33
84
  spawn(key) {
34
- const child = new _Molecule(key, [this], this.store);
85
+ const child = new _Molecule(this.store, this, { key, type: `molecule` });
35
86
  return child;
36
87
  }
37
88
  with(molecule) {
38
89
  return (key) => {
39
- const child = new _Molecule(key, [this, molecule], this.store);
90
+ const child = new _Molecule(this.store, [this, molecule], {
91
+ key,
92
+ type: `molecule`
93
+ });
40
94
  return child;
41
95
  };
42
96
  }
@@ -68,33 +122,139 @@ var Molecule = class _Molecule {
68
122
  while (this.tokens.length > 0) {
69
123
  const token = this.tokens.pop();
70
124
  if (token) {
71
- atom_io.disposeState(token, this.store);
125
+ Internal.disposeFromStore(token, this.store);
72
126
  }
73
127
  }
74
128
  while (this.joins.length > 0) {
75
129
  const join = this.joins.pop();
76
130
  if (join) {
77
- join.molecules.delete(json.stringifyJson(this.key));
131
+ join.molecules.delete(json.stringifyJson(this.token.key));
78
132
  }
79
133
  }
80
134
  }
81
135
  join(token) {
82
136
  const join = data.getJoin(token, this.store);
83
- join.molecules.set(json.stringifyJson(this.key), this);
137
+ join.molecules.set(json.stringifyJson(this.token.key), this);
84
138
  this.joins.push(join);
85
139
  }
86
140
  [Symbol.dispose]() {
87
141
  this.clear();
88
- this.store.molecules.delete(json.stringifyJson(this.key));
142
+ const target = Internal.newest(this.store);
143
+ target.molecules.delete(json.stringifyJson(this.token.key));
89
144
  for (const parent of this.above) {
90
145
  parent.detach(this);
91
146
  }
92
147
  }
93
148
  };
149
+
150
+ // immortal/src/make-molecule.ts
151
+ function createMoleculeFamily(options, store) {
152
+ const subject = new Internal__namespace.Subject();
153
+ const token = {
154
+ key: options.key,
155
+ type: `molecule_family`
156
+ };
157
+ const family = Object.assign(options.new(store), __spreadProps(__spreadValues({}, token), { subject }));
158
+ store.moleculeFamilies.set(options.key, family);
159
+ return token;
160
+ }
161
+ function moleculeFamily(options) {
162
+ return createMoleculeFamily(options, Internal__namespace.IMPLICIT.STORE);
163
+ }
164
+ function makeMoleculeInStore(store, context, family, key, ...params) {
165
+ const target = Internal__namespace.newest(store);
166
+ const token = {
167
+ type: `molecule`,
168
+ key,
169
+ family
170
+ };
171
+ const contextArray = Array.isArray(context) ? context : [context];
172
+ const owners = contextArray.map((ctx) => store.molecules.get(json.stringifyJson(ctx.key))).filter((m) => m !== void 0);
173
+ const Formula = Internal__namespace.withdraw(family, store);
174
+ const molecule = new Formula(owners, token, ...params);
175
+ target.molecules.set(json.stringifyJson(key), molecule);
176
+ const update = {
177
+ type: `molecule_creation`,
178
+ token,
179
+ family,
180
+ context: contextArray,
181
+ params
182
+ };
183
+ const isTransaction = Internal__namespace.isChildStore(target) && target.transactionMeta.phase === `building`;
184
+ if (isTransaction) {
185
+ target.transactionMeta.update.updates.push(update);
186
+ } else {
187
+ Formula.subject.next(update);
188
+ }
189
+ return token;
190
+ }
191
+ function makeMolecule(context, family, key, ...params) {
192
+ return makeMoleculeInStore(
193
+ Internal__namespace.IMPLICIT.STORE,
194
+ context,
195
+ family,
196
+ key,
197
+ ...params
198
+ );
199
+ }
200
+ function useMoleculeFromStore(token, store) {
201
+ const molecule = store.molecules.get(json.stringifyJson(token.key));
202
+ return molecule;
203
+ }
204
+ function useMolecule(token) {
205
+ return useMoleculeFromStore(token, Internal__namespace.IMPLICIT.STORE);
206
+ }
207
+ function disposeMolecule(token, store) {
208
+ const mole = useMoleculeFromStore(token, store);
209
+ if (!mole || !token.family) {
210
+ return;
211
+ }
212
+ const { family } = token;
213
+ const Formula = Internal__namespace.withdraw(family, store);
214
+ const disposalEvent = {
215
+ type: `molecule_disposal`,
216
+ token,
217
+ family,
218
+ context: mole.above,
219
+ familyKeys: mole.tokens.map((t) => {
220
+ var _a;
221
+ return (_a = t.family) == null ? void 0 : _a.key;
222
+ }).filter((k) => typeof k === `string`)
223
+ };
224
+ if (token.family) {
225
+ disposalEvent.family = token.family;
226
+ }
227
+ const isTransaction = Internal__namespace.isChildStore(store) && store.transactionMeta.phase === `building`;
228
+ if (isTransaction) {
229
+ store.transactionMeta.update.updates.push(disposalEvent);
230
+ } else {
231
+ Formula.subject.next(disposalEvent);
232
+ }
233
+ mole.dispose();
234
+ }
235
+ function makeRootMolecule(key, store = Internal__namespace.IMPLICIT.STORE) {
236
+ const molecule = new Molecule(store, void 0, { key, type: `molecule` });
237
+ store.molecules.set(json.stringifyJson(key), molecule);
238
+ return {
239
+ key,
240
+ type: `molecule`
241
+ };
242
+ }
94
243
  function seekState(token, key) {
95
- const state = internal.seekInStore(token, key, internal.IMPLICIT.STORE);
244
+ if (token.type === `molecule_family`) {
245
+ return Internal.seekInStore(token, key, Internal.IMPLICIT.STORE);
246
+ }
247
+ const state = Internal.seekInStore(token, key, Internal.IMPLICIT.STORE);
96
248
  return state;
97
249
  }
98
250
 
99
251
  exports.Molecule = Molecule;
252
+ exports.createMoleculeFamily = createMoleculeFamily;
253
+ exports.disposeMolecule = disposeMolecule;
254
+ exports.makeMolecule = makeMolecule;
255
+ exports.makeMoleculeInStore = makeMoleculeInStore;
256
+ exports.makeRootMolecule = makeRootMolecule;
257
+ exports.moleculeFamily = moleculeFamily;
100
258
  exports.seekState = seekState;
259
+ exports.useMolecule = useMolecule;
260
+ exports.useMoleculeFromStore = useMoleculeFromStore;
@@ -1,40 +1,57 @@
1
- import '../../dist/chunk-F2X4B4VY.js';
2
- import { disposeState } from 'atom.io';
3
- import { getJoin } from 'atom.io/data';
4
- import { IMPLICIT, initFamilyMember, getJsonFamily, seekInStore } from 'atom.io/internal';
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';
5
4
  import { stringifyJson } from 'atom.io/json';
5
+ import { getJoin } from 'atom.io/data';
6
6
 
7
7
  var Molecule = class _Molecule {
8
- constructor(key, above = [], store = IMPLICIT.STORE) {
9
- this.key = key;
10
- this.above = above;
8
+ constructor(store, above, token) {
11
9
  this.store = store;
10
+ this.token = token;
11
+ this.type = `molecule`;
12
12
  this.below = [];
13
13
  this.tokens = [];
14
14
  this.joins = [];
15
+ this.subject = new Subject();
15
16
  this.dispose = this[Symbol.dispose];
16
- store.molecules.set(stringifyJson(key), this);
17
- for (const parent of above) {
18
- parent.below.push(this);
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 = [];
19
29
  }
20
30
  }
31
+ get key() {
32
+ return this.token.key;
33
+ }
21
34
  bond(token) {
22
- const state = initFamilyMember(token, this.key, this.store);
35
+ const state = initFamilyMember(token, this.token.key, this.store);
23
36
  if (token.type === `mutable_atom_family`) {
24
37
  const jsonFamily = getJsonFamily(token, this.store);
25
- const jsonState = initFamilyMember(jsonFamily, this.key, this.store);
38
+ const jsonState = initFamilyMember(jsonFamily, this.token.key, this.store);
26
39
  this.tokens.push(jsonState);
27
40
  }
28
41
  this.tokens.push(state);
42
+ this.subject.next({ type: `state_creation`, token: state });
29
43
  return state;
30
44
  }
31
45
  spawn(key) {
32
- const child = new _Molecule(key, [this], this.store);
46
+ const child = new _Molecule(this.store, this, { key, type: `molecule` });
33
47
  return child;
34
48
  }
35
49
  with(molecule) {
36
50
  return (key) => {
37
- const child = new _Molecule(key, [this, molecule], this.store);
51
+ const child = new _Molecule(this.store, [this, molecule], {
52
+ key,
53
+ type: `molecule`
54
+ });
38
55
  return child;
39
56
  };
40
57
  }
@@ -66,32 +83,130 @@ var Molecule = class _Molecule {
66
83
  while (this.tokens.length > 0) {
67
84
  const token = this.tokens.pop();
68
85
  if (token) {
69
- disposeState(token, this.store);
86
+ disposeFromStore(token, this.store);
70
87
  }
71
88
  }
72
89
  while (this.joins.length > 0) {
73
90
  const join = this.joins.pop();
74
91
  if (join) {
75
- join.molecules.delete(stringifyJson(this.key));
92
+ join.molecules.delete(stringifyJson(this.token.key));
76
93
  }
77
94
  }
78
95
  }
79
96
  join(token) {
80
97
  const join = getJoin(token, this.store);
81
- join.molecules.set(stringifyJson(this.key), this);
98
+ join.molecules.set(stringifyJson(this.token.key), this);
82
99
  this.joins.push(join);
83
100
  }
84
101
  [Symbol.dispose]() {
85
102
  this.clear();
86
- this.store.molecules.delete(stringifyJson(this.key));
103
+ const target = newest(this.store);
104
+ target.molecules.delete(stringifyJson(this.token.key));
87
105
  for (const parent of this.above) {
88
106
  parent.detach(this);
89
107
  }
90
108
  }
91
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
+ }
92
204
  function seekState(token, key) {
205
+ if (token.type === `molecule_family`) {
206
+ return seekInStore(token, key, IMPLICIT.STORE);
207
+ }
93
208
  const state = seekInStore(token, key, IMPLICIT.STORE);
94
209
  return state;
95
210
  }
96
211
 
97
- export { Molecule, seekState };
212
+ export { Molecule, createMoleculeFamily, disposeMolecule, makeMolecule, makeMoleculeInStore, makeRootMolecule, moleculeFamily, seekState, useMolecule, useMoleculeFromStore };
@@ -1,2 +1,3 @@
1
+ export * from "./make-molecule"
1
2
  export * from "./molecule"
2
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
+ }