@tldraw/store 4.1.0-canary.e2133d922c9e → 4.1.0-canary.e23ee15a46bc

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 (72) hide show
  1. package/dist-cjs/index.d.ts +1884 -153
  2. package/dist-cjs/index.js +1 -1
  3. package/dist-cjs/lib/AtomMap.js +241 -1
  4. package/dist-cjs/lib/AtomMap.js.map +2 -2
  5. package/dist-cjs/lib/BaseRecord.js.map +2 -2
  6. package/dist-cjs/lib/ImmutableMap.js +141 -0
  7. package/dist-cjs/lib/ImmutableMap.js.map +2 -2
  8. package/dist-cjs/lib/IncrementalSetConstructor.js +45 -5
  9. package/dist-cjs/lib/IncrementalSetConstructor.js.map +2 -2
  10. package/dist-cjs/lib/RecordType.js +116 -21
  11. package/dist-cjs/lib/RecordType.js.map +2 -2
  12. package/dist-cjs/lib/RecordsDiff.js.map +2 -2
  13. package/dist-cjs/lib/Store.js +233 -39
  14. package/dist-cjs/lib/Store.js.map +2 -2
  15. package/dist-cjs/lib/StoreQueries.js +135 -22
  16. package/dist-cjs/lib/StoreQueries.js.map +2 -2
  17. package/dist-cjs/lib/StoreSchema.js +207 -2
  18. package/dist-cjs/lib/StoreSchema.js.map +2 -2
  19. package/dist-cjs/lib/StoreSideEffects.js +102 -10
  20. package/dist-cjs/lib/StoreSideEffects.js.map +2 -2
  21. package/dist-cjs/lib/executeQuery.js.map +2 -2
  22. package/dist-cjs/lib/migrate.js.map +2 -2
  23. package/dist-cjs/lib/setUtils.js.map +2 -2
  24. package/dist-esm/index.d.mts +1884 -153
  25. package/dist-esm/index.mjs +1 -1
  26. package/dist-esm/lib/AtomMap.mjs +241 -1
  27. package/dist-esm/lib/AtomMap.mjs.map +2 -2
  28. package/dist-esm/lib/BaseRecord.mjs.map +2 -2
  29. package/dist-esm/lib/ImmutableMap.mjs +141 -0
  30. package/dist-esm/lib/ImmutableMap.mjs.map +2 -2
  31. package/dist-esm/lib/IncrementalSetConstructor.mjs +45 -5
  32. package/dist-esm/lib/IncrementalSetConstructor.mjs.map +2 -2
  33. package/dist-esm/lib/RecordType.mjs +116 -21
  34. package/dist-esm/lib/RecordType.mjs.map +2 -2
  35. package/dist-esm/lib/RecordsDiff.mjs.map +2 -2
  36. package/dist-esm/lib/Store.mjs +233 -39
  37. package/dist-esm/lib/Store.mjs.map +2 -2
  38. package/dist-esm/lib/StoreQueries.mjs +135 -22
  39. package/dist-esm/lib/StoreQueries.mjs.map +2 -2
  40. package/dist-esm/lib/StoreSchema.mjs +207 -2
  41. package/dist-esm/lib/StoreSchema.mjs.map +2 -2
  42. package/dist-esm/lib/StoreSideEffects.mjs +102 -10
  43. package/dist-esm/lib/StoreSideEffects.mjs.map +2 -2
  44. package/dist-esm/lib/executeQuery.mjs.map +2 -2
  45. package/dist-esm/lib/migrate.mjs.map +2 -2
  46. package/dist-esm/lib/setUtils.mjs.map +2 -2
  47. package/package.json +3 -3
  48. package/src/lib/AtomMap.ts +241 -1
  49. package/src/lib/BaseRecord.test.ts +44 -0
  50. package/src/lib/BaseRecord.ts +118 -4
  51. package/src/lib/ImmutableMap.test.ts +103 -0
  52. package/src/lib/ImmutableMap.ts +212 -0
  53. package/src/lib/IncrementalSetConstructor.test.ts +111 -0
  54. package/src/lib/IncrementalSetConstructor.ts +63 -6
  55. package/src/lib/RecordType.ts +149 -25
  56. package/src/lib/RecordsDiff.test.ts +144 -0
  57. package/src/lib/RecordsDiff.ts +145 -10
  58. package/src/lib/Store.test.ts +827 -0
  59. package/src/lib/Store.ts +533 -67
  60. package/src/lib/StoreQueries.test.ts +627 -0
  61. package/src/lib/StoreQueries.ts +194 -27
  62. package/src/lib/StoreSchema.test.ts +226 -0
  63. package/src/lib/StoreSchema.ts +386 -8
  64. package/src/lib/StoreSideEffects.test.ts +239 -19
  65. package/src/lib/StoreSideEffects.ts +266 -19
  66. package/src/lib/devFreeze.test.ts +137 -0
  67. package/src/lib/executeQuery.test.ts +481 -0
  68. package/src/lib/executeQuery.ts +80 -2
  69. package/src/lib/migrate.test.ts +400 -0
  70. package/src/lib/migrate.ts +187 -14
  71. package/src/lib/setUtils.test.ts +105 -0
  72. package/src/lib/setUtils.ts +44 -4
@@ -28,7 +28,7 @@ import {
28
28
  } from "./lib/StoreSideEffects.mjs";
29
29
  registerTldrawLibraryVersion(
30
30
  "@tldraw/store",
31
- "4.1.0-canary.e2133d922c9e",
31
+ "4.1.0-canary.e23ee15a46bc",
32
32
  "esm"
33
33
  );
34
34
  export {
@@ -2,6 +2,21 @@ import { atom, transact, UNINITIALIZED } from "@tldraw/state";
2
2
  import { assert } from "@tldraw/utils";
3
3
  import { emptyMap } from "./ImmutableMap.mjs";
4
4
  class AtomMap {
5
+ /**
6
+ * Creates a new AtomMap instance.
7
+ *
8
+ * name - A unique name for this map, used for atom identification
9
+ * entries - Optional initial entries to populate the map with
10
+ * @example
11
+ * ```ts
12
+ * // Create an empty map
13
+ * const map = new AtomMap('userMap')
14
+ *
15
+ * // Create a map with initial data
16
+ * const initialData: [string, number][] = [['a', 1], ['b', 2]]
17
+ * const mapWithData = new AtomMap('numbersMap', initialData)
18
+ * ```
19
+ */
5
20
  constructor(name, entries) {
6
21
  this.name = name;
7
22
  let atoms = emptyMap();
@@ -15,7 +30,13 @@ class AtomMap {
15
30
  this.atoms = atom(`${name}:atoms`, atoms);
16
31
  }
17
32
  atoms;
18
- /** @internal */
33
+ /**
34
+ * Retrieves the underlying atom for a given key.
35
+ *
36
+ * @param key - The key to retrieve the atom for
37
+ * @returns The atom containing the value, or undefined if the key doesn't exist
38
+ * @internal
39
+ */
19
40
  getAtom(key) {
20
41
  const valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key);
21
42
  if (!valueAtom) {
@@ -24,11 +45,38 @@ class AtomMap {
24
45
  }
25
46
  return valueAtom;
26
47
  }
48
+ /**
49
+ * Gets the value associated with a key. Returns undefined if the key doesn't exist.
50
+ * This method is reactive and will cause reactive contexts to update when the value changes.
51
+ *
52
+ * @param key - The key to retrieve the value for
53
+ * @returns The value associated with the key, or undefined if not found
54
+ * @example
55
+ * ```ts
56
+ * const map = new AtomMap('myMap')
57
+ * map.set('name', 'Alice')
58
+ * console.log(map.get('name')) // 'Alice'
59
+ * console.log(map.get('missing')) // undefined
60
+ * ```
61
+ */
27
62
  get(key) {
28
63
  const value = this.getAtom(key)?.get();
29
64
  assert(value !== UNINITIALIZED);
30
65
  return value;
31
66
  }
67
+ /**
68
+ * Gets the value associated with a key without creating reactive dependencies.
69
+ * This method will not cause reactive contexts to update when the value changes.
70
+ *
71
+ * @param key - The key to retrieve the value for
72
+ * @returns The value associated with the key, or undefined if not found
73
+ * @example
74
+ * ```ts
75
+ * const map = new AtomMap('myMap')
76
+ * map.set('count', 42)
77
+ * const value = map.__unsafe__getWithoutCapture('count') // No reactive subscription
78
+ * ```
79
+ */
32
80
  __unsafe__getWithoutCapture(key) {
33
81
  const valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key);
34
82
  if (!valueAtom) return void 0;
@@ -36,6 +84,20 @@ class AtomMap {
36
84
  assert(value !== UNINITIALIZED);
37
85
  return value;
38
86
  }
87
+ /**
88
+ * Checks whether a key exists in the map.
89
+ * This method is reactive and will cause reactive contexts to update when keys are added or removed.
90
+ *
91
+ * @param key - The key to check for
92
+ * @returns True if the key exists in the map, false otherwise
93
+ * @example
94
+ * ```ts
95
+ * const map = new AtomMap('myMap')
96
+ * console.log(map.has('name')) // false
97
+ * map.set('name', 'Alice')
98
+ * console.log(map.has('name')) // true
99
+ * ```
100
+ */
39
101
  has(key) {
40
102
  const valueAtom = this.getAtom(key);
41
103
  if (!valueAtom) {
@@ -43,12 +105,38 @@ class AtomMap {
43
105
  }
44
106
  return valueAtom.get() !== UNINITIALIZED;
45
107
  }
108
+ /**
109
+ * Checks whether a key exists in the map without creating reactive dependencies.
110
+ * This method will not cause reactive contexts to update when keys are added or removed.
111
+ *
112
+ * @param key - The key to check for
113
+ * @returns True if the key exists in the map, false otherwise
114
+ * @example
115
+ * ```ts
116
+ * const map = new AtomMap('myMap')
117
+ * map.set('active', true)
118
+ * const exists = map.__unsafe__hasWithoutCapture('active') // No reactive subscription
119
+ * ```
120
+ */
46
121
  __unsafe__hasWithoutCapture(key) {
47
122
  const valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key);
48
123
  if (!valueAtom) return false;
49
124
  assert(valueAtom.__unsafe__getWithoutCapture() !== UNINITIALIZED);
50
125
  return true;
51
126
  }
127
+ /**
128
+ * Sets a value for the given key. If the key already exists, its value is updated.
129
+ * If the key doesn't exist, a new entry is created.
130
+ *
131
+ * @param key - The key to set the value for
132
+ * @param value - The value to associate with the key
133
+ * @returns This AtomMap instance for method chaining
134
+ * @example
135
+ * ```ts
136
+ * const map = new AtomMap('myMap')
137
+ * map.set('name', 'Alice').set('age', 30)
138
+ * ```
139
+ */
52
140
  set(key, value) {
53
141
  const existingAtom = this.atoms.__unsafe__getWithoutCapture().get(key);
54
142
  if (existingAtom) {
@@ -60,6 +148,19 @@ class AtomMap {
60
148
  }
61
149
  return this;
62
150
  }
151
+ /**
152
+ * Updates an existing value using an updater function.
153
+ *
154
+ * @param key - The key of the value to update
155
+ * @param updater - A function that receives the current value and returns the new value
156
+ * @throws Error if the key doesn't exist in the map
157
+ * @example
158
+ * ```ts
159
+ * const map = new AtomMap('myMap')
160
+ * map.set('count', 5)
161
+ * map.update('count', count => count + 1) // count is now 6
162
+ * ```
163
+ */
63
164
  update(key, updater) {
64
165
  const valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key);
65
166
  if (!valueAtom) {
@@ -69,6 +170,19 @@ class AtomMap {
69
170
  assert(value !== UNINITIALIZED);
70
171
  valueAtom.set(updater(value));
71
172
  }
173
+ /**
174
+ * Removes a key-value pair from the map.
175
+ *
176
+ * @param key - The key to remove
177
+ * @returns True if the key existed and was removed, false if it didn't exist
178
+ * @example
179
+ * ```ts
180
+ * const map = new AtomMap('myMap')
181
+ * map.set('temp', 'value')
182
+ * console.log(map.delete('temp')) // true
183
+ * console.log(map.delete('missing')) // false
184
+ * ```
185
+ */
72
186
  delete(key) {
73
187
  const valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key);
74
188
  if (!valueAtom) {
@@ -82,6 +196,19 @@ class AtomMap {
82
196
  });
83
197
  return true;
84
198
  }
199
+ /**
200
+ * Removes multiple key-value pairs from the map in a single transaction.
201
+ *
202
+ * @param keys - An iterable of keys to remove
203
+ * @returns An array of [key, value] pairs that were actually deleted
204
+ * @example
205
+ * ```ts
206
+ * const map = new AtomMap('myMap')
207
+ * map.set('a', 1).set('b', 2).set('c', 3)
208
+ * const deleted = map.deleteMany(['a', 'c', 'missing'])
209
+ * console.log(deleted) // [['a', 1], ['c', 3]]
210
+ * ```
211
+ */
85
212
  deleteMany(keys) {
86
213
  return transact(() => {
87
214
  const deleted = [];
@@ -102,6 +229,17 @@ class AtomMap {
102
229
  return deleted;
103
230
  });
104
231
  }
232
+ /**
233
+ * Removes all key-value pairs from the map.
234
+ *
235
+ * @example
236
+ * ```ts
237
+ * const map = new AtomMap('myMap')
238
+ * map.set('a', 1).set('b', 2)
239
+ * map.clear()
240
+ * console.log(map.size) // 0
241
+ * ```
242
+ */
105
243
  clear() {
106
244
  return transact(() => {
107
245
  for (const valueAtom of this.atoms.__unsafe__getWithoutCapture().values()) {
@@ -110,6 +248,20 @@ class AtomMap {
110
248
  this.atoms.set(emptyMap());
111
249
  });
112
250
  }
251
+ /**
252
+ * Returns an iterator that yields [key, value] pairs for each entry in the map.
253
+ * This method is reactive and will cause reactive contexts to update when entries change.
254
+ *
255
+ * @returns A generator that yields [key, value] tuples
256
+ * @example
257
+ * ```ts
258
+ * const map = new AtomMap('myMap')
259
+ * map.set('a', 1).set('b', 2)
260
+ * for (const [key, value] of map.entries()) {
261
+ * console.log(`${key}: ${value}`)
262
+ * }
263
+ * ```
264
+ */
113
265
  *entries() {
114
266
  for (const [key, valueAtom] of this.atoms.get()) {
115
267
  const value = valueAtom.get();
@@ -117,11 +269,39 @@ class AtomMap {
117
269
  yield [key, value];
118
270
  }
119
271
  }
272
+ /**
273
+ * Returns an iterator that yields all keys in the map.
274
+ * This method is reactive and will cause reactive contexts to update when keys change.
275
+ *
276
+ * @returns A generator that yields keys
277
+ * @example
278
+ * ```ts
279
+ * const map = new AtomMap('myMap')
280
+ * map.set('name', 'Alice').set('age', 30)
281
+ * for (const key of map.keys()) {
282
+ * console.log(key) // 'name', 'age'
283
+ * }
284
+ * ```
285
+ */
120
286
  *keys() {
121
287
  for (const key of this.atoms.get().keys()) {
122
288
  yield key;
123
289
  }
124
290
  }
291
+ /**
292
+ * Returns an iterator that yields all values in the map.
293
+ * This method is reactive and will cause reactive contexts to update when values change.
294
+ *
295
+ * @returns A generator that yields values
296
+ * @example
297
+ * ```ts
298
+ * const map = new AtomMap('myMap')
299
+ * map.set('name', 'Alice').set('age', 30)
300
+ * for (const value of map.values()) {
301
+ * console.log(value) // 'Alice', 30
302
+ * }
303
+ * ```
304
+ */
125
305
  *values() {
126
306
  for (const valueAtom of this.atoms.get().values()) {
127
307
  const value = valueAtom.get();
@@ -129,18 +309,78 @@ class AtomMap {
129
309
  yield value;
130
310
  }
131
311
  }
312
+ /**
313
+ * The number of key-value pairs in the map.
314
+ * This property is reactive and will cause reactive contexts to update when the size changes.
315
+ *
316
+ * @returns The number of entries in the map
317
+ * @example
318
+ * ```ts
319
+ * const map = new AtomMap('myMap')
320
+ * console.log(map.size) // 0
321
+ * map.set('a', 1)
322
+ * console.log(map.size) // 1
323
+ * ```
324
+ */
132
325
  // eslint-disable-next-line no-restricted-syntax
133
326
  get size() {
134
327
  return this.atoms.get().size;
135
328
  }
329
+ /**
330
+ * Executes a provided function once for each key-value pair in the map.
331
+ * This method is reactive and will cause reactive contexts to update when entries change.
332
+ *
333
+ * @param callbackfn - Function to execute for each entry
334
+ * - value - The value of the current entry
335
+ * - key - The key of the current entry
336
+ * - map - The AtomMap being traversed
337
+ * @param thisArg - Value to use as `this` when executing the callback
338
+ * @example
339
+ * ```ts
340
+ * const map = new AtomMap('myMap')
341
+ * map.set('a', 1).set('b', 2)
342
+ * map.forEach((value, key) => {
343
+ * console.log(`${key} = ${value}`)
344
+ * })
345
+ * ```
346
+ */
136
347
  forEach(callbackfn, thisArg) {
137
348
  for (const [key, value] of this.entries()) {
138
349
  callbackfn.call(thisArg, value, key, this);
139
350
  }
140
351
  }
352
+ /**
353
+ * Returns the default iterator for the map, which is the same as entries().
354
+ * This allows the map to be used in for...of loops and other iterable contexts.
355
+ *
356
+ * @returns The same iterator as entries()
357
+ * @example
358
+ * ```ts
359
+ * const map = new AtomMap('myMap')
360
+ * map.set('a', 1).set('b', 2)
361
+ *
362
+ * // These are equivalent:
363
+ * for (const [key, value] of map) {
364
+ * console.log(`${key}: ${value}`)
365
+ * }
366
+ *
367
+ * for (const [key, value] of map.entries()) {
368
+ * console.log(`${key}: ${value}`)
369
+ * }
370
+ * ```
371
+ */
141
372
  [Symbol.iterator]() {
142
373
  return this.entries();
143
374
  }
375
+ /**
376
+ * The string tag used by Object.prototype.toString for this class.
377
+ *
378
+ * @example
379
+ * ```ts
380
+ * const map = new AtomMap('myMap')
381
+ * console.log(Object.prototype.toString.call(map)) // '[object AtomMap]'
382
+ * ```
383
+ */
144
384
  [Symbol.toStringTag] = "AtomMap";
145
385
  }
146
386
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/AtomMap.ts"],
4
- "sourcesContent": ["import { atom, Atom, transact, UNINITIALIZED } from '@tldraw/state'\nimport { assert } from '@tldraw/utils'\nimport { emptyMap, ImmutableMap } from './ImmutableMap'\n\n/**\n * A drop-in replacement for Map that stores values in atoms and can be used in reactive contexts.\n * @public\n */\nexport class AtomMap<K, V> implements Map<K, V> {\n\tprivate atoms: Atom<ImmutableMap<K, Atom<V | UNINITIALIZED>>>\n\n\tconstructor(\n\t\tprivate readonly name: string,\n\t\tentries?: Iterable<readonly [K, V]>\n\t) {\n\t\tlet atoms = emptyMap<K, Atom<V>>()\n\t\tif (entries) {\n\t\t\tatoms = atoms.withMutations((atoms) => {\n\t\t\t\tfor (const [k, v] of entries) {\n\t\t\t\t\tatoms.set(k, atom(`${name}:${String(k)}`, v))\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t\tthis.atoms = atom(`${name}:atoms`, atoms)\n\t}\n\n\t/** @internal */\n\tgetAtom(key: K): Atom<V | UNINITIALIZED> | undefined {\n\t\tconst valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key)\n\t\tif (!valueAtom) {\n\t\t\t// if the value is missing, we want to track whether it's in the present keys set\n\t\t\tthis.atoms.get()\n\t\t\treturn undefined\n\t\t}\n\t\treturn valueAtom\n\t}\n\n\tget(key: K): V | undefined {\n\t\tconst value = this.getAtom(key)?.get()\n\t\tassert(value !== UNINITIALIZED)\n\t\treturn value\n\t}\n\n\t__unsafe__getWithoutCapture(key: K): V | undefined {\n\t\tconst valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key)\n\t\tif (!valueAtom) return undefined\n\t\tconst value = valueAtom.__unsafe__getWithoutCapture()\n\t\tassert(value !== UNINITIALIZED)\n\t\treturn value\n\t}\n\n\thas(key: K): boolean {\n\t\tconst valueAtom = this.getAtom(key)\n\t\tif (!valueAtom) {\n\t\t\treturn false\n\t\t}\n\t\treturn valueAtom.get() !== UNINITIALIZED\n\t}\n\n\t__unsafe__hasWithoutCapture(key: K): boolean {\n\t\tconst valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key)\n\t\tif (!valueAtom) return false\n\t\tassert(valueAtom.__unsafe__getWithoutCapture() !== UNINITIALIZED)\n\t\treturn true\n\t}\n\n\tset(key: K, value: V) {\n\t\tconst existingAtom = this.atoms.__unsafe__getWithoutCapture().get(key)\n\t\tif (existingAtom) {\n\t\t\texistingAtom.set(value)\n\t\t} else {\n\t\t\tthis.atoms.update((atoms) => {\n\t\t\t\treturn atoms.set(key, atom(`${this.name}:${String(key)}`, value))\n\t\t\t})\n\t\t}\n\t\treturn this\n\t}\n\n\tupdate(key: K, updater: (value: V) => V) {\n\t\tconst valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key)\n\t\tif (!valueAtom) {\n\t\t\tthrow new Error(`AtomMap: key ${key} not found`)\n\t\t}\n\t\tconst value = valueAtom.__unsafe__getWithoutCapture()\n\t\tassert(value !== UNINITIALIZED)\n\t\tvalueAtom.set(updater(value))\n\t}\n\n\tdelete(key: K) {\n\t\tconst valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key)\n\t\tif (!valueAtom) {\n\t\t\treturn false\n\t\t}\n\n\t\ttransact(() => {\n\t\t\tvalueAtom.set(UNINITIALIZED)\n\t\t\tthis.atoms.update((atoms) => {\n\t\t\t\treturn atoms.delete(key)\n\t\t\t})\n\t\t})\n\t\treturn true\n\t}\n\n\tdeleteMany(keys: Iterable<K>): [K, V][] {\n\t\treturn transact(() => {\n\t\t\tconst deleted: [K, V][] = []\n\t\t\tconst newAtoms = this.atoms.get().withMutations((atoms) => {\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\tconst valueAtom = atoms.get(key)\n\t\t\t\t\tif (!valueAtom) continue\n\t\t\t\t\tconst oldValue = valueAtom.get()\n\t\t\t\t\tassert(oldValue !== UNINITIALIZED)\n\n\t\t\t\t\tdeleted.push([key, oldValue])\n\n\t\t\t\t\tatoms.delete(key)\n\t\t\t\t\tvalueAtom.set(UNINITIALIZED)\n\t\t\t\t}\n\t\t\t})\n\n\t\t\tif (deleted.length) {\n\t\t\t\tthis.atoms.set(newAtoms)\n\t\t\t}\n\n\t\t\treturn deleted\n\t\t})\n\t}\n\n\tclear() {\n\t\treturn transact(() => {\n\t\t\tfor (const valueAtom of this.atoms.__unsafe__getWithoutCapture().values()) {\n\t\t\t\tvalueAtom.set(UNINITIALIZED)\n\t\t\t}\n\t\t\tthis.atoms.set(emptyMap())\n\t\t})\n\t}\n\n\t*entries(): Generator<[K, V], undefined, unknown> {\n\t\tfor (const [key, valueAtom] of this.atoms.get()) {\n\t\t\tconst value = valueAtom.get()\n\t\t\tassert(value !== UNINITIALIZED)\n\t\t\tyield [key, value]\n\t\t}\n\t}\n\n\t*keys(): Generator<K, undefined, unknown> {\n\t\tfor (const key of this.atoms.get().keys()) {\n\t\t\tyield key\n\t\t}\n\t}\n\n\t*values(): Generator<V, undefined, unknown> {\n\t\tfor (const valueAtom of this.atoms.get().values()) {\n\t\t\tconst value = valueAtom.get()\n\t\t\tassert(value !== UNINITIALIZED)\n\t\t\tyield value\n\t\t}\n\t}\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget size() {\n\t\treturn this.atoms.get().size\n\t}\n\n\tforEach(callbackfn: (value: V, key: K, map: AtomMap<K, V>) => void, thisArg?: any): void {\n\t\tfor (const [key, value] of this.entries()) {\n\t\t\tcallbackfn.call(thisArg, value, key, this)\n\t\t}\n\t}\n\n\t[Symbol.iterator]() {\n\t\treturn this.entries()\n\t}\n\n\t[Symbol.toStringTag] = 'AtomMap'\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { atom, Atom, transact, UNINITIALIZED } from '@tldraw/state'\nimport { assert } from '@tldraw/utils'\nimport { emptyMap, ImmutableMap } from './ImmutableMap'\n\n/**\n * A drop-in replacement for Map that stores values in atoms and can be used in reactive contexts.\n * @public\n */\nexport class AtomMap<K, V> implements Map<K, V> {\n\tprivate atoms: Atom<ImmutableMap<K, Atom<V | UNINITIALIZED>>>\n\n\t/**\n\t * Creates a new AtomMap instance.\n\t *\n\t * name - A unique name for this map, used for atom identification\n\t * entries - Optional initial entries to populate the map with\n\t * @example\n\t * ```ts\n\t * // Create an empty map\n\t * const map = new AtomMap('userMap')\n\t *\n\t * // Create a map with initial data\n\t * const initialData: [string, number][] = [['a', 1], ['b', 2]]\n\t * const mapWithData = new AtomMap('numbersMap', initialData)\n\t * ```\n\t */\n\tconstructor(\n\t\tprivate readonly name: string,\n\t\tentries?: Iterable<readonly [K, V]>\n\t) {\n\t\tlet atoms = emptyMap<K, Atom<V>>()\n\t\tif (entries) {\n\t\t\tatoms = atoms.withMutations((atoms) => {\n\t\t\t\tfor (const [k, v] of entries) {\n\t\t\t\t\tatoms.set(k, atom(`${name}:${String(k)}`, v))\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t\tthis.atoms = atom(`${name}:atoms`, atoms)\n\t}\n\n\t/**\n\t * Retrieves the underlying atom for a given key.\n\t *\n\t * @param key - The key to retrieve the atom for\n\t * @returns The atom containing the value, or undefined if the key doesn't exist\n\t * @internal\n\t */\n\tgetAtom(key: K): Atom<V | UNINITIALIZED> | undefined {\n\t\tconst valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key)\n\t\tif (!valueAtom) {\n\t\t\t// if the value is missing, we want to track whether it's in the present keys set\n\t\t\tthis.atoms.get()\n\t\t\treturn undefined\n\t\t}\n\t\treturn valueAtom\n\t}\n\n\t/**\n\t * Gets the value associated with a key. Returns undefined if the key doesn't exist.\n\t * This method is reactive and will cause reactive contexts to update when the value changes.\n\t *\n\t * @param key - The key to retrieve the value for\n\t * @returns The value associated with the key, or undefined if not found\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('name', 'Alice')\n\t * console.log(map.get('name')) // 'Alice'\n\t * console.log(map.get('missing')) // undefined\n\t * ```\n\t */\n\tget(key: K): V | undefined {\n\t\tconst value = this.getAtom(key)?.get()\n\t\tassert(value !== UNINITIALIZED)\n\t\treturn value\n\t}\n\n\t/**\n\t * Gets the value associated with a key without creating reactive dependencies.\n\t * This method will not cause reactive contexts to update when the value changes.\n\t *\n\t * @param key - The key to retrieve the value for\n\t * @returns The value associated with the key, or undefined if not found\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('count', 42)\n\t * const value = map.__unsafe__getWithoutCapture('count') // No reactive subscription\n\t * ```\n\t */\n\t__unsafe__getWithoutCapture(key: K): V | undefined {\n\t\tconst valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key)\n\t\tif (!valueAtom) return undefined\n\t\tconst value = valueAtom.__unsafe__getWithoutCapture()\n\t\tassert(value !== UNINITIALIZED)\n\t\treturn value\n\t}\n\n\t/**\n\t * Checks whether a key exists in the map.\n\t * This method is reactive and will cause reactive contexts to update when keys are added or removed.\n\t *\n\t * @param key - The key to check for\n\t * @returns True if the key exists in the map, false otherwise\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * console.log(map.has('name')) // false\n\t * map.set('name', 'Alice')\n\t * console.log(map.has('name')) // true\n\t * ```\n\t */\n\thas(key: K): boolean {\n\t\tconst valueAtom = this.getAtom(key)\n\t\tif (!valueAtom) {\n\t\t\treturn false\n\t\t}\n\t\treturn valueAtom.get() !== UNINITIALIZED\n\t}\n\n\t/**\n\t * Checks whether a key exists in the map without creating reactive dependencies.\n\t * This method will not cause reactive contexts to update when keys are added or removed.\n\t *\n\t * @param key - The key to check for\n\t * @returns True if the key exists in the map, false otherwise\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('active', true)\n\t * const exists = map.__unsafe__hasWithoutCapture('active') // No reactive subscription\n\t * ```\n\t */\n\t__unsafe__hasWithoutCapture(key: K): boolean {\n\t\tconst valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key)\n\t\tif (!valueAtom) return false\n\t\tassert(valueAtom.__unsafe__getWithoutCapture() !== UNINITIALIZED)\n\t\treturn true\n\t}\n\n\t/**\n\t * Sets a value for the given key. If the key already exists, its value is updated.\n\t * If the key doesn't exist, a new entry is created.\n\t *\n\t * @param key - The key to set the value for\n\t * @param value - The value to associate with the key\n\t * @returns This AtomMap instance for method chaining\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('name', 'Alice').set('age', 30)\n\t * ```\n\t */\n\tset(key: K, value: V) {\n\t\tconst existingAtom = this.atoms.__unsafe__getWithoutCapture().get(key)\n\t\tif (existingAtom) {\n\t\t\texistingAtom.set(value)\n\t\t} else {\n\t\t\tthis.atoms.update((atoms) => {\n\t\t\t\treturn atoms.set(key, atom(`${this.name}:${String(key)}`, value))\n\t\t\t})\n\t\t}\n\t\treturn this\n\t}\n\n\t/**\n\t * Updates an existing value using an updater function.\n\t *\n\t * @param key - The key of the value to update\n\t * @param updater - A function that receives the current value and returns the new value\n\t * @throws Error if the key doesn't exist in the map\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('count', 5)\n\t * map.update('count', count => count + 1) // count is now 6\n\t * ```\n\t */\n\tupdate(key: K, updater: (value: V) => V) {\n\t\tconst valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key)\n\t\tif (!valueAtom) {\n\t\t\tthrow new Error(`AtomMap: key ${key} not found`)\n\t\t}\n\t\tconst value = valueAtom.__unsafe__getWithoutCapture()\n\t\tassert(value !== UNINITIALIZED)\n\t\tvalueAtom.set(updater(value))\n\t}\n\n\t/**\n\t * Removes a key-value pair from the map.\n\t *\n\t * @param key - The key to remove\n\t * @returns True if the key existed and was removed, false if it didn't exist\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('temp', 'value')\n\t * console.log(map.delete('temp')) // true\n\t * console.log(map.delete('missing')) // false\n\t * ```\n\t */\n\tdelete(key: K) {\n\t\tconst valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key)\n\t\tif (!valueAtom) {\n\t\t\treturn false\n\t\t}\n\n\t\ttransact(() => {\n\t\t\tvalueAtom.set(UNINITIALIZED)\n\t\t\tthis.atoms.update((atoms) => {\n\t\t\t\treturn atoms.delete(key)\n\t\t\t})\n\t\t})\n\t\treturn true\n\t}\n\n\t/**\n\t * Removes multiple key-value pairs from the map in a single transaction.\n\t *\n\t * @param keys - An iterable of keys to remove\n\t * @returns An array of [key, value] pairs that were actually deleted\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('a', 1).set('b', 2).set('c', 3)\n\t * const deleted = map.deleteMany(['a', 'c', 'missing'])\n\t * console.log(deleted) // [['a', 1], ['c', 3]]\n\t * ```\n\t */\n\tdeleteMany(keys: Iterable<K>): [K, V][] {\n\t\treturn transact(() => {\n\t\t\tconst deleted: [K, V][] = []\n\t\t\tconst newAtoms = this.atoms.get().withMutations((atoms) => {\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\tconst valueAtom = atoms.get(key)\n\t\t\t\t\tif (!valueAtom) continue\n\t\t\t\t\tconst oldValue = valueAtom.get()\n\t\t\t\t\tassert(oldValue !== UNINITIALIZED)\n\n\t\t\t\t\tdeleted.push([key, oldValue])\n\n\t\t\t\t\tatoms.delete(key)\n\t\t\t\t\tvalueAtom.set(UNINITIALIZED)\n\t\t\t\t}\n\t\t\t})\n\n\t\t\tif (deleted.length) {\n\t\t\t\tthis.atoms.set(newAtoms)\n\t\t\t}\n\n\t\t\treturn deleted\n\t\t})\n\t}\n\n\t/**\n\t * Removes all key-value pairs from the map.\n\t *\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('a', 1).set('b', 2)\n\t * map.clear()\n\t * console.log(map.size) // 0\n\t * ```\n\t */\n\tclear() {\n\t\treturn transact(() => {\n\t\t\tfor (const valueAtom of this.atoms.__unsafe__getWithoutCapture().values()) {\n\t\t\t\tvalueAtom.set(UNINITIALIZED)\n\t\t\t}\n\t\t\tthis.atoms.set(emptyMap())\n\t\t})\n\t}\n\n\t/**\n\t * Returns an iterator that yields [key, value] pairs for each entry in the map.\n\t * This method is reactive and will cause reactive contexts to update when entries change.\n\t *\n\t * @returns A generator that yields [key, value] tuples\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('a', 1).set('b', 2)\n\t * for (const [key, value] of map.entries()) {\n\t * console.log(`${key}: ${value}`)\n\t * }\n\t * ```\n\t */\n\t*entries(): Generator<[K, V], undefined, unknown> {\n\t\tfor (const [key, valueAtom] of this.atoms.get()) {\n\t\t\tconst value = valueAtom.get()\n\t\t\tassert(value !== UNINITIALIZED)\n\t\t\tyield [key, value]\n\t\t}\n\t}\n\n\t/**\n\t * Returns an iterator that yields all keys in the map.\n\t * This method is reactive and will cause reactive contexts to update when keys change.\n\t *\n\t * @returns A generator that yields keys\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('name', 'Alice').set('age', 30)\n\t * for (const key of map.keys()) {\n\t * console.log(key) // 'name', 'age'\n\t * }\n\t * ```\n\t */\n\t*keys(): Generator<K, undefined, unknown> {\n\t\tfor (const key of this.atoms.get().keys()) {\n\t\t\tyield key\n\t\t}\n\t}\n\n\t/**\n\t * Returns an iterator that yields all values in the map.\n\t * This method is reactive and will cause reactive contexts to update when values change.\n\t *\n\t * @returns A generator that yields values\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('name', 'Alice').set('age', 30)\n\t * for (const value of map.values()) {\n\t * console.log(value) // 'Alice', 30\n\t * }\n\t * ```\n\t */\n\t*values(): Generator<V, undefined, unknown> {\n\t\tfor (const valueAtom of this.atoms.get().values()) {\n\t\t\tconst value = valueAtom.get()\n\t\t\tassert(value !== UNINITIALIZED)\n\t\t\tyield value\n\t\t}\n\t}\n\n\t/**\n\t * The number of key-value pairs in the map.\n\t * This property is reactive and will cause reactive contexts to update when the size changes.\n\t *\n\t * @returns The number of entries in the map\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * console.log(map.size) // 0\n\t * map.set('a', 1)\n\t * console.log(map.size) // 1\n\t * ```\n\t */\n\t// eslint-disable-next-line no-restricted-syntax\n\tget size() {\n\t\treturn this.atoms.get().size\n\t}\n\n\t/**\n\t * Executes a provided function once for each key-value pair in the map.\n\t * This method is reactive and will cause reactive contexts to update when entries change.\n\t *\n\t * @param callbackfn - Function to execute for each entry\n\t * - value - The value of the current entry\n\t * - key - The key of the current entry\n\t * - map - The AtomMap being traversed\n\t * @param thisArg - Value to use as `this` when executing the callback\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('a', 1).set('b', 2)\n\t * map.forEach((value, key) => {\n\t * console.log(`${key} = ${value}`)\n\t * })\n\t * ```\n\t */\n\tforEach(callbackfn: (value: V, key: K, map: AtomMap<K, V>) => void, thisArg?: any): void {\n\t\tfor (const [key, value] of this.entries()) {\n\t\t\tcallbackfn.call(thisArg, value, key, this)\n\t\t}\n\t}\n\n\t/**\n\t * Returns the default iterator for the map, which is the same as entries().\n\t * This allows the map to be used in for...of loops and other iterable contexts.\n\t *\n\t * @returns The same iterator as entries()\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('a', 1).set('b', 2)\n\t *\n\t * // These are equivalent:\n\t * for (const [key, value] of map) {\n\t * console.log(`${key}: ${value}`)\n\t * }\n\t *\n\t * for (const [key, value] of map.entries()) {\n\t * console.log(`${key}: ${value}`)\n\t * }\n\t * ```\n\t */\n\t[Symbol.iterator]() {\n\t\treturn this.entries()\n\t}\n\n\t/**\n\t * The string tag used by Object.prototype.toString for this class.\n\t *\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * console.log(Object.prototype.toString.call(map)) // '[object AtomMap]'\n\t * ```\n\t */\n\t[Symbol.toStringTag] = 'AtomMap'\n}\n"],
5
+ "mappings": "AAAA,SAAS,MAAY,UAAU,qBAAqB;AACpD,SAAS,cAAc;AACvB,SAAS,gBAA8B;AAMhC,MAAM,QAAmC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkB/C,YACkB,MACjB,SACC;AAFgB;AAGjB,QAAI,QAAQ,SAAqB;AACjC,QAAI,SAAS;AACZ,cAAQ,MAAM,cAAc,CAACA,WAAU;AACtC,mBAAW,CAAC,GAAG,CAAC,KAAK,SAAS;AAC7B,UAAAA,OAAM,IAAI,GAAG,KAAK,GAAG,IAAI,IAAI,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC;AAAA,QAC7C;AAAA,MACD,CAAC;AAAA,IACF;AACA,SAAK,QAAQ,KAAK,GAAG,IAAI,UAAU,KAAK;AAAA,EACzC;AAAA,EA9BQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuCR,QAAQ,KAA6C;AACpD,UAAM,YAAY,KAAK,MAAM,4BAA4B,EAAE,IAAI,GAAG;AAClE,QAAI,CAAC,WAAW;AAEf,WAAK,MAAM,IAAI;AACf,aAAO;AAAA,IACR;AACA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,IAAI,KAAuB;AAC1B,UAAM,QAAQ,KAAK,QAAQ,GAAG,GAAG,IAAI;AACrC,WAAO,UAAU,aAAa;AAC9B,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,4BAA4B,KAAuB;AAClD,UAAM,YAAY,KAAK,MAAM,4BAA4B,EAAE,IAAI,GAAG;AAClE,QAAI,CAAC,UAAW,QAAO;AACvB,UAAM,QAAQ,UAAU,4BAA4B;AACpD,WAAO,UAAU,aAAa;AAC9B,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,IAAI,KAAiB;AACpB,UAAM,YAAY,KAAK,QAAQ,GAAG;AAClC,QAAI,CAAC,WAAW;AACf,aAAO;AAAA,IACR;AACA,WAAO,UAAU,IAAI,MAAM;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,4BAA4B,KAAiB;AAC5C,UAAM,YAAY,KAAK,MAAM,4BAA4B,EAAE,IAAI,GAAG;AAClE,QAAI,CAAC,UAAW,QAAO;AACvB,WAAO,UAAU,4BAA4B,MAAM,aAAa;AAChE,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,IAAI,KAAQ,OAAU;AACrB,UAAM,eAAe,KAAK,MAAM,4BAA4B,EAAE,IAAI,GAAG;AACrE,QAAI,cAAc;AACjB,mBAAa,IAAI,KAAK;AAAA,IACvB,OAAO;AACN,WAAK,MAAM,OAAO,CAAC,UAAU;AAC5B,eAAO,MAAM,IAAI,KAAK,KAAK,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,CAAC;AAAA,MACjE,CAAC;AAAA,IACF;AACA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,OAAO,KAAQ,SAA0B;AACxC,UAAM,YAAY,KAAK,MAAM,4BAA4B,EAAE,IAAI,GAAG;AAClE,QAAI,CAAC,WAAW;AACf,YAAM,IAAI,MAAM,gBAAgB,GAAG,YAAY;AAAA,IAChD;AACA,UAAM,QAAQ,UAAU,4BAA4B;AACpD,WAAO,UAAU,aAAa;AAC9B,cAAU,IAAI,QAAQ,KAAK,CAAC;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,OAAO,KAAQ;AACd,UAAM,YAAY,KAAK,MAAM,4BAA4B,EAAE,IAAI,GAAG;AAClE,QAAI,CAAC,WAAW;AACf,aAAO;AAAA,IACR;AAEA,aAAS,MAAM;AACd,gBAAU,IAAI,aAAa;AAC3B,WAAK,MAAM,OAAO,CAAC,UAAU;AAC5B,eAAO,MAAM,OAAO,GAAG;AAAA,MACxB,CAAC;AAAA,IACF,CAAC;AACD,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,WAAW,MAA6B;AACvC,WAAO,SAAS,MAAM;AACrB,YAAM,UAAoB,CAAC;AAC3B,YAAM,WAAW,KAAK,MAAM,IAAI,EAAE,cAAc,CAAC,UAAU;AAC1D,mBAAW,OAAO,MAAM;AACvB,gBAAM,YAAY,MAAM,IAAI,GAAG;AAC/B,cAAI,CAAC,UAAW;AAChB,gBAAM,WAAW,UAAU,IAAI;AAC/B,iBAAO,aAAa,aAAa;AAEjC,kBAAQ,KAAK,CAAC,KAAK,QAAQ,CAAC;AAE5B,gBAAM,OAAO,GAAG;AAChB,oBAAU,IAAI,aAAa;AAAA,QAC5B;AAAA,MACD,CAAC;AAED,UAAI,QAAQ,QAAQ;AACnB,aAAK,MAAM,IAAI,QAAQ;AAAA,MACxB;AAEA,aAAO;AAAA,IACR,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,QAAQ;AACP,WAAO,SAAS,MAAM;AACrB,iBAAW,aAAa,KAAK,MAAM,4BAA4B,EAAE,OAAO,GAAG;AAC1E,kBAAU,IAAI,aAAa;AAAA,MAC5B;AACA,WAAK,MAAM,IAAI,SAAS,CAAC;AAAA,IAC1B,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,CAAC,UAAiD;AACjD,eAAW,CAAC,KAAK,SAAS,KAAK,KAAK,MAAM,IAAI,GAAG;AAChD,YAAM,QAAQ,UAAU,IAAI;AAC5B,aAAO,UAAU,aAAa;AAC9B,YAAM,CAAC,KAAK,KAAK;AAAA,IAClB;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,CAAC,OAAyC;AACzC,eAAW,OAAO,KAAK,MAAM,IAAI,EAAE,KAAK,GAAG;AAC1C,YAAM;AAAA,IACP;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,CAAC,SAA2C;AAC3C,eAAW,aAAa,KAAK,MAAM,IAAI,EAAE,OAAO,GAAG;AAClD,YAAM,QAAQ,UAAU,IAAI;AAC5B,aAAO,UAAU,aAAa;AAC9B,YAAM;AAAA,IACP;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,IAAI,OAAO;AACV,WAAO,KAAK,MAAM,IAAI,EAAE;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBA,QAAQ,YAA4D,SAAqB;AACxF,eAAW,CAAC,KAAK,KAAK,KAAK,KAAK,QAAQ,GAAG;AAC1C,iBAAW,KAAK,SAAS,OAAO,KAAK,IAAI;AAAA,IAC1C;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBA,CAAC,OAAO,QAAQ,IAAI;AACnB,WAAO,KAAK,QAAQ;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,CAAC,OAAO,WAAW,IAAI;AACxB;",
6
6
  "names": ["atoms"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/BaseRecord.ts"],
4
- "sourcesContent": ["/** @public */\nexport type RecordId<R extends UnknownRecord> = string & { __type__: R }\n\n/** @public */\nexport type IdOf<R extends UnknownRecord> = R['id']\n\n/**\n * The base record that all records must extend.\n *\n * @public\n */\nexport interface BaseRecord<TypeName extends string, Id extends RecordId<UnknownRecord>> {\n\treadonly id: Id\n\treadonly typeName: TypeName\n}\n\n/** @public */\nexport type UnknownRecord = BaseRecord<string, RecordId<UnknownRecord>>\n\nexport function isRecord(record: unknown): record is UnknownRecord {\n\treturn typeof record === 'object' && record !== null && 'id' in record && 'typeName' in record\n}\n"],
5
- "mappings": "AAmBO,SAAS,SAAS,QAA0C;AAClE,SAAO,OAAO,WAAW,YAAY,WAAW,QAAQ,QAAQ,UAAU,cAAc;AACzF;",
4
+ "sourcesContent": ["/**\n * A branded string type that represents a unique identifier for a record.\n * The brand ensures type safety by preventing mixing of IDs between different record types.\n *\n * @example\n * ```ts\n * // Define a Book record\n * interface Book extends BaseRecord<'book', RecordId<Book>> {\n * title: string\n * author: string\n * }\n *\n * const bookId: RecordId<Book> = 'book:abc123' as RecordId<Book>\n * const authorId: RecordId<Author> = 'author:xyz789' as RecordId<Author>\n *\n * // TypeScript prevents mixing different record ID types\n * // bookId = authorId // Type error!\n * ```\n *\n * @public\n */\nexport type RecordId<R extends UnknownRecord> = string & { __type__: R }\n\n/**\n * Utility type that extracts the ID type from a record type.\n * This is useful when you need to work with record IDs without having the full record type.\n *\n * @example\n * ```ts\n * interface Book extends BaseRecord<'book', RecordId<Book>> {\n * title: string\n * author: string\n * }\n *\n * // Extract the ID type from the Book record\n * type BookId = IdOf<Book> // RecordId<Book>\n *\n * function findBook(id: IdOf<Book>): Book | undefined {\n * return store.get(id)\n * }\n * ```\n *\n * @public\n */\nexport type IdOf<R extends UnknownRecord> = R['id']\n\n/**\n * The base record interface that all records in the store must extend.\n * This interface provides the fundamental structure required for all records: a unique ID and a type name.\n * The type parameters ensure type safety and prevent mixing of different record types.\n *\n * @example\n * ```ts\n * // Define a Book record that extends BaseRecord\n * interface Book extends BaseRecord<'book', RecordId<Book>> {\n * title: string\n * author: string\n * publishedYear: number\n * }\n *\n * // Define an Author record\n * interface Author extends BaseRecord<'author', RecordId<Author>> {\n * name: string\n * birthYear: number\n * }\n *\n * // Usage with RecordType\n * const Book = createRecordType<Book>('book', { scope: 'document' })\n * const book = Book.create({\n * title: '1984',\n * author: 'George Orwell',\n * publishedYear: 1949\n * })\n * // Results in: { id: 'book:abc123', typeName: 'book', title: '1984', ... }\n * ```\n *\n * @public\n */\nexport interface BaseRecord<TypeName extends string, Id extends RecordId<UnknownRecord>> {\n\treadonly id: Id\n\treadonly typeName: TypeName\n}\n\n/**\n * A generic type representing any record that extends BaseRecord.\n * This is useful for type constraints when you need to work with records of unknown types,\n * but still want to ensure they follow the BaseRecord structure.\n *\n * @example\n * ```ts\n * // Function that works with any type of record\n * function logRecord(record: UnknownRecord): void {\n * console.log(`Record ${record.id} of type ${record.typeName}`)\n * }\n *\n * // Can be used with any record type\n * const book: Book = { id: 'book:123' as RecordId<Book>, typeName: 'book', title: '1984' }\n * const author: Author = { id: 'author:456' as RecordId<Author>, typeName: 'author', name: 'Orwell' }\n *\n * logRecord(book) // \"Record book:123 of type book\"\n * logRecord(author) // \"Record author:456 of type author\"\n * ```\n *\n * @public\n */\nexport type UnknownRecord = BaseRecord<string, RecordId<UnknownRecord>>\n\n/**\n * Type guard function that checks if an unknown value is a valid record.\n * A valid record must be an object with both `id` and `typeName` properties.\n *\n * @param record - The unknown value to check\n * @returns `true` if the value is a valid UnknownRecord, `false` otherwise\n *\n * @example\n * ```ts\n * const maybeRecord: unknown = { id: 'book:123', typeName: 'book', title: '1984' }\n * const notARecord: unknown = { title: '1984', author: 'Orwell' }\n * const nullValue: unknown = null\n *\n * if (isRecord(maybeRecord)) {\n * // TypeScript now knows maybeRecord is UnknownRecord\n * console.log(maybeRecord.id) // 'book:123'\n * console.log(maybeRecord.typeName) // 'book'\n * }\n *\n * console.log(isRecord(maybeRecord)) // true\n * console.log(isRecord(notARecord)) // false (missing id and typeName)\n * console.log(isRecord(nullValue)) // false\n * ```\n *\n * @public\n */\nexport function isRecord(record: unknown): record is UnknownRecord {\n\treturn typeof record === 'object' && record !== null && 'id' in record && 'typeName' in record\n}\n"],
5
+ "mappings": "AAqIO,SAAS,SAAS,QAA0C;AAClE,SAAO,OAAO,WAAW,YAAY,WAAW,QAAQ,QAAQ,UAAU,cAAc;AACzF;",
6
6
  "names": []
7
7
  }
@@ -148,6 +148,22 @@ class ImmutableMap {
148
148
  __hash;
149
149
  // @ts-ignore
150
150
  __altered;
151
+ /**
152
+ * Creates a new ImmutableMap instance.
153
+ *
154
+ * @param value - An iterable of key-value pairs to populate the map, or null/undefined for an empty map
155
+ * @example
156
+ * ```ts
157
+ * // Create from array of pairs
158
+ * const map1 = new ImmutableMap([['a', 1], ['b', 2]])
159
+ *
160
+ * // Create empty map
161
+ * const map2 = new ImmutableMap()
162
+ *
163
+ * // Create from another map
164
+ * const map3 = new ImmutableMap(map1)
165
+ * ```
166
+ */
151
167
  constructor(value) {
152
168
  return value === void 0 || value === null ? emptyMap() : value instanceof ImmutableMap ? value : emptyMap().withMutations((map) => {
153
169
  for (const [k, v] of value) {
@@ -155,15 +171,67 @@ class ImmutableMap {
155
171
  }
156
172
  });
157
173
  }
174
+ /**
175
+ * Gets the value associated with the specified key, with a fallback value.
176
+ *
177
+ * @param k - The key to look up
178
+ * @param notSetValue - The value to return if the key is not found
179
+ * @returns The value associated with the key, or the fallback value if not found
180
+ * @example
181
+ * ```ts
182
+ * const map = new ImmutableMap([['key1', 'value1']])
183
+ * console.log(map.get('key1', 'default')) // 'value1'
184
+ * console.log(map.get('missing', 'default')) // 'default'
185
+ * ```
186
+ */
158
187
  get(k, notSetValue) {
159
188
  return this._root ? this._root.get(0, void 0, k, notSetValue) : notSetValue;
160
189
  }
190
+ /**
191
+ * Returns a new ImmutableMap with the specified key-value pair added or updated.
192
+ * If the key already exists, its value is replaced. Otherwise, a new entry is created.
193
+ *
194
+ * @param k - The key to set
195
+ * @param v - The value to associate with the key
196
+ * @returns A new ImmutableMap with the key-value pair set
197
+ * @example
198
+ * ```ts
199
+ * const map = new ImmutableMap([['a', 1]])
200
+ * const updated = map.set('b', 2) // New map with both 'a' and 'b'
201
+ * const replaced = map.set('a', 10) // New map with 'a' updated to 10
202
+ * ```
203
+ */
161
204
  set(k, v) {
162
205
  return updateMap(this, k, v);
163
206
  }
207
+ /**
208
+ * Returns a new ImmutableMap with the specified key removed.
209
+ * If the key doesn't exist, returns the same map instance.
210
+ *
211
+ * @param k - The key to remove
212
+ * @returns A new ImmutableMap with the key removed, or the same instance if key not found
213
+ * @example
214
+ * ```ts
215
+ * const map = new ImmutableMap([['a', 1], ['b', 2]])
216
+ * const smaller = map.delete('a') // New map with only 'b'
217
+ * const same = map.delete('missing') // Returns original map
218
+ * ```
219
+ */
164
220
  delete(k) {
165
221
  return updateMap(this, k, NOT_SET);
166
222
  }
223
+ /**
224
+ * Returns a new ImmutableMap with all specified keys removed.
225
+ * This is more efficient than calling delete() multiple times.
226
+ *
227
+ * @param keys - An iterable of keys to remove
228
+ * @returns A new ImmutableMap with all specified keys removed
229
+ * @example
230
+ * ```ts
231
+ * const map = new ImmutableMap([['a', 1], ['b', 2], ['c', 3]])
232
+ * const smaller = map.deleteAll(['a', 'c']) // New map with only 'b'
233
+ * ```
234
+ */
167
235
  deleteAll(keys) {
168
236
  return this.withMutations((map) => {
169
237
  for (const key of keys) {
@@ -185,26 +253,99 @@ class ImmutableMap {
185
253
  }
186
254
  return makeMap(this.size, this._root, ownerID, this.__hash);
187
255
  }
256
+ /**
257
+ * Applies multiple mutations efficiently by creating a mutable copy,
258
+ * applying all changes, then returning an immutable result.
259
+ * This is more efficient than chaining multiple set/delete operations.
260
+ *
261
+ * @param fn - Function that receives a mutable copy and applies changes
262
+ * @returns A new ImmutableMap with all mutations applied, or the same instance if no changes
263
+ * @example
264
+ * ```ts
265
+ * const map = new ImmutableMap([['a', 1]])
266
+ * const updated = map.withMutations(mutable => {
267
+ * mutable.set('b', 2)
268
+ * mutable.set('c', 3)
269
+ * mutable.delete('a')
270
+ * }) // Efficiently applies all changes at once
271
+ * ```
272
+ */
188
273
  withMutations(fn) {
189
274
  const mutable = this.asMutable();
190
275
  fn(mutable);
191
276
  return mutable.wasAltered() ? mutable.__ensureOwner(this.__ownerID) : this;
192
277
  }
278
+ /**
279
+ * Checks if this map instance has been altered during a mutation operation.
280
+ * This is used internally to optimize mutations.
281
+ *
282
+ * @returns True if the map was altered, false otherwise
283
+ * @internal
284
+ */
193
285
  wasAltered() {
194
286
  return this.__altered;
195
287
  }
288
+ /**
289
+ * Returns a mutable copy of this map that can be efficiently modified.
290
+ * Multiple changes to the mutable copy are batched together.
291
+ *
292
+ * @returns A mutable copy of this map
293
+ * @internal
294
+ */
196
295
  asMutable() {
197
296
  return this.__ownerID ? this : this.__ensureOwner(new OwnerID());
198
297
  }
298
+ /**
299
+ * Makes the map iterable, yielding key-value pairs.
300
+ *
301
+ * @returns An iterator over [key, value] pairs
302
+ * @example
303
+ * ```ts
304
+ * const map = new ImmutableMap([['a', 1], ['b', 2]])
305
+ * for (const [key, value] of map) {
306
+ * console.log(key, value) // 'a' 1, then 'b' 2
307
+ * }
308
+ * ```
309
+ */
199
310
  [Symbol.iterator]() {
200
311
  return this.entries()[Symbol.iterator]();
201
312
  }
313
+ /**
314
+ * Returns an iterable of key-value pairs.
315
+ *
316
+ * @returns An iterable over [key, value] pairs
317
+ * @example
318
+ * ```ts
319
+ * const map = new ImmutableMap([['a', 1], ['b', 2]])
320
+ * const entries = Array.from(map.entries()) // [['a', 1], ['b', 2]]
321
+ * ```
322
+ */
202
323
  entries() {
203
324
  return new MapIterator(this, ITERATE_ENTRIES, false);
204
325
  }
326
+ /**
327
+ * Returns an iterable of keys.
328
+ *
329
+ * @returns An iterable over keys
330
+ * @example
331
+ * ```ts
332
+ * const map = new ImmutableMap([['a', 1], ['b', 2]])
333
+ * const keys = Array.from(map.keys()) // ['a', 'b']
334
+ * ```
335
+ */
205
336
  keys() {
206
337
  return new MapIterator(this, ITERATE_KEYS, false);
207
338
  }
339
+ /**
340
+ * Returns an iterable of values.
341
+ *
342
+ * @returns An iterable over values
343
+ * @example
344
+ * ```ts
345
+ * const map = new ImmutableMap([['a', 1], ['b', 2]])
346
+ * const values = Array.from(map.values()) // [1, 2]
347
+ * ```
348
+ */
208
349
  values() {
209
350
  return new MapIterator(this, ITERATE_VALUES, false);
210
351
  }