@tldraw/store 4.1.0-canary.bace23a29058 → 4.1.0-canary.bf8b596d2b31

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
package/dist-cjs/index.js CHANGED
@@ -54,7 +54,7 @@ var import_StoreSchema = require("./lib/StoreSchema");
54
54
  var import_StoreSideEffects = require("./lib/StoreSideEffects");
55
55
  (0, import_utils.registerTldrawLibraryVersion)(
56
56
  "@tldraw/store",
57
- "4.1.0-canary.bace23a29058",
57
+ "4.1.0-canary.bf8b596d2b31",
58
58
  "cjs"
59
59
  );
60
60
  //# sourceMappingURL=index.js.map
@@ -25,6 +25,21 @@ var import_state = require("@tldraw/state");
25
25
  var import_utils = require("@tldraw/utils");
26
26
  var import_ImmutableMap = require("./ImmutableMap");
27
27
  class AtomMap {
28
+ /**
29
+ * Creates a new AtomMap instance.
30
+ *
31
+ * name - A unique name for this map, used for atom identification
32
+ * entries - Optional initial entries to populate the map with
33
+ * @example
34
+ * ```ts
35
+ * // Create an empty map
36
+ * const map = new AtomMap('userMap')
37
+ *
38
+ * // Create a map with initial data
39
+ * const initialData: [string, number][] = [['a', 1], ['b', 2]]
40
+ * const mapWithData = new AtomMap('numbersMap', initialData)
41
+ * ```
42
+ */
28
43
  constructor(name, entries) {
29
44
  this.name = name;
30
45
  let atoms = (0, import_ImmutableMap.emptyMap)();
@@ -38,7 +53,13 @@ class AtomMap {
38
53
  this.atoms = (0, import_state.atom)(`${name}:atoms`, atoms);
39
54
  }
40
55
  atoms;
41
- /** @internal */
56
+ /**
57
+ * Retrieves the underlying atom for a given key.
58
+ *
59
+ * @param key - The key to retrieve the atom for
60
+ * @returns The atom containing the value, or undefined if the key doesn't exist
61
+ * @internal
62
+ */
42
63
  getAtom(key) {
43
64
  const valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key);
44
65
  if (!valueAtom) {
@@ -47,11 +68,38 @@ class AtomMap {
47
68
  }
48
69
  return valueAtom;
49
70
  }
71
+ /**
72
+ * Gets the value associated with a key. Returns undefined if the key doesn't exist.
73
+ * This method is reactive and will cause reactive contexts to update when the value changes.
74
+ *
75
+ * @param key - The key to retrieve the value for
76
+ * @returns The value associated with the key, or undefined if not found
77
+ * @example
78
+ * ```ts
79
+ * const map = new AtomMap('myMap')
80
+ * map.set('name', 'Alice')
81
+ * console.log(map.get('name')) // 'Alice'
82
+ * console.log(map.get('missing')) // undefined
83
+ * ```
84
+ */
50
85
  get(key) {
51
86
  const value = this.getAtom(key)?.get();
52
87
  (0, import_utils.assert)(value !== import_state.UNINITIALIZED);
53
88
  return value;
54
89
  }
90
+ /**
91
+ * Gets the value associated with a key without creating reactive dependencies.
92
+ * This method will not cause reactive contexts to update when the value changes.
93
+ *
94
+ * @param key - The key to retrieve the value for
95
+ * @returns The value associated with the key, or undefined if not found
96
+ * @example
97
+ * ```ts
98
+ * const map = new AtomMap('myMap')
99
+ * map.set('count', 42)
100
+ * const value = map.__unsafe__getWithoutCapture('count') // No reactive subscription
101
+ * ```
102
+ */
55
103
  __unsafe__getWithoutCapture(key) {
56
104
  const valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key);
57
105
  if (!valueAtom) return void 0;
@@ -59,6 +107,20 @@ class AtomMap {
59
107
  (0, import_utils.assert)(value !== import_state.UNINITIALIZED);
60
108
  return value;
61
109
  }
110
+ /**
111
+ * Checks whether a key exists in the map.
112
+ * This method is reactive and will cause reactive contexts to update when keys are added or removed.
113
+ *
114
+ * @param key - The key to check for
115
+ * @returns True if the key exists in the map, false otherwise
116
+ * @example
117
+ * ```ts
118
+ * const map = new AtomMap('myMap')
119
+ * console.log(map.has('name')) // false
120
+ * map.set('name', 'Alice')
121
+ * console.log(map.has('name')) // true
122
+ * ```
123
+ */
62
124
  has(key) {
63
125
  const valueAtom = this.getAtom(key);
64
126
  if (!valueAtom) {
@@ -66,12 +128,38 @@ class AtomMap {
66
128
  }
67
129
  return valueAtom.get() !== import_state.UNINITIALIZED;
68
130
  }
131
+ /**
132
+ * Checks whether a key exists in the map without creating reactive dependencies.
133
+ * This method will not cause reactive contexts to update when keys are added or removed.
134
+ *
135
+ * @param key - The key to check for
136
+ * @returns True if the key exists in the map, false otherwise
137
+ * @example
138
+ * ```ts
139
+ * const map = new AtomMap('myMap')
140
+ * map.set('active', true)
141
+ * const exists = map.__unsafe__hasWithoutCapture('active') // No reactive subscription
142
+ * ```
143
+ */
69
144
  __unsafe__hasWithoutCapture(key) {
70
145
  const valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key);
71
146
  if (!valueAtom) return false;
72
147
  (0, import_utils.assert)(valueAtom.__unsafe__getWithoutCapture() !== import_state.UNINITIALIZED);
73
148
  return true;
74
149
  }
150
+ /**
151
+ * Sets a value for the given key. If the key already exists, its value is updated.
152
+ * If the key doesn't exist, a new entry is created.
153
+ *
154
+ * @param key - The key to set the value for
155
+ * @param value - The value to associate with the key
156
+ * @returns This AtomMap instance for method chaining
157
+ * @example
158
+ * ```ts
159
+ * const map = new AtomMap('myMap')
160
+ * map.set('name', 'Alice').set('age', 30)
161
+ * ```
162
+ */
75
163
  set(key, value) {
76
164
  const existingAtom = this.atoms.__unsafe__getWithoutCapture().get(key);
77
165
  if (existingAtom) {
@@ -83,6 +171,19 @@ class AtomMap {
83
171
  }
84
172
  return this;
85
173
  }
174
+ /**
175
+ * Updates an existing value using an updater function.
176
+ *
177
+ * @param key - The key of the value to update
178
+ * @param updater - A function that receives the current value and returns the new value
179
+ * @throws Error if the key doesn't exist in the map
180
+ * @example
181
+ * ```ts
182
+ * const map = new AtomMap('myMap')
183
+ * map.set('count', 5)
184
+ * map.update('count', count => count + 1) // count is now 6
185
+ * ```
186
+ */
86
187
  update(key, updater) {
87
188
  const valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key);
88
189
  if (!valueAtom) {
@@ -92,6 +193,19 @@ class AtomMap {
92
193
  (0, import_utils.assert)(value !== import_state.UNINITIALIZED);
93
194
  valueAtom.set(updater(value));
94
195
  }
196
+ /**
197
+ * Removes a key-value pair from the map.
198
+ *
199
+ * @param key - The key to remove
200
+ * @returns True if the key existed and was removed, false if it didn't exist
201
+ * @example
202
+ * ```ts
203
+ * const map = new AtomMap('myMap')
204
+ * map.set('temp', 'value')
205
+ * console.log(map.delete('temp')) // true
206
+ * console.log(map.delete('missing')) // false
207
+ * ```
208
+ */
95
209
  delete(key) {
96
210
  const valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key);
97
211
  if (!valueAtom) {
@@ -105,6 +219,19 @@ class AtomMap {
105
219
  });
106
220
  return true;
107
221
  }
222
+ /**
223
+ * Removes multiple key-value pairs from the map in a single transaction.
224
+ *
225
+ * @param keys - An iterable of keys to remove
226
+ * @returns An array of [key, value] pairs that were actually deleted
227
+ * @example
228
+ * ```ts
229
+ * const map = new AtomMap('myMap')
230
+ * map.set('a', 1).set('b', 2).set('c', 3)
231
+ * const deleted = map.deleteMany(['a', 'c', 'missing'])
232
+ * console.log(deleted) // [['a', 1], ['c', 3]]
233
+ * ```
234
+ */
108
235
  deleteMany(keys) {
109
236
  return (0, import_state.transact)(() => {
110
237
  const deleted = [];
@@ -125,6 +252,17 @@ class AtomMap {
125
252
  return deleted;
126
253
  });
127
254
  }
255
+ /**
256
+ * Removes all key-value pairs from the map.
257
+ *
258
+ * @example
259
+ * ```ts
260
+ * const map = new AtomMap('myMap')
261
+ * map.set('a', 1).set('b', 2)
262
+ * map.clear()
263
+ * console.log(map.size) // 0
264
+ * ```
265
+ */
128
266
  clear() {
129
267
  return (0, import_state.transact)(() => {
130
268
  for (const valueAtom of this.atoms.__unsafe__getWithoutCapture().values()) {
@@ -133,6 +271,20 @@ class AtomMap {
133
271
  this.atoms.set((0, import_ImmutableMap.emptyMap)());
134
272
  });
135
273
  }
274
+ /**
275
+ * Returns an iterator that yields [key, value] pairs for each entry in the map.
276
+ * This method is reactive and will cause reactive contexts to update when entries change.
277
+ *
278
+ * @returns A generator that yields [key, value] tuples
279
+ * @example
280
+ * ```ts
281
+ * const map = new AtomMap('myMap')
282
+ * map.set('a', 1).set('b', 2)
283
+ * for (const [key, value] of map.entries()) {
284
+ * console.log(`${key}: ${value}`)
285
+ * }
286
+ * ```
287
+ */
136
288
  *entries() {
137
289
  for (const [key, valueAtom] of this.atoms.get()) {
138
290
  const value = valueAtom.get();
@@ -140,11 +292,39 @@ class AtomMap {
140
292
  yield [key, value];
141
293
  }
142
294
  }
295
+ /**
296
+ * Returns an iterator that yields all keys in the map.
297
+ * This method is reactive and will cause reactive contexts to update when keys change.
298
+ *
299
+ * @returns A generator that yields keys
300
+ * @example
301
+ * ```ts
302
+ * const map = new AtomMap('myMap')
303
+ * map.set('name', 'Alice').set('age', 30)
304
+ * for (const key of map.keys()) {
305
+ * console.log(key) // 'name', 'age'
306
+ * }
307
+ * ```
308
+ */
143
309
  *keys() {
144
310
  for (const key of this.atoms.get().keys()) {
145
311
  yield key;
146
312
  }
147
313
  }
314
+ /**
315
+ * Returns an iterator that yields all values in the map.
316
+ * This method is reactive and will cause reactive contexts to update when values change.
317
+ *
318
+ * @returns A generator that yields values
319
+ * @example
320
+ * ```ts
321
+ * const map = new AtomMap('myMap')
322
+ * map.set('name', 'Alice').set('age', 30)
323
+ * for (const value of map.values()) {
324
+ * console.log(value) // 'Alice', 30
325
+ * }
326
+ * ```
327
+ */
148
328
  *values() {
149
329
  for (const valueAtom of this.atoms.get().values()) {
150
330
  const value = valueAtom.get();
@@ -152,18 +332,78 @@ class AtomMap {
152
332
  yield value;
153
333
  }
154
334
  }
335
+ /**
336
+ * The number of key-value pairs in the map.
337
+ * This property is reactive and will cause reactive contexts to update when the size changes.
338
+ *
339
+ * @returns The number of entries in the map
340
+ * @example
341
+ * ```ts
342
+ * const map = new AtomMap('myMap')
343
+ * console.log(map.size) // 0
344
+ * map.set('a', 1)
345
+ * console.log(map.size) // 1
346
+ * ```
347
+ */
155
348
  // eslint-disable-next-line no-restricted-syntax
156
349
  get size() {
157
350
  return this.atoms.get().size;
158
351
  }
352
+ /**
353
+ * Executes a provided function once for each key-value pair in the map.
354
+ * This method is reactive and will cause reactive contexts to update when entries change.
355
+ *
356
+ * @param callbackfn - Function to execute for each entry
357
+ * - value - The value of the current entry
358
+ * - key - The key of the current entry
359
+ * - map - The AtomMap being traversed
360
+ * @param thisArg - Value to use as `this` when executing the callback
361
+ * @example
362
+ * ```ts
363
+ * const map = new AtomMap('myMap')
364
+ * map.set('a', 1).set('b', 2)
365
+ * map.forEach((value, key) => {
366
+ * console.log(`${key} = ${value}`)
367
+ * })
368
+ * ```
369
+ */
159
370
  forEach(callbackfn, thisArg) {
160
371
  for (const [key, value] of this.entries()) {
161
372
  callbackfn.call(thisArg, value, key, this);
162
373
  }
163
374
  }
375
+ /**
376
+ * Returns the default iterator for the map, which is the same as entries().
377
+ * This allows the map to be used in for...of loops and other iterable contexts.
378
+ *
379
+ * @returns The same iterator as entries()
380
+ * @example
381
+ * ```ts
382
+ * const map = new AtomMap('myMap')
383
+ * map.set('a', 1).set('b', 2)
384
+ *
385
+ * // These are equivalent:
386
+ * for (const [key, value] of map) {
387
+ * console.log(`${key}: ${value}`)
388
+ * }
389
+ *
390
+ * for (const [key, value] of map.entries()) {
391
+ * console.log(`${key}: ${value}`)
392
+ * }
393
+ * ```
394
+ */
164
395
  [Symbol.iterator]() {
165
396
  return this.entries();
166
397
  }
398
+ /**
399
+ * The string tag used by Object.prototype.toString for this class.
400
+ *
401
+ * @example
402
+ * ```ts
403
+ * const map = new AtomMap('myMap')
404
+ * console.log(Object.prototype.toString.call(map)) // '[object AtomMap]'
405
+ * ```
406
+ */
167
407
  [Symbol.toStringTag] = "AtomMap";
168
408
  }
169
409
  //# sourceMappingURL=AtomMap.js.map
@@ -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": "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",
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": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;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": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAqIO,SAAS,SAAS,QAA0C;AAClE,SAAO,OAAO,WAAW,YAAY,WAAW,QAAQ,QAAQ,UAAU,cAAc;AACzF;",
6
6
  "names": []
7
7
  }
@@ -173,6 +173,22 @@ class ImmutableMap {
173
173
  __hash;
174
174
  // @ts-ignore
175
175
  __altered;
176
+ /**
177
+ * Creates a new ImmutableMap instance.
178
+ *
179
+ * @param value - An iterable of key-value pairs to populate the map, or null/undefined for an empty map
180
+ * @example
181
+ * ```ts
182
+ * // Create from array of pairs
183
+ * const map1 = new ImmutableMap([['a', 1], ['b', 2]])
184
+ *
185
+ * // Create empty map
186
+ * const map2 = new ImmutableMap()
187
+ *
188
+ * // Create from another map
189
+ * const map3 = new ImmutableMap(map1)
190
+ * ```
191
+ */
176
192
  constructor(value) {
177
193
  return value === void 0 || value === null ? emptyMap() : value instanceof ImmutableMap ? value : emptyMap().withMutations((map) => {
178
194
  for (const [k, v] of value) {
@@ -180,15 +196,67 @@ class ImmutableMap {
180
196
  }
181
197
  });
182
198
  }
199
+ /**
200
+ * Gets the value associated with the specified key, with a fallback value.
201
+ *
202
+ * @param k - The key to look up
203
+ * @param notSetValue - The value to return if the key is not found
204
+ * @returns The value associated with the key, or the fallback value if not found
205
+ * @example
206
+ * ```ts
207
+ * const map = new ImmutableMap([['key1', 'value1']])
208
+ * console.log(map.get('key1', 'default')) // 'value1'
209
+ * console.log(map.get('missing', 'default')) // 'default'
210
+ * ```
211
+ */
183
212
  get(k, notSetValue) {
184
213
  return this._root ? this._root.get(0, void 0, k, notSetValue) : notSetValue;
185
214
  }
215
+ /**
216
+ * Returns a new ImmutableMap with the specified key-value pair added or updated.
217
+ * If the key already exists, its value is replaced. Otherwise, a new entry is created.
218
+ *
219
+ * @param k - The key to set
220
+ * @param v - The value to associate with the key
221
+ * @returns A new ImmutableMap with the key-value pair set
222
+ * @example
223
+ * ```ts
224
+ * const map = new ImmutableMap([['a', 1]])
225
+ * const updated = map.set('b', 2) // New map with both 'a' and 'b'
226
+ * const replaced = map.set('a', 10) // New map with 'a' updated to 10
227
+ * ```
228
+ */
186
229
  set(k, v) {
187
230
  return updateMap(this, k, v);
188
231
  }
232
+ /**
233
+ * Returns a new ImmutableMap with the specified key removed.
234
+ * If the key doesn't exist, returns the same map instance.
235
+ *
236
+ * @param k - The key to remove
237
+ * @returns A new ImmutableMap with the key removed, or the same instance if key not found
238
+ * @example
239
+ * ```ts
240
+ * const map = new ImmutableMap([['a', 1], ['b', 2]])
241
+ * const smaller = map.delete('a') // New map with only 'b'
242
+ * const same = map.delete('missing') // Returns original map
243
+ * ```
244
+ */
189
245
  delete(k) {
190
246
  return updateMap(this, k, NOT_SET);
191
247
  }
248
+ /**
249
+ * Returns a new ImmutableMap with all specified keys removed.
250
+ * This is more efficient than calling delete() multiple times.
251
+ *
252
+ * @param keys - An iterable of keys to remove
253
+ * @returns A new ImmutableMap with all specified keys removed
254
+ * @example
255
+ * ```ts
256
+ * const map = new ImmutableMap([['a', 1], ['b', 2], ['c', 3]])
257
+ * const smaller = map.deleteAll(['a', 'c']) // New map with only 'b'
258
+ * ```
259
+ */
192
260
  deleteAll(keys) {
193
261
  return this.withMutations((map) => {
194
262
  for (const key of keys) {
@@ -210,26 +278,99 @@ class ImmutableMap {
210
278
  }
211
279
  return makeMap(this.size, this._root, ownerID, this.__hash);
212
280
  }
281
+ /**
282
+ * Applies multiple mutations efficiently by creating a mutable copy,
283
+ * applying all changes, then returning an immutable result.
284
+ * This is more efficient than chaining multiple set/delete operations.
285
+ *
286
+ * @param fn - Function that receives a mutable copy and applies changes
287
+ * @returns A new ImmutableMap with all mutations applied, or the same instance if no changes
288
+ * @example
289
+ * ```ts
290
+ * const map = new ImmutableMap([['a', 1]])
291
+ * const updated = map.withMutations(mutable => {
292
+ * mutable.set('b', 2)
293
+ * mutable.set('c', 3)
294
+ * mutable.delete('a')
295
+ * }) // Efficiently applies all changes at once
296
+ * ```
297
+ */
213
298
  withMutations(fn) {
214
299
  const mutable = this.asMutable();
215
300
  fn(mutable);
216
301
  return mutable.wasAltered() ? mutable.__ensureOwner(this.__ownerID) : this;
217
302
  }
303
+ /**
304
+ * Checks if this map instance has been altered during a mutation operation.
305
+ * This is used internally to optimize mutations.
306
+ *
307
+ * @returns True if the map was altered, false otherwise
308
+ * @internal
309
+ */
218
310
  wasAltered() {
219
311
  return this.__altered;
220
312
  }
313
+ /**
314
+ * Returns a mutable copy of this map that can be efficiently modified.
315
+ * Multiple changes to the mutable copy are batched together.
316
+ *
317
+ * @returns A mutable copy of this map
318
+ * @internal
319
+ */
221
320
  asMutable() {
222
321
  return this.__ownerID ? this : this.__ensureOwner(new OwnerID());
223
322
  }
323
+ /**
324
+ * Makes the map iterable, yielding key-value pairs.
325
+ *
326
+ * @returns An iterator over [key, value] pairs
327
+ * @example
328
+ * ```ts
329
+ * const map = new ImmutableMap([['a', 1], ['b', 2]])
330
+ * for (const [key, value] of map) {
331
+ * console.log(key, value) // 'a' 1, then 'b' 2
332
+ * }
333
+ * ```
334
+ */
224
335
  [Symbol.iterator]() {
225
336
  return this.entries()[Symbol.iterator]();
226
337
  }
338
+ /**
339
+ * Returns an iterable of key-value pairs.
340
+ *
341
+ * @returns An iterable over [key, value] pairs
342
+ * @example
343
+ * ```ts
344
+ * const map = new ImmutableMap([['a', 1], ['b', 2]])
345
+ * const entries = Array.from(map.entries()) // [['a', 1], ['b', 2]]
346
+ * ```
347
+ */
227
348
  entries() {
228
349
  return new MapIterator(this, ITERATE_ENTRIES, false);
229
350
  }
351
+ /**
352
+ * Returns an iterable of keys.
353
+ *
354
+ * @returns An iterable over keys
355
+ * @example
356
+ * ```ts
357
+ * const map = new ImmutableMap([['a', 1], ['b', 2]])
358
+ * const keys = Array.from(map.keys()) // ['a', 'b']
359
+ * ```
360
+ */
230
361
  keys() {
231
362
  return new MapIterator(this, ITERATE_KEYS, false);
232
363
  }
364
+ /**
365
+ * Returns an iterable of values.
366
+ *
367
+ * @returns An iterable over values
368
+ * @example
369
+ * ```ts
370
+ * const map = new ImmutableMap([['a', 1], ['b', 2]])
371
+ * const values = Array.from(map.values()) // [1, 2]
372
+ * ```
373
+ */
233
374
  values() {
234
375
  return new MapIterator(this, ITERATE_VALUES, false);
235
376
  }