@tldraw/store 4.1.0-next.b6dfe9bccde9 → 4.1.0-next.b73a0d46b63f
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.
- package/dist-cjs/index.d.ts +1884 -153
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/lib/AtomMap.js +241 -1
- package/dist-cjs/lib/AtomMap.js.map +2 -2
- package/dist-cjs/lib/BaseRecord.js.map +2 -2
- package/dist-cjs/lib/ImmutableMap.js +141 -0
- package/dist-cjs/lib/ImmutableMap.js.map +2 -2
- package/dist-cjs/lib/IncrementalSetConstructor.js +45 -5
- package/dist-cjs/lib/IncrementalSetConstructor.js.map +2 -2
- package/dist-cjs/lib/RecordType.js +116 -21
- package/dist-cjs/lib/RecordType.js.map +2 -2
- package/dist-cjs/lib/RecordsDiff.js.map +2 -2
- package/dist-cjs/lib/Store.js +233 -39
- package/dist-cjs/lib/Store.js.map +2 -2
- package/dist-cjs/lib/StoreQueries.js +135 -22
- package/dist-cjs/lib/StoreQueries.js.map +2 -2
- package/dist-cjs/lib/StoreSchema.js +207 -2
- package/dist-cjs/lib/StoreSchema.js.map +2 -2
- package/dist-cjs/lib/StoreSideEffects.js +102 -10
- package/dist-cjs/lib/StoreSideEffects.js.map +2 -2
- package/dist-cjs/lib/executeQuery.js.map +2 -2
- package/dist-cjs/lib/migrate.js.map +2 -2
- package/dist-cjs/lib/setUtils.js.map +2 -2
- package/dist-esm/index.d.mts +1884 -153
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/AtomMap.mjs +241 -1
- package/dist-esm/lib/AtomMap.mjs.map +2 -2
- package/dist-esm/lib/BaseRecord.mjs.map +2 -2
- package/dist-esm/lib/ImmutableMap.mjs +141 -0
- package/dist-esm/lib/ImmutableMap.mjs.map +2 -2
- package/dist-esm/lib/IncrementalSetConstructor.mjs +45 -5
- package/dist-esm/lib/IncrementalSetConstructor.mjs.map +2 -2
- package/dist-esm/lib/RecordType.mjs +116 -21
- package/dist-esm/lib/RecordType.mjs.map +2 -2
- package/dist-esm/lib/RecordsDiff.mjs.map +2 -2
- package/dist-esm/lib/Store.mjs +233 -39
- package/dist-esm/lib/Store.mjs.map +2 -2
- package/dist-esm/lib/StoreQueries.mjs +135 -22
- package/dist-esm/lib/StoreQueries.mjs.map +2 -2
- package/dist-esm/lib/StoreSchema.mjs +207 -2
- package/dist-esm/lib/StoreSchema.mjs.map +2 -2
- package/dist-esm/lib/StoreSideEffects.mjs +102 -10
- package/dist-esm/lib/StoreSideEffects.mjs.map +2 -2
- package/dist-esm/lib/executeQuery.mjs.map +2 -2
- package/dist-esm/lib/migrate.mjs.map +2 -2
- package/dist-esm/lib/setUtils.mjs.map +2 -2
- package/package.json +3 -3
- package/src/lib/AtomMap.ts +241 -1
- package/src/lib/BaseRecord.test.ts +44 -0
- package/src/lib/BaseRecord.ts +118 -4
- package/src/lib/ImmutableMap.test.ts +103 -0
- package/src/lib/ImmutableMap.ts +212 -0
- package/src/lib/IncrementalSetConstructor.test.ts +111 -0
- package/src/lib/IncrementalSetConstructor.ts +63 -6
- package/src/lib/RecordType.ts +149 -25
- package/src/lib/RecordsDiff.test.ts +144 -0
- package/src/lib/RecordsDiff.ts +145 -10
- package/src/lib/Store.test.ts +827 -0
- package/src/lib/Store.ts +533 -67
- package/src/lib/StoreQueries.test.ts +627 -0
- package/src/lib/StoreQueries.ts +194 -27
- package/src/lib/StoreSchema.test.ts +226 -0
- package/src/lib/StoreSchema.ts +386 -8
- package/src/lib/StoreSideEffects.test.ts +239 -19
- package/src/lib/StoreSideEffects.ts +266 -19
- package/src/lib/devFreeze.test.ts +137 -0
- package/src/lib/executeQuery.test.ts +481 -0
- package/src/lib/executeQuery.ts +80 -2
- package/src/lib/migrate.test.ts +400 -0
- package/src/lib/migrate.ts +187 -14
- package/src/lib/setUtils.test.ts +105 -0
- 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-next.
|
|
57
|
+
"4.1.0-next.b73a0d46b63f",
|
|
58
58
|
"cjs"
|
|
59
59
|
);
|
|
60
60
|
//# sourceMappingURL=index.js.map
|
package/dist-cjs/lib/AtomMap.js
CHANGED
|
@@ -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
|
-
/**
|
|
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": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAoD;AACpD,mBAAuB;AACvB,0BAAuC;AAMhC,MAAM,QAAmC;AAAA,
|
|
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": ["
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
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
|
}
|