reptree 0.3.0 → 0.4.0-alpha.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.cjs CHANGED
@@ -187,6 +187,12 @@ var VertexState = class {
187
187
  removeTransientProperty(key) {
188
188
  this.transientProperties = this.transientProperties.filter((p) => p.key !== key);
189
189
  }
190
+ getTransientProperties() {
191
+ return this.transientProperties;
192
+ }
193
+ clearAllTransientProperties() {
194
+ this.transientProperties = [];
195
+ }
190
196
  };
191
197
 
192
198
  // src/TreeState.ts
@@ -423,234 +429,285 @@ function buildAliasMaps(aliases) {
423
429
  }
424
430
  return { publicToInternal, internalToPublic };
425
431
  }
426
- function toPublicObject(tree, id, internalToPublic) {
427
- const obj = {};
428
- for (const { key, value } of tree.getVertexProperties(id)) {
429
- const rule = internalToPublic.get(key);
430
- if (rule) {
431
- const converted = rule.toPublic ? rule.toPublic(value) : value;
432
- obj[rule.publicKey] = converted;
433
- } else {
434
- obj[key] = value;
435
- }
436
- }
437
- return obj;
438
- }
439
- var RESERVED_METHOD_USE_TRANSIENT = "useTransient";
440
- var RESERVED_METHOD_COMMIT_TRANSIENTS = "commitTransients";
441
- var VERTEX_PROPS = ["$id", "$parentId", "$parent", "$children", "$childrenIds"];
442
- var VERTEX_METHODS = ["$moveTo", "$delete", "$observe", "$observeChildren", "$newChild", "$newNamedChild"];
443
432
  function bindVertex(tree, id, schemaOrOptions) {
444
433
  const isOptions = typeof schemaOrOptions === "object" && schemaOrOptions !== null && (Object.prototype.hasOwnProperty.call(schemaOrOptions, "aliases") || Object.prototype.hasOwnProperty.call(schemaOrOptions, "includeInternalKeys") || Object.prototype.hasOwnProperty.call(schemaOrOptions, "schema"));
445
434
  const options = isOptions ? schemaOrOptions : { schema: schemaOrOptions };
446
435
  const schema = options.schema;
447
436
  const aliases = options.aliases ?? defaultAliases;
448
- const includeInternalKeys = options.includeInternalKeys ?? false;
449
437
  const { publicToInternal, internalToPublic } = buildAliasMaps(aliases);
450
- const cachedMethods = /* @__PURE__ */ new Map();
451
- return new Proxy({}, {
452
- get(_target, prop) {
453
- if (prop === RESERVED_METHOD_USE_TRANSIENT) {
454
- return (fn) => {
455
- const transientProxy = new Proxy({}, {
456
- get(_t, p) {
457
- if (typeof p !== "string") return void 0;
458
- const rule2 = publicToInternal.get(p);
459
- if (rule2) {
460
- const raw = tree.getVertexProperty(id, rule2.internalKey);
461
- return rule2.toPublic ? rule2.toPublic(raw) : raw;
462
- }
463
- return tree.getVertexProperty(id, p);
464
- },
465
- set(_t, p, value) {
466
- if (typeof p !== "string") return true;
467
- if (schema?.shape && schema.shape[p]) {
468
- const field = schema.shape[p];
469
- if (field.safeParse) {
470
- const res = field.safeParse(value);
471
- if (!res.success) throw new Error(`Invalid value for ${String(p)}`);
472
- value = res.data ?? value;
473
- }
474
- } else if (schema?.safeParse) {
475
- const next = { ...toPublicObject(tree, id, internalToPublic), [p]: value };
476
- const res = schema.safeParse(next);
477
- if (!res.success) throw new Error(`Invalid value for ${String(p)}`);
478
- const parsed = res.data;
479
- if (parsed && Object.prototype.hasOwnProperty.call(parsed, p)) {
480
- value = parsed[p];
481
- }
482
- }
483
- const rule2 = publicToInternal.get(p);
484
- if (rule2) {
485
- const converted = rule2.toInternal ? rule2.toInternal(value) : value;
486
- tree.setTransientVertexProperty(id, rule2.internalKey, converted);
487
- return true;
488
- }
489
- tree.setTransientVertexProperty(id, p, value);
490
- return true;
491
- },
492
- deleteProperty(_t, p) {
493
- if (typeof p !== "string") return true;
494
- const rule2 = publicToInternal.get(p);
495
- if (rule2) {
496
- tree.setTransientVertexProperty(id, rule2.internalKey, void 0);
497
- return true;
498
- }
499
- tree.setTransientVertexProperty(id, p, void 0);
500
- return true;
501
- }
502
- });
503
- fn(transientProxy);
504
- };
505
- }
506
- if (prop === RESERVED_METHOD_COMMIT_TRANSIENTS) {
507
- return () => {
508
- const entries = tree.getVertexProperties(id);
509
- const currentPublic = schema?.safeParse ? toPublicObject(tree, id, internalToPublic) : void 0;
510
- for (const { key: internalKey, value: overlayValue } of entries) {
511
- const persistentValue = tree.getVertexProperty(id, internalKey, false);
512
- if (overlayValue === persistentValue) continue;
513
- const aliasRule = internalToPublic.get(internalKey);
514
- const publicKey = aliasRule ? aliasRule.publicKey : internalKey;
515
- const publicValue = aliasRule && aliasRule.toPublic ? aliasRule.toPublic(overlayValue) : overlayValue;
516
- let valueToPersistInternal = overlayValue;
517
- if (schema?.shape && schema.shape[publicKey]) {
518
- const field = schema.shape[publicKey];
519
- if (field.safeParse) {
520
- const res = field.safeParse(publicValue);
521
- if (!res.success) throw new Error(`Invalid value for ${String(publicKey)}`);
522
- const coerced = res.data;
523
- const maybeInternal = aliasRule && aliasRule.toInternal ? aliasRule.toInternal(coerced) : coerced;
524
- valueToPersistInternal = maybeInternal;
525
- }
526
- } else if (schema?.safeParse && currentPublic) {
527
- const nextPublic = { ...currentPublic, [publicKey]: publicValue };
528
- const res = schema.safeParse(nextPublic);
529
- if (!res.success) throw new Error("Invalid values for commitTransients");
530
- const parsed = res.data;
531
- const parsedPublic = Object.prototype.hasOwnProperty.call(parsed, publicKey) ? parsed[publicKey] : publicValue;
532
- const maybeInternal = aliasRule && aliasRule.toInternal ? aliasRule.toInternal(parsedPublic) : parsedPublic;
533
- valueToPersistInternal = maybeInternal;
534
- }
535
- tree.setVertexProperty(id, internalKey, valueToPersistInternal);
536
- }
537
- };
538
- }
539
- if (typeof prop === "string") {
540
- if (prop === "$id") return id;
541
- if (prop === "$parentId") return tree.getVertex(id)?.parentId ?? null;
542
- if (prop === "$parent") {
543
- const vertex = tree.getVertex(id);
544
- return vertex?.parent;
545
- }
546
- if (prop === "$children") return tree.getChildren(id);
547
- if (prop === "$childrenIds") return tree.getChildrenIds(id);
548
- if (prop === "$moveTo") {
549
- if (!cachedMethods.has(prop)) {
550
- cachedMethods.set(prop, (parent) => {
551
- const parentId = typeof parent === "object" && parent !== null ? parent.id || parent.$id : parent;
552
- tree.moveVertex(id, parentId);
553
- });
554
- }
555
- return cachedMethods.get(prop);
438
+ const obj = {};
439
+ let isObserverUpdate = false;
440
+ const propsToDefine = /* @__PURE__ */ new Set();
441
+ if (schema?.shape) {
442
+ Object.keys(schema.shape).forEach((key) => propsToDefine.add(key));
443
+ aliases.forEach((alias) => propsToDefine.add(alias.publicKey));
444
+ }
445
+ const localValues = /* @__PURE__ */ new Map();
446
+ propsToDefine.forEach((publicKey) => {
447
+ const rule = publicToInternal.get(publicKey);
448
+ const internalKey = rule?.internalKey ?? publicKey;
449
+ const rawValue = tree.getVertexProperty(id, internalKey);
450
+ const publicValue = rule?.toPublic ? rule.toPublic(rawValue) : rawValue;
451
+ localValues.set(publicKey, publicValue);
452
+ });
453
+ propsToDefine.forEach((publicKey) => {
454
+ const rule = publicToInternal.get(publicKey);
455
+ const storageKey = `_${publicKey}_value`;
456
+ obj[storageKey] = localValues.get(publicKey);
457
+ Object.defineProperty(obj, publicKey, {
458
+ get: function() {
459
+ const internalKey = rule?.internalKey ?? publicKey;
460
+ const rawValue = tree.getVertexProperty(id, internalKey, true);
461
+ const publicValue = rule?.toPublic ? rule.toPublic(rawValue) : rawValue;
462
+ if (this[storageKey] !== publicValue) {
463
+ this[storageKey] = publicValue;
556
464
  }
557
- if (prop === "$delete") {
558
- if (!cachedMethods.has(prop)) {
559
- cachedMethods.set(prop, () => tree.deleteVertex(id));
465
+ return publicValue;
466
+ },
467
+ set: function(value) {
468
+ if (schema?.shape && schema.shape[publicKey]) {
469
+ const field = schema.shape[publicKey];
470
+ if (field.safeParse) {
471
+ const res = field.safeParse(value);
472
+ if (!res.success) throw new Error(`Invalid value for ${publicKey}`);
473
+ value = res.data;
560
474
  }
561
- return cachedMethods.get(prop);
562
475
  }
563
- if (prop === "$observe") {
564
- if (!cachedMethods.has(prop)) {
565
- cachedMethods.set(prop, (listener) => tree.observe(id, listener));
566
- }
567
- return cachedMethods.get(prop);
476
+ this[storageKey] = value;
477
+ if (!isObserverUpdate) {
478
+ const internalKey = rule?.internalKey ?? publicKey;
479
+ const internalValue = rule?.toInternal ? rule.toInternal(value) : value;
480
+ tree.setVertexProperty(id, internalKey, internalValue);
568
481
  }
569
- if (prop === "$observeChildren") {
570
- if (!cachedMethods.has(prop)) {
571
- cachedMethods.set(prop, (listener) => {
572
- return tree.observe(id, (events) => {
573
- if (events.some((e) => e.type === "children")) {
574
- listener(tree.getChildren(id));
575
- }
576
- });
577
- });
482
+ },
483
+ enumerable: true,
484
+ configurable: true
485
+ });
486
+ });
487
+ const cachedMethods = /* @__PURE__ */ new Map();
488
+ const getCachedMethod = (name, factory) => {
489
+ if (!cachedMethods.has(name)) {
490
+ cachedMethods.set(name, factory());
491
+ }
492
+ return cachedMethods.get(name);
493
+ };
494
+ Object.defineProperties(obj, {
495
+ $id: {
496
+ get: () => id,
497
+ set: () => {
498
+ },
499
+ // No-op setter (silently ignore)
500
+ enumerable: false,
501
+ configurable: true
502
+ },
503
+ $parentId: {
504
+ get: () => tree.getVertex(id)?.parentId ?? null,
505
+ set: () => {
506
+ },
507
+ // No-op setter
508
+ enumerable: false,
509
+ configurable: true
510
+ },
511
+ $parent: {
512
+ get: () => tree.getVertex(id)?.parent,
513
+ set: () => {
514
+ },
515
+ // No-op setter
516
+ enumerable: false,
517
+ configurable: true
518
+ },
519
+ $children: {
520
+ get: () => tree.getChildren(id),
521
+ set: () => {
522
+ },
523
+ // No-op setter
524
+ enumerable: false,
525
+ configurable: true
526
+ },
527
+ $childrenIds: {
528
+ get: () => tree.getChildrenIds(id),
529
+ set: () => {
530
+ },
531
+ // No-op setter
532
+ enumerable: false,
533
+ configurable: true
534
+ },
535
+ $moveTo: {
536
+ get: () => getCachedMethod("$moveTo", () => (parent) => {
537
+ const parentId = typeof parent === "object" && parent !== null ? parent.id || parent.$id : parent;
538
+ tree.moveVertex(id, parentId);
539
+ }),
540
+ set: () => {
541
+ },
542
+ // No-op setter
543
+ enumerable: false,
544
+ configurable: true
545
+ },
546
+ $delete: {
547
+ get: () => getCachedMethod("$delete", () => () => tree.deleteVertex(id)),
548
+ set: () => {
549
+ },
550
+ // No-op setter
551
+ enumerable: false,
552
+ configurable: true
553
+ },
554
+ $observe: {
555
+ get: () => getCachedMethod("$observe", () => (listener) => tree.observe(id, listener)),
556
+ set: () => {
557
+ },
558
+ // No-op setter
559
+ enumerable: false,
560
+ configurable: true
561
+ },
562
+ $observeChildren: {
563
+ get: () => getCachedMethod("$observeChildren", () => (listener) => {
564
+ return tree.observe(id, (events) => {
565
+ if (events.some((e) => e.type === "children")) {
566
+ listener(tree.getChildren(id));
578
567
  }
579
- return cachedMethods.get(prop);
580
- }
581
- if (prop === "$newChild") {
582
- if (!cachedMethods.has(prop)) {
583
- cachedMethods.set(prop, (props) => {
584
- const vertex = tree.getVertex(id);
585
- return vertex?.newChild(props);
586
- });
568
+ });
569
+ }),
570
+ set: () => {
571
+ },
572
+ // No-op setter
573
+ enumerable: false,
574
+ configurable: true
575
+ },
576
+ $newChild: {
577
+ get: () => getCachedMethod("$newChild", () => (props) => {
578
+ const vertex = tree.getVertex(id);
579
+ return vertex?.newChild(props);
580
+ }),
581
+ set: () => {
582
+ },
583
+ // No-op setter
584
+ enumerable: false,
585
+ configurable: true
586
+ },
587
+ $newNamedChild: {
588
+ get: () => getCachedMethod("$newNamedChild", () => (name, props) => {
589
+ const vertex = tree.getVertex(id);
590
+ return vertex?.newNamedChild(name, props);
591
+ }),
592
+ set: () => {
593
+ },
594
+ // No-op setter
595
+ enumerable: false,
596
+ configurable: true
597
+ },
598
+ useTransient: {
599
+ value: function(fn) {
600
+ const transientProxy = new Proxy({}, {
601
+ set(_, prop, value) {
602
+ if (typeof prop === "string") {
603
+ const rule = publicToInternal.get(prop);
604
+ const internalKey = rule?.internalKey ?? prop;
605
+ const internalValue = rule?.toInternal ? rule.toInternal(value) : value;
606
+ tree.setTransientVertexProperty(id, internalKey, internalValue);
607
+ }
608
+ return true;
609
+ },
610
+ get(_, prop) {
611
+ if (typeof prop !== "string") return void 0;
612
+ const rule = publicToInternal.get(prop);
613
+ const internalKey = rule?.internalKey ?? prop;
614
+ const rawValue = tree.getVertexProperty(id, internalKey, true);
615
+ return rule?.toPublic ? rule.toPublic(rawValue) : rawValue;
587
616
  }
588
- return cachedMethods.get(prop);
617
+ });
618
+ fn(transientProxy);
619
+ },
620
+ enumerable: false,
621
+ configurable: true
622
+ },
623
+ commitTransients: {
624
+ value: function() {
625
+ tree.commitTransients(id);
626
+ },
627
+ enumerable: false,
628
+ configurable: true
629
+ },
630
+ equals: {
631
+ value: function(other) {
632
+ if (other && typeof other === "object" && "$id" in other) {
633
+ return other.$id === id;
589
634
  }
590
- if (prop === "$newNamedChild") {
591
- if (!cachedMethods.has(prop)) {
592
- cachedMethods.set(prop, (name, props) => {
593
- const vertex = tree.getVertex(id);
594
- return vertex?.newNamedChild(name, props);
595
- });
635
+ return obj === other;
636
+ },
637
+ enumerable: false,
638
+ configurable: true
639
+ }
640
+ });
641
+ tree.observe(id, (events) => {
642
+ isObserverUpdate = true;
643
+ for (const e of events) {
644
+ if (e.type === "property") {
645
+ const propEvent = e;
646
+ const rule = internalToPublic.get(propEvent.key);
647
+ if (rule) {
648
+ const publicKey = rule.publicKey;
649
+ const publicValue = rule.toPublic ? rule.toPublic(propEvent.value) : propEvent.value;
650
+ const storageKey = `_${publicKey}_value`;
651
+ if (storageKey in obj) {
652
+ obj[storageKey] = publicValue;
596
653
  }
597
- return cachedMethods.get(prop);
598
654
  }
599
655
  }
600
- if (typeof prop !== "string") return void 0;
656
+ }
657
+ isObserverUpdate = false;
658
+ });
659
+ if (schema) {
660
+ return obj;
661
+ }
662
+ const proxy = new Proxy(obj, {
663
+ get(target, prop) {
664
+ if (typeof prop !== "string") {
665
+ return target[prop];
666
+ }
667
+ if (prop in target || prop.startsWith("$") || prop === "equals") {
668
+ return target[prop];
669
+ }
601
670
  const rule = publicToInternal.get(prop);
602
671
  if (rule) {
603
- const raw = tree.getVertexProperty(id, rule.internalKey);
604
- return rule.toPublic ? rule.toPublic(raw) : raw;
672
+ const internalKey = rule.internalKey;
673
+ const rawValue2 = tree.getVertexProperty(id, internalKey);
674
+ const result = rule.toPublic ? rule.toPublic(rawValue2) : rawValue2;
675
+ return result;
605
676
  }
606
- return tree.getVertexProperty(id, prop);
677
+ const rawValue = tree.getVertexProperty(id, prop);
678
+ return rawValue;
607
679
  },
608
- set(_target, prop, value) {
609
- if (typeof prop !== "string") return true;
610
- if (prop === RESERVED_METHOD_USE_TRANSIENT || prop === RESERVED_METHOD_COMMIT_TRANSIENTS) {
611
- return true;
612
- }
613
- if (VERTEX_PROPS.includes(prop)) {
680
+ set(target, prop, value) {
681
+ if (typeof prop !== "string") {
682
+ target[prop] = value;
614
683
  return true;
615
684
  }
616
- if (VERTEX_METHODS.includes(prop)) {
685
+ const descriptor = Object.getOwnPropertyDescriptor(target, prop);
686
+ if (descriptor && descriptor.set) {
687
+ target[prop] = value;
617
688
  return true;
618
689
  }
619
- if (schema?.shape && schema.shape[prop]) {
620
- const field = schema.shape[prop];
621
- if (field.safeParse) {
622
- const res = field.safeParse(value);
623
- if (!res.success) throw new Error(`Invalid value for ${String(prop)}`);
624
- value = res.data ?? value;
625
- }
626
- } else if (schema?.safeParse) {
627
- const next = { ...toPublicObject(tree, id, internalToPublic), [prop]: value };
628
- const res = schema.safeParse(next);
629
- if (!res.success) throw new Error(`Invalid value for ${String(prop)}`);
630
- const parsed = res.data;
631
- if (parsed && Object.prototype.hasOwnProperty.call(parsed, prop)) {
632
- value = parsed[prop];
633
- }
634
- }
635
690
  const rule = publicToInternal.get(prop);
636
691
  if (rule) {
637
- const converted = rule.toInternal ? rule.toInternal(value) : value;
638
- tree.setVertexProperty(id, rule.internalKey, converted);
692
+ const internalKey = rule.internalKey;
693
+ const internalValue = rule.toInternal ? rule.toInternal(value) : value;
694
+ tree.setVertexProperty(id, internalKey, internalValue);
639
695
  return true;
640
696
  }
641
697
  tree.setVertexProperty(id, prop, value);
642
698
  return true;
643
699
  },
644
- deleteProperty(_target, prop) {
645
- if (typeof prop !== "string") return true;
646
- if (prop === RESERVED_METHOD_USE_TRANSIENT || prop === RESERVED_METHOD_COMMIT_TRANSIENTS) {
700
+ deleteProperty(target, prop) {
701
+ if (typeof prop !== "string") {
702
+ delete target[prop];
647
703
  return true;
648
704
  }
649
- if (VERTEX_PROPS.includes(prop)) {
650
- return true;
705
+ const storageKey = `_${prop}_value`;
706
+ if (storageKey in target) {
707
+ delete target[storageKey];
651
708
  }
652
- if (VERTEX_METHODS.includes(prop)) {
653
- return true;
709
+ if (prop in target) {
710
+ delete target[prop];
654
711
  }
655
712
  const rule = publicToInternal.get(prop);
656
713
  if (rule) {
@@ -659,27 +716,9 @@ function bindVertex(tree, id, schemaOrOptions) {
659
716
  }
660
717
  tree.setVertexProperty(id, prop, void 0);
661
718
  return true;
662
- },
663
- has(_target, prop) {
664
- if (typeof prop !== "string") return false;
665
- if (schema?.shape && Object.prototype.hasOwnProperty.call(schema.shape, prop)) return true;
666
- if (includeInternalKeys) {
667
- return publicToInternal.has(prop) || internalToPublic.has(prop);
668
- }
669
- return false;
670
- },
671
- ownKeys() {
672
- const keys = /* @__PURE__ */ new Set();
673
- for (const k of Object.keys(schema?.shape ?? {})) keys.add(k);
674
- if (includeInternalKeys) {
675
- for (const rule of aliases) keys.add(rule.internalKey);
676
- }
677
- return Array.from(keys);
678
- },
679
- getOwnPropertyDescriptor() {
680
- return { enumerable: true, configurable: true };
681
719
  }
682
720
  });
721
+ return proxy;
683
722
  }
684
723
 
685
724
  // src/Vertex.ts
@@ -757,6 +796,9 @@ var Vertex = class _Vertex {
757
796
  }
758
797
  this.tree.setTransientVertexProperty(this.id, key, value);
759
798
  }
799
+ commitTransients() {
800
+ this.tree.commitTransients(this.id);
801
+ }
760
802
  setProperties(props) {
761
803
  for (const [key, value] of Object.entries(props)) {
762
804
  this.setProperty(key, value);
@@ -1233,6 +1275,20 @@ var _RepTree = class _RepTree {
1233
1275
  this.localOps.push(op);
1234
1276
  this.applyProperty(op);
1235
1277
  }
1278
+ commitTransients(vertexId) {
1279
+ const vertex = this.state.getVertex(vertexId);
1280
+ if (!vertex) {
1281
+ return;
1282
+ }
1283
+ const transientProps = vertex.getTransientProperties();
1284
+ for (const prop of transientProps) {
1285
+ this.setVertexProperty(vertexId, prop.key, prop.value);
1286
+ }
1287
+ for (const prop of transientProps) {
1288
+ this.transientPropertiesAndTheirOpIds.delete(`${prop.key}@${vertexId}`);
1289
+ }
1290
+ vertex.clearAllTransientProperties();
1291
+ }
1236
1292
  setVertexProperty(vertexId, key, value) {
1237
1293
  this.lamportClock++;
1238
1294
  let opValue;