@loro-extended/change 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1491 @@
1
+ // src/change.ts
2
+ import { LoroDoc } from "loro-crdt";
3
+
4
+ // src/draft-nodes/base.ts
5
+ var DraftNode = class {
6
+ constructor(_params) {
7
+ this._params = _params;
8
+ }
9
+ _cachedContainer;
10
+ get shape() {
11
+ return this._params.shape;
12
+ }
13
+ get emptyState() {
14
+ return this._params.emptyState;
15
+ }
16
+ get container() {
17
+ if (!this._cachedContainer) {
18
+ const container = this._params.getContainer();
19
+ this._cachedContainer = container;
20
+ return container;
21
+ }
22
+ return this._cachedContainer;
23
+ }
24
+ };
25
+
26
+ // src/draft-nodes/counter.ts
27
+ var CounterDraftNode = class extends DraftNode {
28
+ absorbPlainValues() {
29
+ }
30
+ increment(value) {
31
+ this.container.increment(value);
32
+ }
33
+ decrement(value) {
34
+ this.container.decrement(value);
35
+ }
36
+ get value() {
37
+ return this.container.value;
38
+ }
39
+ };
40
+
41
+ // src/conversion.ts
42
+ import {
43
+ LoroCounter,
44
+ LoroList,
45
+ LoroMap,
46
+ LoroMovableList,
47
+ LoroText
48
+ } from "loro-crdt";
49
+
50
+ // src/utils/type-guards.ts
51
+ import { isContainer, isContainerId } from "loro-crdt";
52
+ function isContainerShape(schema) {
53
+ return schema._type && schema._type !== "value";
54
+ }
55
+ function isValueShape(schema) {
56
+ return schema._type === "value" && [
57
+ "string",
58
+ "number",
59
+ "boolean",
60
+ "null",
61
+ "undefined",
62
+ "uint8array",
63
+ "object",
64
+ "record",
65
+ "array"
66
+ ].includes(schema.valueType);
67
+ }
68
+ function isObjectValue(value) {
69
+ return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Uint8Array);
70
+ }
71
+
72
+ // src/conversion.ts
73
+ function convertTextInput(value) {
74
+ const text = new LoroText();
75
+ if (value.length > 0) {
76
+ text.insert(0, value);
77
+ }
78
+ return text;
79
+ }
80
+ function convertCounterInput(value) {
81
+ const counter = new LoroCounter();
82
+ counter.increment(value);
83
+ return counter;
84
+ }
85
+ function convertListInput(value, shape) {
86
+ if (!isContainerShape(shape)) {
87
+ return value;
88
+ }
89
+ const list = new LoroList();
90
+ for (const item of value) {
91
+ const convertedItem = convertInputToNode(item, shape.shape);
92
+ if (isContainer(convertedItem)) {
93
+ list.pushContainer(convertedItem);
94
+ } else {
95
+ list.push(convertedItem);
96
+ }
97
+ }
98
+ return list;
99
+ }
100
+ function convertMovableListInput(value, shape) {
101
+ if (!isContainerShape(shape)) {
102
+ return value;
103
+ }
104
+ const list = new LoroMovableList();
105
+ for (const item of value) {
106
+ const convertedItem = convertInputToNode(item, shape.shape);
107
+ if (isContainer(convertedItem)) {
108
+ list.pushContainer(convertedItem);
109
+ } else {
110
+ list.push(convertedItem);
111
+ }
112
+ }
113
+ return list;
114
+ }
115
+ function convertMapInput(value, shape) {
116
+ if (!isContainerShape(shape)) {
117
+ return value;
118
+ }
119
+ const map = new LoroMap();
120
+ for (const [k, v] of Object.entries(value)) {
121
+ const nestedSchema = shape.shapes[k];
122
+ if (nestedSchema) {
123
+ const convertedValue = convertInputToNode(v, nestedSchema);
124
+ if (isContainer(convertedValue)) {
125
+ map.setContainer(k, convertedValue);
126
+ } else {
127
+ map.set(k, convertedValue);
128
+ }
129
+ } else {
130
+ map.set(k, value);
131
+ }
132
+ }
133
+ return map;
134
+ }
135
+ function convertRecordInput(value, shape) {
136
+ if (!isContainerShape(shape)) {
137
+ return value;
138
+ }
139
+ const map = new LoroMap();
140
+ for (const [k, v] of Object.entries(value)) {
141
+ const convertedValue = convertInputToNode(v, shape.shape);
142
+ if (isContainer(convertedValue)) {
143
+ map.setContainer(k, convertedValue);
144
+ } else {
145
+ map.set(k, convertedValue);
146
+ }
147
+ }
148
+ return map;
149
+ }
150
+ function convertInputToNode(value, shape) {
151
+ switch (shape._type) {
152
+ case "text": {
153
+ if (typeof value !== "string") {
154
+ throw new Error("string expected");
155
+ }
156
+ return convertTextInput(value);
157
+ }
158
+ case "counter": {
159
+ if (typeof value !== "number") {
160
+ throw new Error("number expected");
161
+ }
162
+ return convertCounterInput(value);
163
+ }
164
+ case "list": {
165
+ if (!Array.isArray(value)) {
166
+ throw new Error("array expected");
167
+ }
168
+ return convertListInput(value, shape);
169
+ }
170
+ case "movableList": {
171
+ if (!Array.isArray(value)) {
172
+ throw new Error("array expected");
173
+ }
174
+ return convertMovableListInput(value, shape);
175
+ }
176
+ case "map": {
177
+ if (!isObjectValue(value)) {
178
+ throw new Error("object expected");
179
+ }
180
+ return convertMapInput(value, shape);
181
+ }
182
+ case "record": {
183
+ if (!isObjectValue(value)) {
184
+ throw new Error("object expected");
185
+ }
186
+ return convertRecordInput(value, shape);
187
+ }
188
+ case "value": {
189
+ if (!isValueShape(shape)) {
190
+ throw new Error("value expected");
191
+ }
192
+ return value;
193
+ }
194
+ case "tree":
195
+ throw new Error("tree type unimplemented");
196
+ default:
197
+ throw new Error(`unexpected type: ${shape._type}`);
198
+ }
199
+ }
200
+
201
+ // src/draft-nodes/list-base.ts
202
+ var ListDraftNodeBase = class extends DraftNode {
203
+ // Cache for items returned by array methods to track mutations
204
+ itemCache = /* @__PURE__ */ new Map();
205
+ get container() {
206
+ return super.container;
207
+ }
208
+ get shape() {
209
+ return super.shape;
210
+ }
211
+ absorbPlainValues() {
212
+ for (const [index, cachedItem] of this.itemCache.entries()) {
213
+ if (cachedItem) {
214
+ if (isValueShape(this.shape.shape)) {
215
+ this.absorbValueAtIndex(index, cachedItem);
216
+ } else {
217
+ if (cachedItem && typeof cachedItem === "object" && "absorbPlainValues" in cachedItem) {
218
+ ;
219
+ cachedItem.absorbPlainValues();
220
+ }
221
+ }
222
+ }
223
+ }
224
+ this.itemCache.clear();
225
+ }
226
+ insertWithConversion(index, item) {
227
+ const convertedItem = convertInputToNode(item, this.shape.shape);
228
+ if (isContainer(convertedItem)) {
229
+ this.container.insertContainer(index, convertedItem);
230
+ } else {
231
+ this.container.insert(index, convertedItem);
232
+ }
233
+ }
234
+ pushWithConversion(item) {
235
+ const convertedItem = convertInputToNode(item, this.shape.shape);
236
+ if (isContainer(convertedItem)) {
237
+ this.container.pushContainer(convertedItem);
238
+ } else {
239
+ this.container.push(convertedItem);
240
+ }
241
+ }
242
+ getDraftNodeParams(index, shape) {
243
+ return {
244
+ shape,
245
+ emptyState: void 0,
246
+ // List items don't have empty state
247
+ getContainer: () => {
248
+ const containerItem = this.container.get(index);
249
+ if (!containerItem || !isContainer(containerItem)) {
250
+ throw new Error(`No container found at index ${index}`);
251
+ }
252
+ return containerItem;
253
+ }
254
+ };
255
+ }
256
+ // Get item for predicate functions - always returns plain Item for filtering logic
257
+ getPredicateItem(index) {
258
+ const cachedItem = this.itemCache.get(index);
259
+ if (cachedItem && isValueShape(this.shape.shape)) {
260
+ return cachedItem;
261
+ }
262
+ const containerItem = this.container.get(index);
263
+ if (containerItem === void 0) {
264
+ return void 0;
265
+ }
266
+ if (isValueShape(this.shape.shape)) {
267
+ return containerItem;
268
+ } else {
269
+ if (isContainer(containerItem)) {
270
+ if (typeof containerItem === "object" && containerItem !== null && "toJSON" in containerItem) {
271
+ return containerItem.toJSON();
272
+ } else if (typeof containerItem === "object" && containerItem !== null && "getShallowValue" in containerItem) {
273
+ return containerItem.getShallowValue();
274
+ } else {
275
+ return containerItem;
276
+ }
277
+ }
278
+ return containerItem;
279
+ }
280
+ }
281
+ // Get item for return values - returns DraftItem that can be mutated
282
+ getDraftItem(index) {
283
+ let cachedItem = this.itemCache.get(index);
284
+ if (cachedItem) {
285
+ return cachedItem;
286
+ }
287
+ const containerItem = this.container.get(index);
288
+ if (containerItem === void 0) {
289
+ return void 0;
290
+ }
291
+ if (isValueShape(this.shape.shape)) {
292
+ if (typeof containerItem === "object" && containerItem !== null) {
293
+ cachedItem = JSON.parse(JSON.stringify(containerItem));
294
+ } else {
295
+ cachedItem = containerItem;
296
+ }
297
+ this.itemCache.set(index, cachedItem);
298
+ return cachedItem;
299
+ } else {
300
+ cachedItem = createContainerDraftNode(
301
+ this.getDraftNodeParams(index, this.shape.shape)
302
+ );
303
+ this.itemCache.set(index, cachedItem);
304
+ return cachedItem;
305
+ }
306
+ }
307
+ // Array-like methods for better developer experience
308
+ // DUAL INTERFACE: Predicates get Item (plain data), return values are DraftItem (mutable)
309
+ find(predicate) {
310
+ for (let i = 0; i < this.length; i++) {
311
+ const predicateItem = this.getPredicateItem(i);
312
+ if (predicate(predicateItem, i)) {
313
+ return this.getDraftItem(i);
314
+ }
315
+ }
316
+ return void 0;
317
+ }
318
+ findIndex(predicate) {
319
+ for (let i = 0; i < this.length; i++) {
320
+ const predicateItem = this.getPredicateItem(i);
321
+ if (predicate(predicateItem, i)) {
322
+ return i;
323
+ }
324
+ }
325
+ return -1;
326
+ }
327
+ map(callback) {
328
+ const result = [];
329
+ for (let i = 0; i < this.length; i++) {
330
+ const predicateItem = this.getPredicateItem(i);
331
+ result.push(callback(predicateItem, i));
332
+ }
333
+ return result;
334
+ }
335
+ filter(predicate) {
336
+ const result = [];
337
+ for (let i = 0; i < this.length; i++) {
338
+ const predicateItem = this.getPredicateItem(i);
339
+ if (predicate(predicateItem, i)) {
340
+ result.push(this.getDraftItem(i));
341
+ }
342
+ }
343
+ return result;
344
+ }
345
+ forEach(callback) {
346
+ for (let i = 0; i < this.length; i++) {
347
+ const predicateItem = this.getPredicateItem(i);
348
+ callback(predicateItem, i);
349
+ }
350
+ }
351
+ some(predicate) {
352
+ for (let i = 0; i < this.length; i++) {
353
+ const predicateItem = this.getPredicateItem(i);
354
+ if (predicate(predicateItem, i)) {
355
+ return true;
356
+ }
357
+ }
358
+ return false;
359
+ }
360
+ every(predicate) {
361
+ for (let i = 0; i < this.length; i++) {
362
+ const predicateItem = this.getPredicateItem(i);
363
+ if (!predicate(predicateItem, i)) {
364
+ return false;
365
+ }
366
+ }
367
+ return true;
368
+ }
369
+ insert(index, item) {
370
+ this.updateCacheForInsert(index);
371
+ this.insertWithConversion(index, item);
372
+ }
373
+ delete(index, len) {
374
+ this.updateCacheForDelete(index, len);
375
+ this.container.delete(index, len);
376
+ }
377
+ push(item) {
378
+ this.pushWithConversion(item);
379
+ }
380
+ pushContainer(container) {
381
+ return this.container.pushContainer(container);
382
+ }
383
+ insertContainer(index, container) {
384
+ return this.container.insertContainer(index, container);
385
+ }
386
+ get(index) {
387
+ return this.getDraftItem(index);
388
+ }
389
+ toArray() {
390
+ return this.container.toArray();
391
+ }
392
+ get length() {
393
+ return this.container.length;
394
+ }
395
+ // Update cache indices when items are deleted
396
+ updateCacheForDelete(deleteIndex, deleteLen) {
397
+ const newCache = /* @__PURE__ */ new Map();
398
+ for (const [cachedIndex, cachedItem] of this.itemCache.entries()) {
399
+ if (cachedIndex < deleteIndex) {
400
+ newCache.set(cachedIndex, cachedItem);
401
+ } else if (cachedIndex >= deleteIndex + deleteLen) {
402
+ newCache.set(cachedIndex - deleteLen, cachedItem);
403
+ }
404
+ }
405
+ this.itemCache = newCache;
406
+ }
407
+ // Update cache indices when items are inserted
408
+ updateCacheForInsert(insertIndex) {
409
+ const newCache = /* @__PURE__ */ new Map();
410
+ for (const [cachedIndex, cachedItem] of this.itemCache.entries()) {
411
+ if (cachedIndex < insertIndex) {
412
+ newCache.set(cachedIndex, cachedItem);
413
+ } else {
414
+ newCache.set(cachedIndex + 1, cachedItem);
415
+ }
416
+ }
417
+ this.itemCache = newCache;
418
+ }
419
+ };
420
+
421
+ // src/draft-nodes/list.ts
422
+ var ListDraftNode = class extends ListDraftNodeBase {
423
+ get container() {
424
+ return super.container;
425
+ }
426
+ absorbValueAtIndex(index, value) {
427
+ this.container.delete(index, 1);
428
+ this.container.insert(index, value);
429
+ }
430
+ };
431
+
432
+ // src/draft-nodes/map.ts
433
+ import {
434
+ LoroCounter as LoroCounter2,
435
+ LoroList as LoroList2,
436
+ LoroMap as LoroMap2,
437
+ LoroMovableList as LoroMovableList2,
438
+ LoroText as LoroText2,
439
+ LoroTree
440
+ } from "loro-crdt";
441
+ var containerConstructor = {
442
+ counter: LoroCounter2,
443
+ list: LoroList2,
444
+ map: LoroMap2,
445
+ movableList: LoroMovableList2,
446
+ record: LoroMap2,
447
+ text: LoroText2,
448
+ tree: LoroTree
449
+ };
450
+ var MapDraftNode = class extends DraftNode {
451
+ propertyCache = /* @__PURE__ */ new Map();
452
+ constructor(params) {
453
+ super(params);
454
+ this.createLazyProperties();
455
+ }
456
+ get shape() {
457
+ return super.shape;
458
+ }
459
+ get container() {
460
+ return super.container;
461
+ }
462
+ absorbPlainValues() {
463
+ for (const [key, node] of this.propertyCache.entries()) {
464
+ if (node instanceof DraftNode) {
465
+ node.absorbPlainValues();
466
+ continue;
467
+ }
468
+ this.container.set(key, node);
469
+ }
470
+ }
471
+ getDraftNodeParams(key, shape) {
472
+ const emptyState = this.emptyState?.[key];
473
+ const LoroContainer = containerConstructor[shape._type];
474
+ return {
475
+ shape,
476
+ emptyState,
477
+ getContainer: () => this.container.getOrCreateContainer(key, new LoroContainer())
478
+ };
479
+ }
480
+ getOrCreateNode(key, shape) {
481
+ let node = this.propertyCache.get(key);
482
+ if (!node) {
483
+ if (isContainerShape(shape)) {
484
+ node = createContainerDraftNode(this.getDraftNodeParams(key, shape));
485
+ } else {
486
+ const containerValue = this.container.get(key);
487
+ if (containerValue !== void 0) {
488
+ node = containerValue;
489
+ } else {
490
+ const emptyState = this.emptyState?.[key];
491
+ if (!emptyState) {
492
+ throw new Error("empty state required");
493
+ }
494
+ node = emptyState;
495
+ }
496
+ }
497
+ if (!node) throw new Error("no container made");
498
+ this.propertyCache.set(key, node);
499
+ }
500
+ return node;
501
+ }
502
+ createLazyProperties() {
503
+ for (const key in this.shape.shapes) {
504
+ const shape = this.shape.shapes[key];
505
+ Object.defineProperty(this, key, {
506
+ get: () => this.getOrCreateNode(key, shape),
507
+ set: isValueShape(shape) ? (value) => {
508
+ this.container.set(key, value);
509
+ } : void 0
510
+ });
511
+ }
512
+ }
513
+ // TOOD(duane): return correct type here
514
+ get(key) {
515
+ return this.container.get(key);
516
+ }
517
+ set(key, value) {
518
+ this.container.set(key, value);
519
+ }
520
+ setContainer(key, container) {
521
+ return this.container.setContainer(key, container);
522
+ }
523
+ delete(key) {
524
+ this.container.delete(key);
525
+ }
526
+ has(key) {
527
+ return this.container.get(key) !== void 0;
528
+ }
529
+ keys() {
530
+ return this.container.keys();
531
+ }
532
+ values() {
533
+ return this.container.values();
534
+ }
535
+ get size() {
536
+ return this.container.size;
537
+ }
538
+ };
539
+
540
+ // src/draft-nodes/movable-list.ts
541
+ var MovableListDraftNode = class extends ListDraftNodeBase {
542
+ get container() {
543
+ return super.container;
544
+ }
545
+ absorbValueAtIndex(index, value) {
546
+ this.container.set(index, value);
547
+ }
548
+ move(from, to) {
549
+ this.container.move(from, to);
550
+ }
551
+ set(index, item) {
552
+ return this.container.set(index, item);
553
+ }
554
+ };
555
+
556
+ // src/draft-nodes/record.ts
557
+ import {
558
+ LoroCounter as LoroCounter3,
559
+ LoroList as LoroList3,
560
+ LoroMap as LoroMap3,
561
+ LoroMovableList as LoroMovableList3,
562
+ LoroText as LoroText3,
563
+ LoroTree as LoroTree2
564
+ } from "loro-crdt";
565
+ var containerConstructor2 = {
566
+ counter: LoroCounter3,
567
+ list: LoroList3,
568
+ map: LoroMap3,
569
+ movableList: LoroMovableList3,
570
+ record: LoroMap3,
571
+ text: LoroText3,
572
+ tree: LoroTree2
573
+ };
574
+ var RecordDraftNode = class extends DraftNode {
575
+ nodeCache = /* @__PURE__ */ new Map();
576
+ constructor(params) {
577
+ super(params);
578
+ return new Proxy(this, {
579
+ get: (target, prop) => {
580
+ if (typeof prop === "string" && !(prop in target)) {
581
+ return target.get(prop);
582
+ }
583
+ return Reflect.get(target, prop);
584
+ },
585
+ set: (target, prop, value) => {
586
+ if (typeof prop === "string" && !(prop in target)) {
587
+ target.set(prop, value);
588
+ return true;
589
+ }
590
+ return Reflect.set(target, prop, value);
591
+ },
592
+ deleteProperty: (target, prop) => {
593
+ if (typeof prop === "string" && !(prop in target)) {
594
+ target.delete(prop);
595
+ return true;
596
+ }
597
+ return Reflect.deleteProperty(target, prop);
598
+ },
599
+ ownKeys: (target) => {
600
+ return target.keys();
601
+ },
602
+ getOwnPropertyDescriptor: (target, prop) => {
603
+ if (typeof prop === "string" && target.has(prop)) {
604
+ return {
605
+ configurable: true,
606
+ enumerable: true,
607
+ value: target.get(prop)
608
+ };
609
+ }
610
+ return Reflect.getOwnPropertyDescriptor(target, prop);
611
+ }
612
+ });
613
+ }
614
+ get shape() {
615
+ return super.shape;
616
+ }
617
+ get container() {
618
+ return super.container;
619
+ }
620
+ absorbPlainValues() {
621
+ for (const [key, node] of this.nodeCache.entries()) {
622
+ if (node instanceof DraftNode) {
623
+ node.absorbPlainValues();
624
+ continue;
625
+ }
626
+ this.container.set(key, node);
627
+ }
628
+ }
629
+ getDraftNodeParams(key, shape) {
630
+ const emptyState = this.emptyState?.[key];
631
+ const LoroContainer = containerConstructor2[shape._type];
632
+ return {
633
+ shape,
634
+ emptyState,
635
+ getContainer: () => this.container.getOrCreateContainer(key, new LoroContainer())
636
+ };
637
+ }
638
+ getOrCreateNode(key) {
639
+ let node = this.nodeCache.get(key);
640
+ if (!node) {
641
+ const shape = this.shape.shape;
642
+ if (isContainerShape(shape)) {
643
+ node = createContainerDraftNode(
644
+ this.getDraftNodeParams(key, shape)
645
+ );
646
+ } else {
647
+ const containerValue = this.container.get(key);
648
+ if (containerValue !== void 0) {
649
+ node = containerValue;
650
+ } else {
651
+ const emptyState = this.emptyState?.[key];
652
+ if (emptyState === void 0) {
653
+ node = shape._plain;
654
+ } else {
655
+ node = emptyState;
656
+ }
657
+ }
658
+ }
659
+ if (node !== void 0) {
660
+ this.nodeCache.set(key, node);
661
+ }
662
+ }
663
+ return node;
664
+ }
665
+ get(key) {
666
+ return this.getOrCreateNode(key);
667
+ }
668
+ set(key, value) {
669
+ if (isValueShape(this.shape.shape)) {
670
+ this.container.set(key, value);
671
+ this.nodeCache.set(key, value);
672
+ } else {
673
+ throw new Error(
674
+ "Cannot set container directly, modify the draft node instead"
675
+ );
676
+ }
677
+ }
678
+ setContainer(key, container) {
679
+ return this.container.setContainer(key, container);
680
+ }
681
+ delete(key) {
682
+ this.container.delete(key);
683
+ this.nodeCache.delete(key);
684
+ }
685
+ has(key) {
686
+ return this.container.get(key) !== void 0;
687
+ }
688
+ keys() {
689
+ return this.container.keys();
690
+ }
691
+ values() {
692
+ return this.container.values();
693
+ }
694
+ get size() {
695
+ return this.container.size;
696
+ }
697
+ };
698
+
699
+ // src/draft-nodes/text.ts
700
+ var TextDraftNode = class extends DraftNode {
701
+ absorbPlainValues() {
702
+ }
703
+ // Text methods
704
+ insert(index, content) {
705
+ if (content.length === 0) return;
706
+ this.container.insert(index, content);
707
+ }
708
+ delete(index, len) {
709
+ this.container.delete(index, len);
710
+ }
711
+ toString() {
712
+ return this.container.toString();
713
+ }
714
+ update(text) {
715
+ this.container.update(text);
716
+ }
717
+ mark(range, key, value) {
718
+ this.container.mark(range, key, value);
719
+ }
720
+ unmark(range, key) {
721
+ this.container.unmark(range, key);
722
+ }
723
+ toDelta() {
724
+ return this.container.toDelta();
725
+ }
726
+ applyDelta(delta) {
727
+ this.container.applyDelta(delta);
728
+ }
729
+ get length() {
730
+ return this.container.length;
731
+ }
732
+ };
733
+
734
+ // src/draft-nodes/tree.ts
735
+ var TreeDraftNode = class extends DraftNode {
736
+ absorbPlainValues() {
737
+ }
738
+ createNode(parent, index) {
739
+ return this.container.createNode(parent, index);
740
+ }
741
+ move(target, parent, index) {
742
+ this.container.move(target, parent, index);
743
+ }
744
+ delete(target) {
745
+ this.container.delete(target);
746
+ }
747
+ has(target) {
748
+ return this.container.has(target);
749
+ }
750
+ getNodeByID(id) {
751
+ return this.container.getNodeByID ? this.container.getNodeByID(id) : void 0;
752
+ }
753
+ };
754
+
755
+ // src/draft-nodes/utils.ts
756
+ function createContainerDraftNode(params) {
757
+ switch (params.shape._type) {
758
+ case "counter":
759
+ return new CounterDraftNode(
760
+ params
761
+ );
762
+ case "list":
763
+ return new ListDraftNode(params);
764
+ case "map":
765
+ return new MapDraftNode(params);
766
+ case "movableList":
767
+ return new MovableListDraftNode(
768
+ params
769
+ );
770
+ case "record":
771
+ return new RecordDraftNode(
772
+ params
773
+ );
774
+ case "text":
775
+ return new TextDraftNode(params);
776
+ case "tree":
777
+ return new TreeDraftNode(params);
778
+ default:
779
+ throw new Error(
780
+ `Unknown container type: ${params.shape._type}`
781
+ );
782
+ }
783
+ }
784
+
785
+ // src/draft-nodes/doc.ts
786
+ var containerGetter = {
787
+ counter: "getCounter",
788
+ list: "getList",
789
+ map: "getMap",
790
+ movableList: "getMovableList",
791
+ record: "getMap",
792
+ text: "getText",
793
+ tree: "getTree"
794
+ };
795
+ var DraftDoc = class extends DraftNode {
796
+ doc;
797
+ propertyCache = /* @__PURE__ */ new Map();
798
+ requiredEmptyState;
799
+ constructor(_params) {
800
+ super({
801
+ ..._params,
802
+ getContainer: () => {
803
+ throw new Error("can't get container on DraftDoc");
804
+ }
805
+ });
806
+ if (!_params.emptyState) throw new Error("emptyState required");
807
+ this.doc = _params.doc;
808
+ this.requiredEmptyState = _params.emptyState;
809
+ this.createLazyProperties();
810
+ }
811
+ getDraftNodeParams(key, shape) {
812
+ const getter = this.doc[containerGetter[shape._type]].bind(this.doc);
813
+ return {
814
+ shape,
815
+ emptyState: this.requiredEmptyState[key],
816
+ getContainer: () => getter(key)
817
+ };
818
+ }
819
+ getOrCreateDraftNode(key, shape) {
820
+ let node = this.propertyCache.get(key);
821
+ if (!node) {
822
+ node = createContainerDraftNode(this.getDraftNodeParams(key, shape));
823
+ this.propertyCache.set(key, node);
824
+ }
825
+ return node;
826
+ }
827
+ createLazyProperties() {
828
+ for (const key in this.shape.shapes) {
829
+ const shape = this.shape.shapes[key];
830
+ Object.defineProperty(this, key, {
831
+ get: () => this.getOrCreateDraftNode(key, shape)
832
+ });
833
+ }
834
+ }
835
+ absorbPlainValues() {
836
+ for (const [, node] of this.propertyCache.entries()) {
837
+ node.absorbPlainValues();
838
+ }
839
+ }
840
+ };
841
+
842
+ // src/json-patch.ts
843
+ function normalizePath(path) {
844
+ if (Array.isArray(path)) {
845
+ return path;
846
+ }
847
+ if (path.startsWith("/")) {
848
+ return path.slice(1).split("/").map((segment) => {
849
+ const unescaped = segment.replace(/~1/g, "/").replace(/~0/g, "~");
850
+ const asNumber = Number(unescaped);
851
+ return Number.isInteger(asNumber) && asNumber >= 0 ? asNumber : unescaped;
852
+ });
853
+ }
854
+ return path.split(".").map((segment) => {
855
+ const asNumber = Number(segment);
856
+ return Number.isInteger(asNumber) && asNumber >= 0 ? asNumber : segment;
857
+ });
858
+ }
859
+ function navigateToPath(draft, path) {
860
+ if (path.length === 0) {
861
+ throw new Error("Cannot navigate to empty path");
862
+ }
863
+ let current = draft;
864
+ for (let i = 0; i < path.length - 1; i++) {
865
+ const segment = path[i];
866
+ if (typeof segment === "string") {
867
+ current = current[segment];
868
+ if (current === void 0) {
869
+ throw new Error(`Cannot navigate to path segment: ${segment}`);
870
+ }
871
+ } else if (typeof segment === "number") {
872
+ if (current.get && typeof current.get === "function") {
873
+ current = current.get(segment);
874
+ if (current === void 0) {
875
+ throw new Error(`List index ${segment} does not exist`);
876
+ }
877
+ } else {
878
+ throw new Error(`Cannot use numeric index ${segment} on non-list`);
879
+ }
880
+ } else {
881
+ throw new Error(`Invalid path segment type: ${typeof segment}`);
882
+ }
883
+ }
884
+ const targetKey = path[path.length - 1];
885
+ return { parent: current, key: targetKey };
886
+ }
887
+ function getValueAtPath(draft, path) {
888
+ if (path.length === 0) {
889
+ return draft;
890
+ }
891
+ const { parent, key } = navigateToPath(draft, path);
892
+ if (typeof key === "string") {
893
+ if (parent.get && typeof parent.get === "function") {
894
+ return parent.get(key);
895
+ }
896
+ return parent[key];
897
+ } else if (typeof key === "number") {
898
+ if (parent.get && typeof parent.get === "function") {
899
+ return parent.get(key);
900
+ }
901
+ throw new Error(`Cannot use numeric index ${key} on non-list`);
902
+ }
903
+ throw new Error(`Invalid key type: ${typeof key}`);
904
+ }
905
+ function handleAdd(draft, operation) {
906
+ const path = normalizePath(operation.path);
907
+ const { parent, key } = navigateToPath(draft, path);
908
+ if (typeof key === "string") {
909
+ if (parent.set && typeof parent.set === "function") {
910
+ parent.set(key, operation.value);
911
+ } else {
912
+ parent[key] = operation.value;
913
+ }
914
+ } else if (typeof key === "number") {
915
+ if (parent.insert && typeof parent.insert === "function") {
916
+ parent.insert(key, operation.value);
917
+ } else {
918
+ throw new Error(`Cannot insert at numeric index ${key} on non-list`);
919
+ }
920
+ } else {
921
+ throw new Error(`Invalid key type: ${typeof key}`);
922
+ }
923
+ }
924
+ function handleRemove(draft, operation) {
925
+ const path = normalizePath(operation.path);
926
+ const { parent, key } = navigateToPath(draft, path);
927
+ if (typeof key === "string") {
928
+ if (parent.delete && typeof parent.delete === "function") {
929
+ parent.delete(key);
930
+ } else {
931
+ delete parent[key];
932
+ }
933
+ } else if (typeof key === "number") {
934
+ if (parent.delete && typeof parent.delete === "function") {
935
+ parent.delete(key, 1);
936
+ } else {
937
+ throw new Error(`Cannot remove at numeric index ${key} on non-list`);
938
+ }
939
+ } else {
940
+ throw new Error(`Invalid key type: ${typeof key}`);
941
+ }
942
+ }
943
+ function handleReplace(draft, operation) {
944
+ const path = normalizePath(operation.path);
945
+ const { parent, key } = navigateToPath(draft, path);
946
+ if (typeof key === "string") {
947
+ if (parent.set && typeof parent.set === "function") {
948
+ parent.set(key, operation.value);
949
+ } else {
950
+ parent[key] = operation.value;
951
+ }
952
+ } else if (typeof key === "number") {
953
+ if (parent.delete && parent.insert && typeof parent.delete === "function" && typeof parent.insert === "function") {
954
+ parent.delete(key, 1);
955
+ parent.insert(key, operation.value);
956
+ } else {
957
+ throw new Error(`Cannot replace at numeric index ${key} on non-list`);
958
+ }
959
+ } else {
960
+ throw new Error(`Invalid key type: ${typeof key}`);
961
+ }
962
+ }
963
+ function handleMove(draft, operation) {
964
+ const fromPath = normalizePath(operation.from);
965
+ const toPath = normalizePath(operation.path);
966
+ if (fromPath.length === toPath.length && fromPath.slice(0, -1).every((segment, i) => segment === toPath[i])) {
967
+ const fromIndex = fromPath[fromPath.length - 1];
968
+ const toIndex = toPath[toPath.length - 1];
969
+ if (typeof fromIndex === "number" && typeof toIndex === "number") {
970
+ const { parent } = navigateToPath(draft, fromPath.slice(0, -1));
971
+ if (parent.move && typeof parent.move === "function") {
972
+ parent.move(fromIndex, toIndex);
973
+ return;
974
+ }
975
+ const value2 = getValueAtPath(draft, fromPath);
976
+ handleRemove(draft, { op: "remove", path: operation.from });
977
+ handleAdd(draft, { op: "add", path: operation.path, value: value2 });
978
+ return;
979
+ }
980
+ }
981
+ const value = getValueAtPath(draft, fromPath);
982
+ handleRemove(draft, { op: "remove", path: operation.from });
983
+ handleAdd(draft, { op: "add", path: operation.path, value });
984
+ }
985
+ function handleCopy(draft, operation) {
986
+ const fromPath = normalizePath(operation.from);
987
+ const value = getValueAtPath(draft, fromPath);
988
+ handleAdd(draft, { op: "add", path: operation.path, value });
989
+ }
990
+ function handleTest(draft, operation) {
991
+ const path = normalizePath(operation.path);
992
+ const actualValue = getValueAtPath(draft, path);
993
+ return JSON.stringify(actualValue) === JSON.stringify(operation.value);
994
+ }
995
+ var JsonPatchApplicator = class {
996
+ constructor(rootDraft) {
997
+ this.rootDraft = rootDraft;
998
+ }
999
+ /**
1000
+ * Apply a single JSON Patch operation
1001
+ */
1002
+ applyOperation(operation) {
1003
+ switch (operation.op) {
1004
+ case "add":
1005
+ handleAdd(this.rootDraft, operation);
1006
+ break;
1007
+ case "remove":
1008
+ handleRemove(this.rootDraft, operation);
1009
+ break;
1010
+ case "replace":
1011
+ handleReplace(this.rootDraft, operation);
1012
+ break;
1013
+ case "move":
1014
+ handleMove(this.rootDraft, operation);
1015
+ break;
1016
+ case "copy":
1017
+ handleCopy(this.rootDraft, operation);
1018
+ break;
1019
+ case "test":
1020
+ if (!handleTest(this.rootDraft, operation)) {
1021
+ throw new Error(`JSON Patch test failed at path: ${operation.path}`);
1022
+ }
1023
+ break;
1024
+ default:
1025
+ throw new Error(
1026
+ `Unsupported JSON Patch operation: ${operation.op}`
1027
+ );
1028
+ }
1029
+ }
1030
+ /**
1031
+ * Apply multiple JSON Patch operations in sequence
1032
+ */
1033
+ applyPatch(patch) {
1034
+ for (const operation of patch) {
1035
+ this.applyOperation(operation);
1036
+ }
1037
+ }
1038
+ };
1039
+
1040
+ // src/overlay.ts
1041
+ function overlayEmptyState(shape, crdtValue, emptyValue) {
1042
+ if (typeof crdtValue !== "object") {
1043
+ throw new Error("crdt object is required");
1044
+ }
1045
+ if (typeof emptyValue !== "object") {
1046
+ throw new Error("empty object is required");
1047
+ }
1048
+ const result = { ...emptyValue };
1049
+ for (const [key, propShape] of Object.entries(shape.shapes)) {
1050
+ const propCrdtValue = crdtValue[key];
1051
+ const propEmptyValue = emptyValue[key];
1052
+ result[key] = mergeValue(
1053
+ propShape,
1054
+ propCrdtValue,
1055
+ propEmptyValue
1056
+ );
1057
+ }
1058
+ return result;
1059
+ }
1060
+ function mergeValue(shape, crdtValue, emptyValue) {
1061
+ if (crdtValue === void 0 && emptyValue === void 0) {
1062
+ throw new Error("either crdt or empty value must be defined");
1063
+ }
1064
+ switch (shape._type) {
1065
+ case "text":
1066
+ return crdtValue ?? emptyValue ?? "";
1067
+ case "counter":
1068
+ return crdtValue ?? emptyValue ?? 0;
1069
+ case "list":
1070
+ case "movableList":
1071
+ return crdtValue ?? emptyValue ?? [];
1072
+ case "map": {
1073
+ if (!isObjectValue(crdtValue) && crdtValue !== void 0) {
1074
+ throw new Error("map crdt must be object");
1075
+ }
1076
+ const crdtMapValue = crdtValue ?? {};
1077
+ if (!isObjectValue(emptyValue) && emptyValue !== void 0) {
1078
+ throw new Error("map empty state must be object");
1079
+ }
1080
+ const emptyMapValue = emptyValue ?? {};
1081
+ const result = { ...emptyMapValue };
1082
+ for (const [key, nestedShape] of Object.entries(shape.shapes)) {
1083
+ const nestedCrdtValue = crdtMapValue[key];
1084
+ const nestedEmptyValue = emptyMapValue[key];
1085
+ result[key] = mergeValue(
1086
+ nestedShape,
1087
+ nestedCrdtValue,
1088
+ nestedEmptyValue
1089
+ );
1090
+ }
1091
+ return result;
1092
+ }
1093
+ case "tree":
1094
+ return crdtValue ?? emptyValue ?? [];
1095
+ default:
1096
+ return crdtValue ?? emptyValue;
1097
+ }
1098
+ }
1099
+
1100
+ // src/validation.ts
1101
+ function validateValue(value, schema, path = "") {
1102
+ if (!schema || typeof schema !== "object" || !("_type" in schema)) {
1103
+ throw new Error(`Invalid schema at path ${path}: missing _type`);
1104
+ }
1105
+ const currentPath = path || "root";
1106
+ if (schema._type === "text") {
1107
+ if (typeof value !== "string") {
1108
+ throw new Error(
1109
+ `Expected string at path ${currentPath}, got ${typeof value}`
1110
+ );
1111
+ }
1112
+ return value;
1113
+ }
1114
+ if (schema._type === "counter") {
1115
+ if (typeof value !== "number") {
1116
+ throw new Error(
1117
+ `Expected number at path ${currentPath}, got ${typeof value}`
1118
+ );
1119
+ }
1120
+ return value;
1121
+ }
1122
+ if (schema._type === "list" || schema._type === "movableList") {
1123
+ if (!Array.isArray(value)) {
1124
+ throw new Error(
1125
+ `Expected array at path ${currentPath}, got ${typeof value}`
1126
+ );
1127
+ }
1128
+ const listSchema = schema;
1129
+ return value.map(
1130
+ (item, index) => validateValue(item, listSchema.shape, `${currentPath}[${index}]`)
1131
+ );
1132
+ }
1133
+ if (schema._type === "map") {
1134
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1135
+ throw new Error(
1136
+ `Expected object at path ${currentPath}, got ${typeof value}`
1137
+ );
1138
+ }
1139
+ const mapSchema = schema;
1140
+ const result = {};
1141
+ for (const [key, nestedSchema] of Object.entries(mapSchema.shapes)) {
1142
+ const nestedPath = `${currentPath}.${key}`;
1143
+ const nestedValue = value[key];
1144
+ result[key] = validateValue(nestedValue, nestedSchema, nestedPath);
1145
+ }
1146
+ return result;
1147
+ }
1148
+ if (schema._type === "record") {
1149
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1150
+ throw new Error(
1151
+ `Expected object at path ${currentPath}, got ${typeof value}`
1152
+ );
1153
+ }
1154
+ const recordSchema = schema;
1155
+ const result = {};
1156
+ for (const [key, nestedValue] of Object.entries(value)) {
1157
+ const nestedPath = `${currentPath}.${key}`;
1158
+ result[key] = validateValue(nestedValue, recordSchema.shape, nestedPath);
1159
+ }
1160
+ return result;
1161
+ }
1162
+ if (schema._type === "tree") {
1163
+ if (!Array.isArray(value)) {
1164
+ throw new Error(
1165
+ `Expected array for tree at path ${currentPath}, got ${typeof value}`
1166
+ );
1167
+ }
1168
+ return value;
1169
+ }
1170
+ if (schema._type === "value") {
1171
+ const valueSchema = schema;
1172
+ switch (valueSchema.valueType) {
1173
+ case "string":
1174
+ if (typeof value !== "string") {
1175
+ throw new Error(
1176
+ `Expected string at path ${currentPath}, got ${typeof value}`
1177
+ );
1178
+ }
1179
+ return value;
1180
+ case "number":
1181
+ if (typeof value !== "number") {
1182
+ throw new Error(
1183
+ `Expected number at path ${currentPath}, got ${typeof value}`
1184
+ );
1185
+ }
1186
+ return value;
1187
+ case "boolean":
1188
+ if (typeof value !== "boolean") {
1189
+ throw new Error(
1190
+ `Expected boolean at path ${currentPath}, got ${typeof value}`
1191
+ );
1192
+ }
1193
+ return value;
1194
+ case "null":
1195
+ if (value !== null) {
1196
+ throw new Error(
1197
+ `Expected null at path ${currentPath}, got ${typeof value}`
1198
+ );
1199
+ }
1200
+ return value;
1201
+ case "undefined":
1202
+ if (value !== void 0) {
1203
+ throw new Error(
1204
+ `Expected undefined at path ${currentPath}, got ${typeof value}`
1205
+ );
1206
+ }
1207
+ return value;
1208
+ case "uint8array":
1209
+ if (!(value instanceof Uint8Array)) {
1210
+ throw new Error(
1211
+ `Expected Uint8Array at path ${currentPath}, got ${typeof value}`
1212
+ );
1213
+ }
1214
+ return value;
1215
+ case "object": {
1216
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1217
+ throw new Error(
1218
+ `Expected object at path ${currentPath}, got ${typeof value}`
1219
+ );
1220
+ }
1221
+ const objectSchema = valueSchema;
1222
+ const result = {};
1223
+ for (const [key, nestedSchema] of Object.entries(objectSchema.shape)) {
1224
+ const nestedPath = `${currentPath}.${key}`;
1225
+ const nestedValue = value[key];
1226
+ result[key] = validateValue(nestedValue, nestedSchema, nestedPath);
1227
+ }
1228
+ return result;
1229
+ }
1230
+ case "record": {
1231
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1232
+ throw new Error(
1233
+ `Expected object at path ${currentPath}, got ${typeof value}`
1234
+ );
1235
+ }
1236
+ const recordSchema = valueSchema;
1237
+ const result = {};
1238
+ for (const [key, nestedValue] of Object.entries(value)) {
1239
+ const nestedPath = `${currentPath}.${key}`;
1240
+ result[key] = validateValue(
1241
+ nestedValue,
1242
+ recordSchema.shape,
1243
+ nestedPath
1244
+ );
1245
+ }
1246
+ return result;
1247
+ }
1248
+ case "array": {
1249
+ if (!Array.isArray(value)) {
1250
+ throw new Error(
1251
+ `Expected array at path ${currentPath}, got ${typeof value}`
1252
+ );
1253
+ }
1254
+ const arraySchema = valueSchema;
1255
+ return value.map(
1256
+ (item, index) => validateValue(item, arraySchema.shape, `${currentPath}[${index}]`)
1257
+ );
1258
+ }
1259
+ case "union": {
1260
+ const unionSchema = valueSchema;
1261
+ let lastError = null;
1262
+ for (const shape of unionSchema.shapes) {
1263
+ try {
1264
+ return validateValue(value, shape, currentPath);
1265
+ } catch (error) {
1266
+ lastError = error;
1267
+ }
1268
+ }
1269
+ throw new Error(
1270
+ `Value at path ${currentPath} does not match any union type: ${lastError?.message}`
1271
+ );
1272
+ }
1273
+ default:
1274
+ throw new Error(`Unknown value type: ${valueSchema.valueType}`);
1275
+ }
1276
+ }
1277
+ throw new Error(`Unknown schema type: ${schema._type}`);
1278
+ }
1279
+ function validateEmptyState(emptyState, schema) {
1280
+ if (!emptyState || typeof emptyState !== "object" || Array.isArray(emptyState)) {
1281
+ throw new Error("Empty state must be an object");
1282
+ }
1283
+ const result = {};
1284
+ for (const [key, schemaValue] of Object.entries(schema.shapes)) {
1285
+ const value = emptyState[key];
1286
+ result[key] = validateValue(value, schemaValue, key);
1287
+ }
1288
+ return result;
1289
+ }
1290
+
1291
+ // src/change.ts
1292
+ var TypedDoc = class {
1293
+ constructor(shape, emptyState, doc = new LoroDoc()) {
1294
+ this.shape = shape;
1295
+ this.emptyState = emptyState;
1296
+ this.doc = doc;
1297
+ validateEmptyState(emptyState, shape);
1298
+ }
1299
+ get value() {
1300
+ const crdtValue = this.doc.toJSON();
1301
+ return overlayEmptyState(
1302
+ this.shape,
1303
+ crdtValue,
1304
+ this.emptyState
1305
+ );
1306
+ }
1307
+ change(fn) {
1308
+ const draft = new DraftDoc({
1309
+ shape: this.shape,
1310
+ emptyState: this.emptyState,
1311
+ doc: this.doc
1312
+ });
1313
+ fn(draft);
1314
+ draft.absorbPlainValues();
1315
+ this.doc.commit();
1316
+ return this.value;
1317
+ }
1318
+ /**
1319
+ * Apply JSON Patch operations to the document
1320
+ *
1321
+ * @param patch - Array of JSON Patch operations (RFC 6902)
1322
+ * @param pathPrefix - Optional path prefix for scoped operations
1323
+ * @returns Updated document value
1324
+ *
1325
+ * @example
1326
+ * ```typescript
1327
+ * const result = typedDoc.applyPatch([
1328
+ * { op: 'add', path: '/users/0/name', value: 'Alice' },
1329
+ * { op: 'replace', path: '/settings/theme', value: 'dark' }
1330
+ * ])
1331
+ * ```
1332
+ */
1333
+ applyPatch(patch, pathPrefix) {
1334
+ return this.change((draft) => {
1335
+ const applicator = new JsonPatchApplicator(draft);
1336
+ const prefixedPatch = pathPrefix ? patch.map((op) => ({
1337
+ ...op,
1338
+ path: [...pathPrefix, ...normalizePath(op.path)]
1339
+ })) : patch;
1340
+ applicator.applyPatch(prefixedPatch);
1341
+ });
1342
+ }
1343
+ // Expose underlying doc for advanced use cases
1344
+ get loroDoc() {
1345
+ return this.doc;
1346
+ }
1347
+ // Expose shape for internal use
1348
+ get docShape() {
1349
+ return this.shape;
1350
+ }
1351
+ // Get raw CRDT value without overlay
1352
+ get rawValue() {
1353
+ return this.doc.toJSON();
1354
+ }
1355
+ };
1356
+ function createTypedDoc(shape, emptyState, existingDoc) {
1357
+ return new TypedDoc(shape, emptyState, existingDoc || new LoroDoc());
1358
+ }
1359
+
1360
+ // src/shape.ts
1361
+ var Shape = {
1362
+ doc: (shape) => ({
1363
+ _type: "doc",
1364
+ shapes: shape,
1365
+ _plain: {},
1366
+ _draft: {}
1367
+ }),
1368
+ // CRDTs are represented by Loro Containers--they converge on state using Loro's
1369
+ // various CRDT algorithms
1370
+ counter: () => ({
1371
+ _type: "counter",
1372
+ _plain: 0,
1373
+ _draft: {}
1374
+ }),
1375
+ list: (shape) => ({
1376
+ _type: "list",
1377
+ shape,
1378
+ _plain: [],
1379
+ _draft: {}
1380
+ }),
1381
+ map: (shape) => ({
1382
+ _type: "map",
1383
+ shapes: shape,
1384
+ _plain: {},
1385
+ _draft: {}
1386
+ }),
1387
+ record: (shape) => ({
1388
+ _type: "record",
1389
+ shape,
1390
+ _plain: {},
1391
+ _draft: {}
1392
+ }),
1393
+ movableList: (shape) => ({
1394
+ _type: "movableList",
1395
+ shape,
1396
+ _plain: [],
1397
+ _draft: {}
1398
+ }),
1399
+ text: () => ({
1400
+ _type: "text",
1401
+ _plain: "",
1402
+ _draft: {}
1403
+ }),
1404
+ tree: (shape) => ({
1405
+ _type: "tree",
1406
+ shape,
1407
+ _plain: {},
1408
+ _draft: {}
1409
+ }),
1410
+ // Values are represented as plain JS objects, with the limitation that they MUST be
1411
+ // representable as a Loro "Value"--basically JSON. The behavior of a Value is basically
1412
+ // "Last Write Wins", meaning there is no subtle convergent behavior here, just taking
1413
+ // the most recent value based on the current available information.
1414
+ plain: {
1415
+ string: () => ({
1416
+ _type: "value",
1417
+ valueType: "string",
1418
+ _plain: "",
1419
+ _draft: ""
1420
+ }),
1421
+ number: () => ({
1422
+ _type: "value",
1423
+ valueType: "number",
1424
+ _plain: 0,
1425
+ _draft: 0
1426
+ }),
1427
+ boolean: () => ({
1428
+ _type: "value",
1429
+ valueType: "boolean",
1430
+ _plain: false,
1431
+ _draft: false
1432
+ }),
1433
+ null: () => ({
1434
+ _type: "value",
1435
+ valueType: "null",
1436
+ _plain: null,
1437
+ _draft: null
1438
+ }),
1439
+ undefined: () => ({
1440
+ _type: "value",
1441
+ valueType: "undefined",
1442
+ _plain: void 0,
1443
+ _draft: void 0
1444
+ }),
1445
+ uint8Array: () => ({
1446
+ _type: "value",
1447
+ valueType: "uint8array",
1448
+ _plain: new Uint8Array(),
1449
+ _draft: new Uint8Array()
1450
+ }),
1451
+ object: (shape) => ({
1452
+ _type: "value",
1453
+ valueType: "object",
1454
+ shape,
1455
+ _plain: {},
1456
+ _draft: {}
1457
+ }),
1458
+ record: (shape) => ({
1459
+ _type: "value",
1460
+ valueType: "record",
1461
+ shape,
1462
+ _plain: {},
1463
+ _draft: {}
1464
+ }),
1465
+ array: (shape) => ({
1466
+ _type: "value",
1467
+ valueType: "array",
1468
+ shape,
1469
+ _plain: [],
1470
+ _draft: []
1471
+ }),
1472
+ // Special value type that helps make things like `string | null` representable
1473
+ // TODO(duane): should this be a more general type for containers too?
1474
+ union: (shapes) => ({
1475
+ _type: "value",
1476
+ valueType: "union",
1477
+ shapes,
1478
+ _plain: {},
1479
+ _draft: {}
1480
+ })
1481
+ }
1482
+ };
1483
+ export {
1484
+ Shape,
1485
+ TypedDoc,
1486
+ createTypedDoc,
1487
+ mergeValue,
1488
+ overlayEmptyState,
1489
+ validateEmptyState
1490
+ };
1491
+ //# sourceMappingURL=index.js.map