reptree 0.2.4 → 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.d.cts CHANGED
@@ -18,6 +18,8 @@ declare class VertexState {
18
18
  getAllProperties(includingTransient?: boolean): ReadonlyArray<TreeVertexProperty>;
19
19
  removeProperty(key: string): void;
20
20
  removeTransientProperty(key: string): void;
21
+ getTransientProperties(): ReadonlyArray<TreeVertexProperty>;
22
+ clearAllTransientProperties(): void;
21
23
  }
22
24
 
23
25
  type TreeVertexId = string;
@@ -128,6 +130,19 @@ type BindedVertex<T> = T & {
128
130
  * Promote transient properties to persistent.
129
131
  */
130
132
  commitTransients(): void;
133
+ /** Vertex properties (prefixed with $ to avoid conflicts) */
134
+ $id: string;
135
+ $parentId: string | null;
136
+ $parent: Vertex | undefined;
137
+ $children: Vertex[];
138
+ $childrenIds: string[];
139
+ /** Vertex methods (prefixed with $ to avoid conflicts) */
140
+ $moveTo(parent: Vertex | BindedVertex<any> | string): void;
141
+ $delete(): void;
142
+ $observe(listener: (events: any[]) => void): () => void;
143
+ $observeChildren(listener: (children: Vertex[]) => void): () => void;
144
+ $newChild(props?: Record<string, any> | object | null): Vertex;
145
+ $newNamedChild(name: string, props?: Record<string, any> | object | null): Vertex;
131
146
  };
132
147
  /**
133
148
  * Returns a live object that proxies reads/writes to a vertex.
@@ -160,6 +175,7 @@ declare class Vertex {
160
175
  newNamedChild(name: string, props?: Record<string, VertexPropertyType> | object | null): Vertex;
161
176
  setProperty(key: string, value: VertexPropertyType): void;
162
177
  setTransientProperty(key: string, value: VertexPropertyType): void;
178
+ commitTransients(): void;
163
179
  setProperties(props: Record<string, VertexPropertyType> | object): void;
164
180
  getProperty(key: string, includingTransient?: boolean): VertexPropertyType | undefined;
165
181
  getProperties(): Record<string, VertexPropertyType>;
@@ -236,6 +252,7 @@ declare class RepTree {
236
252
  moveVertex(vertexId: string, parentId: string): void;
237
253
  deleteVertex(vertexId: string): void;
238
254
  setTransientVertexProperty(vertexId: string, key: string, value: VertexPropertyType): void;
255
+ commitTransients(vertexId: string): void;
239
256
  setVertexProperty(vertexId: string, key: string, value: VertexPropertyType): void;
240
257
  setVertexProperties(vertexId: string, props: Record<string, VertexPropertyType> | object): void;
241
258
  getVertexByPath(path: string): Vertex | undefined;
package/dist/index.d.ts CHANGED
@@ -18,6 +18,8 @@ declare class VertexState {
18
18
  getAllProperties(includingTransient?: boolean): ReadonlyArray<TreeVertexProperty>;
19
19
  removeProperty(key: string): void;
20
20
  removeTransientProperty(key: string): void;
21
+ getTransientProperties(): ReadonlyArray<TreeVertexProperty>;
22
+ clearAllTransientProperties(): void;
21
23
  }
22
24
 
23
25
  type TreeVertexId = string;
@@ -128,6 +130,19 @@ type BindedVertex<T> = T & {
128
130
  * Promote transient properties to persistent.
129
131
  */
130
132
  commitTransients(): void;
133
+ /** Vertex properties (prefixed with $ to avoid conflicts) */
134
+ $id: string;
135
+ $parentId: string | null;
136
+ $parent: Vertex | undefined;
137
+ $children: Vertex[];
138
+ $childrenIds: string[];
139
+ /** Vertex methods (prefixed with $ to avoid conflicts) */
140
+ $moveTo(parent: Vertex | BindedVertex<any> | string): void;
141
+ $delete(): void;
142
+ $observe(listener: (events: any[]) => void): () => void;
143
+ $observeChildren(listener: (children: Vertex[]) => void): () => void;
144
+ $newChild(props?: Record<string, any> | object | null): Vertex;
145
+ $newNamedChild(name: string, props?: Record<string, any> | object | null): Vertex;
131
146
  };
132
147
  /**
133
148
  * Returns a live object that proxies reads/writes to a vertex.
@@ -160,6 +175,7 @@ declare class Vertex {
160
175
  newNamedChild(name: string, props?: Record<string, VertexPropertyType> | object | null): Vertex;
161
176
  setProperty(key: string, value: VertexPropertyType): void;
162
177
  setTransientProperty(key: string, value: VertexPropertyType): void;
178
+ commitTransients(): void;
163
179
  setProperties(props: Record<string, VertexPropertyType> | object): void;
164
180
  getProperty(key: string, includingTransient?: boolean): VertexPropertyType | undefined;
165
181
  getProperties(): Record<string, VertexPropertyType>;
@@ -236,6 +252,7 @@ declare class RepTree {
236
252
  moveVertex(vertexId: string, parentId: string): void;
237
253
  deleteVertex(vertexId: string): void;
238
254
  setTransientVertexProperty(vertexId: string, key: string, value: VertexPropertyType): void;
255
+ commitTransients(vertexId: string): void;
239
256
  setVertexProperty(vertexId: string, key: string, value: VertexPropertyType): void;
240
257
  setVertexProperties(vertexId: string, props: Record<string, VertexPropertyType> | object): void;
241
258
  getVertexByPath(path: string): Vertex | undefined;
package/dist/index.js CHANGED
@@ -137,6 +137,12 @@ var VertexState = class {
137
137
  removeTransientProperty(key) {
138
138
  this.transientProperties = this.transientProperties.filter((p) => p.key !== key);
139
139
  }
140
+ getTransientProperties() {
141
+ return this.transientProperties;
142
+ }
143
+ clearAllTransientProperties() {
144
+ this.transientProperties = [];
145
+ }
140
146
  };
141
147
 
142
148
  // src/TreeState.ts
@@ -373,159 +379,286 @@ function buildAliasMaps(aliases) {
373
379
  }
374
380
  return { publicToInternal, internalToPublic };
375
381
  }
376
- function toPublicObject(tree, id, internalToPublic) {
377
- const obj = {};
378
- for (const { key, value } of tree.getVertexProperties(id)) {
379
- const rule = internalToPublic.get(key);
380
- if (rule) {
381
- const converted = rule.toPublic ? rule.toPublic(value) : value;
382
- obj[rule.publicKey] = converted;
383
- } else {
384
- obj[key] = value;
385
- }
386
- }
387
- return obj;
388
- }
389
- var RESERVED_METHOD_USE_TRANSIENT = "useTransient";
390
- var RESERVED_METHOD_COMMIT_TRANSIENTS = "commitTransients";
391
382
  function bindVertex(tree, id, schemaOrOptions) {
392
383
  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"));
393
384
  const options = isOptions ? schemaOrOptions : { schema: schemaOrOptions };
394
385
  const schema = options.schema;
395
386
  const aliases = options.aliases ?? defaultAliases;
396
- const includeInternalKeys = options.includeInternalKeys ?? false;
397
387
  const { publicToInternal, internalToPublic } = buildAliasMaps(aliases);
398
- return new Proxy({}, {
399
- get(_target, prop) {
400
- if (prop === RESERVED_METHOD_USE_TRANSIENT) {
401
- return (fn) => {
402
- const transientProxy = new Proxy({}, {
403
- get(_t, p) {
404
- if (typeof p !== "string") return void 0;
405
- const rule2 = publicToInternal.get(p);
406
- if (rule2) {
407
- const raw = tree.getVertexProperty(id, rule2.internalKey);
408
- return rule2.toPublic ? rule2.toPublic(raw) : raw;
409
- }
410
- return tree.getVertexProperty(id, p);
411
- },
412
- set(_t, p, value) {
413
- if (typeof p !== "string") return true;
414
- if (schema?.shape && schema.shape[p]) {
415
- const field = schema.shape[p];
416
- if (field.safeParse) {
417
- const res = field.safeParse(value);
418
- if (!res.success) throw new Error(`Invalid value for ${String(p)}`);
419
- value = res.data ?? value;
420
- }
421
- } else if (schema?.safeParse) {
422
- const next = { ...toPublicObject(tree, id, internalToPublic), [p]: value };
423
- const res = schema.safeParse(next);
424
- if (!res.success) throw new Error(`Invalid value for ${String(p)}`);
425
- const parsed = res.data;
426
- if (parsed && Object.prototype.hasOwnProperty.call(parsed, p)) {
427
- value = parsed[p];
428
- }
429
- }
430
- const rule2 = publicToInternal.get(p);
431
- if (rule2) {
432
- const converted = rule2.toInternal ? rule2.toInternal(value) : value;
433
- tree.setTransientVertexProperty(id, rule2.internalKey, converted);
434
- return true;
435
- }
436
- tree.setTransientVertexProperty(id, p, value);
437
- return true;
438
- },
439
- deleteProperty(_t, p) {
440
- if (typeof p !== "string") return true;
441
- const rule2 = publicToInternal.get(p);
442
- if (rule2) {
443
- tree.setTransientVertexProperty(id, rule2.internalKey, void 0);
444
- return true;
445
- }
446
- tree.setTransientVertexProperty(id, p, void 0);
447
- return true;
448
- }
449
- });
450
- fn(transientProxy);
451
- };
452
- }
453
- if (prop === RESERVED_METHOD_COMMIT_TRANSIENTS) {
454
- return () => {
455
- const entries = tree.getVertexProperties(id);
456
- const currentPublic = schema?.safeParse ? toPublicObject(tree, id, internalToPublic) : void 0;
457
- for (const { key: internalKey, value: overlayValue } of entries) {
458
- const persistentValue = tree.getVertexProperty(id, internalKey, false);
459
- if (overlayValue === persistentValue) continue;
460
- const aliasRule = internalToPublic.get(internalKey);
461
- const publicKey = aliasRule ? aliasRule.publicKey : internalKey;
462
- const publicValue = aliasRule && aliasRule.toPublic ? aliasRule.toPublic(overlayValue) : overlayValue;
463
- let valueToPersistInternal = overlayValue;
464
- if (schema?.shape && schema.shape[publicKey]) {
465
- const field = schema.shape[publicKey];
466
- if (field.safeParse) {
467
- const res = field.safeParse(publicValue);
468
- if (!res.success) throw new Error(`Invalid value for ${String(publicKey)}`);
469
- const coerced = res.data;
470
- const maybeInternal = aliasRule && aliasRule.toInternal ? aliasRule.toInternal(coerced) : coerced;
471
- valueToPersistInternal = maybeInternal;
472
- }
473
- } else if (schema?.safeParse && currentPublic) {
474
- const nextPublic = { ...currentPublic, [publicKey]: publicValue };
475
- const res = schema.safeParse(nextPublic);
476
- if (!res.success) throw new Error("Invalid values for commitTransients");
477
- const parsed = res.data;
478
- const parsedPublic = Object.prototype.hasOwnProperty.call(parsed, publicKey) ? parsed[publicKey] : publicValue;
479
- const maybeInternal = aliasRule && aliasRule.toInternal ? aliasRule.toInternal(parsedPublic) : parsedPublic;
480
- valueToPersistInternal = maybeInternal;
388
+ const obj = {};
389
+ let isObserverUpdate = false;
390
+ const propsToDefine = /* @__PURE__ */ new Set();
391
+ if (schema?.shape) {
392
+ Object.keys(schema.shape).forEach((key) => propsToDefine.add(key));
393
+ aliases.forEach((alias) => propsToDefine.add(alias.publicKey));
394
+ }
395
+ const localValues = /* @__PURE__ */ new Map();
396
+ propsToDefine.forEach((publicKey) => {
397
+ const rule = publicToInternal.get(publicKey);
398
+ const internalKey = rule?.internalKey ?? publicKey;
399
+ const rawValue = tree.getVertexProperty(id, internalKey);
400
+ const publicValue = rule?.toPublic ? rule.toPublic(rawValue) : rawValue;
401
+ localValues.set(publicKey, publicValue);
402
+ });
403
+ propsToDefine.forEach((publicKey) => {
404
+ const rule = publicToInternal.get(publicKey);
405
+ const storageKey = `_${publicKey}_value`;
406
+ obj[storageKey] = localValues.get(publicKey);
407
+ Object.defineProperty(obj, publicKey, {
408
+ get: function() {
409
+ const internalKey = rule?.internalKey ?? publicKey;
410
+ const rawValue = tree.getVertexProperty(id, internalKey, true);
411
+ const publicValue = rule?.toPublic ? rule.toPublic(rawValue) : rawValue;
412
+ if (this[storageKey] !== publicValue) {
413
+ this[storageKey] = publicValue;
414
+ }
415
+ return publicValue;
416
+ },
417
+ set: function(value) {
418
+ if (schema?.shape && schema.shape[publicKey]) {
419
+ const field = schema.shape[publicKey];
420
+ if (field.safeParse) {
421
+ const res = field.safeParse(value);
422
+ if (!res.success) throw new Error(`Invalid value for ${publicKey}`);
423
+ value = res.data;
424
+ }
425
+ }
426
+ this[storageKey] = value;
427
+ if (!isObserverUpdate) {
428
+ const internalKey = rule?.internalKey ?? publicKey;
429
+ const internalValue = rule?.toInternal ? rule.toInternal(value) : value;
430
+ tree.setVertexProperty(id, internalKey, internalValue);
431
+ }
432
+ },
433
+ enumerable: true,
434
+ configurable: true
435
+ });
436
+ });
437
+ const cachedMethods = /* @__PURE__ */ new Map();
438
+ const getCachedMethod = (name, factory) => {
439
+ if (!cachedMethods.has(name)) {
440
+ cachedMethods.set(name, factory());
441
+ }
442
+ return cachedMethods.get(name);
443
+ };
444
+ Object.defineProperties(obj, {
445
+ $id: {
446
+ get: () => id,
447
+ set: () => {
448
+ },
449
+ // No-op setter (silently ignore)
450
+ enumerable: false,
451
+ configurable: true
452
+ },
453
+ $parentId: {
454
+ get: () => tree.getVertex(id)?.parentId ?? null,
455
+ set: () => {
456
+ },
457
+ // No-op setter
458
+ enumerable: false,
459
+ configurable: true
460
+ },
461
+ $parent: {
462
+ get: () => tree.getVertex(id)?.parent,
463
+ set: () => {
464
+ },
465
+ // No-op setter
466
+ enumerable: false,
467
+ configurable: true
468
+ },
469
+ $children: {
470
+ get: () => tree.getChildren(id),
471
+ set: () => {
472
+ },
473
+ // No-op setter
474
+ enumerable: false,
475
+ configurable: true
476
+ },
477
+ $childrenIds: {
478
+ get: () => tree.getChildrenIds(id),
479
+ set: () => {
480
+ },
481
+ // No-op setter
482
+ enumerable: false,
483
+ configurable: true
484
+ },
485
+ $moveTo: {
486
+ get: () => getCachedMethod("$moveTo", () => (parent) => {
487
+ const parentId = typeof parent === "object" && parent !== null ? parent.id || parent.$id : parent;
488
+ tree.moveVertex(id, parentId);
489
+ }),
490
+ set: () => {
491
+ },
492
+ // No-op setter
493
+ enumerable: false,
494
+ configurable: true
495
+ },
496
+ $delete: {
497
+ get: () => getCachedMethod("$delete", () => () => tree.deleteVertex(id)),
498
+ set: () => {
499
+ },
500
+ // No-op setter
501
+ enumerable: false,
502
+ configurable: true
503
+ },
504
+ $observe: {
505
+ get: () => getCachedMethod("$observe", () => (listener) => tree.observe(id, listener)),
506
+ set: () => {
507
+ },
508
+ // No-op setter
509
+ enumerable: false,
510
+ configurable: true
511
+ },
512
+ $observeChildren: {
513
+ get: () => getCachedMethod("$observeChildren", () => (listener) => {
514
+ return tree.observe(id, (events) => {
515
+ if (events.some((e) => e.type === "children")) {
516
+ listener(tree.getChildren(id));
517
+ }
518
+ });
519
+ }),
520
+ set: () => {
521
+ },
522
+ // No-op setter
523
+ enumerable: false,
524
+ configurable: true
525
+ },
526
+ $newChild: {
527
+ get: () => getCachedMethod("$newChild", () => (props) => {
528
+ const vertex = tree.getVertex(id);
529
+ return vertex?.newChild(props);
530
+ }),
531
+ set: () => {
532
+ },
533
+ // No-op setter
534
+ enumerable: false,
535
+ configurable: true
536
+ },
537
+ $newNamedChild: {
538
+ get: () => getCachedMethod("$newNamedChild", () => (name, props) => {
539
+ const vertex = tree.getVertex(id);
540
+ return vertex?.newNamedChild(name, props);
541
+ }),
542
+ set: () => {
543
+ },
544
+ // No-op setter
545
+ enumerable: false,
546
+ configurable: true
547
+ },
548
+ useTransient: {
549
+ value: function(fn) {
550
+ const transientProxy = new Proxy({}, {
551
+ set(_, prop, value) {
552
+ if (typeof prop === "string") {
553
+ const rule = publicToInternal.get(prop);
554
+ const internalKey = rule?.internalKey ?? prop;
555
+ const internalValue = rule?.toInternal ? rule.toInternal(value) : value;
556
+ tree.setTransientVertexProperty(id, internalKey, internalValue);
481
557
  }
482
- tree.setVertexProperty(id, internalKey, valueToPersistInternal);
558
+ return true;
559
+ },
560
+ get(_, prop) {
561
+ if (typeof prop !== "string") return void 0;
562
+ const rule = publicToInternal.get(prop);
563
+ const internalKey = rule?.internalKey ?? prop;
564
+ const rawValue = tree.getVertexProperty(id, internalKey, true);
565
+ return rule?.toPublic ? rule.toPublic(rawValue) : rawValue;
483
566
  }
484
- };
567
+ });
568
+ fn(transientProxy);
569
+ },
570
+ enumerable: false,
571
+ configurable: true
572
+ },
573
+ commitTransients: {
574
+ value: function() {
575
+ tree.commitTransients(id);
576
+ },
577
+ enumerable: false,
578
+ configurable: true
579
+ },
580
+ equals: {
581
+ value: function(other) {
582
+ if (other && typeof other === "object" && "$id" in other) {
583
+ return other.$id === id;
584
+ }
585
+ return obj === other;
586
+ },
587
+ enumerable: false,
588
+ configurable: true
589
+ }
590
+ });
591
+ tree.observe(id, (events) => {
592
+ isObserverUpdate = true;
593
+ for (const e of events) {
594
+ if (e.type === "property") {
595
+ const propEvent = e;
596
+ const rule = internalToPublic.get(propEvent.key);
597
+ if (rule) {
598
+ const publicKey = rule.publicKey;
599
+ const publicValue = rule.toPublic ? rule.toPublic(propEvent.value) : propEvent.value;
600
+ const storageKey = `_${publicKey}_value`;
601
+ if (storageKey in obj) {
602
+ obj[storageKey] = publicValue;
603
+ }
604
+ }
605
+ }
606
+ }
607
+ isObserverUpdate = false;
608
+ });
609
+ if (schema) {
610
+ return obj;
611
+ }
612
+ const proxy = new Proxy(obj, {
613
+ get(target, prop) {
614
+ if (typeof prop !== "string") {
615
+ return target[prop];
616
+ }
617
+ if (prop in target || prop.startsWith("$") || prop === "equals") {
618
+ return target[prop];
485
619
  }
486
- if (typeof prop !== "string") return void 0;
487
620
  const rule = publicToInternal.get(prop);
488
621
  if (rule) {
489
- const raw = tree.getVertexProperty(id, rule.internalKey);
490
- return rule.toPublic ? rule.toPublic(raw) : raw;
622
+ const internalKey = rule.internalKey;
623
+ const rawValue2 = tree.getVertexProperty(id, internalKey);
624
+ const result = rule.toPublic ? rule.toPublic(rawValue2) : rawValue2;
625
+ return result;
491
626
  }
492
- return tree.getVertexProperty(id, prop);
627
+ const rawValue = tree.getVertexProperty(id, prop);
628
+ return rawValue;
493
629
  },
494
- set(_target, prop, value) {
495
- if (typeof prop !== "string") return true;
496
- if (prop === RESERVED_METHOD_USE_TRANSIENT || prop === RESERVED_METHOD_COMMIT_TRANSIENTS) {
630
+ set(target, prop, value) {
631
+ if (typeof prop !== "string") {
632
+ target[prop] = value;
497
633
  return true;
498
634
  }
499
- if (schema?.shape && schema.shape[prop]) {
500
- const field = schema.shape[prop];
501
- if (field.safeParse) {
502
- const res = field.safeParse(value);
503
- if (!res.success) throw new Error(`Invalid value for ${String(prop)}`);
504
- value = res.data ?? value;
505
- }
506
- } else if (schema?.safeParse) {
507
- const next = { ...toPublicObject(tree, id, internalToPublic), [prop]: value };
508
- const res = schema.safeParse(next);
509
- if (!res.success) throw new Error(`Invalid value for ${String(prop)}`);
510
- const parsed = res.data;
511
- if (parsed && Object.prototype.hasOwnProperty.call(parsed, prop)) {
512
- value = parsed[prop];
513
- }
635
+ const descriptor = Object.getOwnPropertyDescriptor(target, prop);
636
+ if (descriptor && descriptor.set) {
637
+ target[prop] = value;
638
+ return true;
514
639
  }
515
640
  const rule = publicToInternal.get(prop);
516
641
  if (rule) {
517
- const converted = rule.toInternal ? rule.toInternal(value) : value;
518
- tree.setVertexProperty(id, rule.internalKey, converted);
642
+ const internalKey = rule.internalKey;
643
+ const internalValue = rule.toInternal ? rule.toInternal(value) : value;
644
+ tree.setVertexProperty(id, internalKey, internalValue);
519
645
  return true;
520
646
  }
521
647
  tree.setVertexProperty(id, prop, value);
522
648
  return true;
523
649
  },
524
- deleteProperty(_target, prop) {
525
- if (typeof prop !== "string") return true;
526
- if (prop === RESERVED_METHOD_USE_TRANSIENT || prop === RESERVED_METHOD_COMMIT_TRANSIENTS) {
650
+ deleteProperty(target, prop) {
651
+ if (typeof prop !== "string") {
652
+ delete target[prop];
527
653
  return true;
528
654
  }
655
+ const storageKey = `_${prop}_value`;
656
+ if (storageKey in target) {
657
+ delete target[storageKey];
658
+ }
659
+ if (prop in target) {
660
+ delete target[prop];
661
+ }
529
662
  const rule = publicToInternal.get(prop);
530
663
  if (rule) {
531
664
  tree.setVertexProperty(id, rule.internalKey, void 0);
@@ -533,27 +666,9 @@ function bindVertex(tree, id, schemaOrOptions) {
533
666
  }
534
667
  tree.setVertexProperty(id, prop, void 0);
535
668
  return true;
536
- },
537
- has(_target, prop) {
538
- if (typeof prop !== "string") return false;
539
- if (schema?.shape && Object.prototype.hasOwnProperty.call(schema.shape, prop)) return true;
540
- if (includeInternalKeys) {
541
- return publicToInternal.has(prop) || internalToPublic.has(prop);
542
- }
543
- return false;
544
- },
545
- ownKeys() {
546
- const keys = /* @__PURE__ */ new Set();
547
- for (const k of Object.keys(schema?.shape ?? {})) keys.add(k);
548
- if (includeInternalKeys) {
549
- for (const rule of aliases) keys.add(rule.internalKey);
550
- }
551
- return Array.from(keys);
552
- },
553
- getOwnPropertyDescriptor() {
554
- return { enumerable: true, configurable: true };
555
669
  }
556
670
  });
671
+ return proxy;
557
672
  }
558
673
 
559
674
  // src/Vertex.ts
@@ -631,6 +746,9 @@ var Vertex = class _Vertex {
631
746
  }
632
747
  this.tree.setTransientVertexProperty(this.id, key, value);
633
748
  }
749
+ commitTransients() {
750
+ this.tree.commitTransients(this.id);
751
+ }
634
752
  setProperties(props) {
635
753
  for (const [key, value] of Object.entries(props)) {
636
754
  this.setProperty(key, value);
@@ -1107,6 +1225,20 @@ var _RepTree = class _RepTree {
1107
1225
  this.localOps.push(op);
1108
1226
  this.applyProperty(op);
1109
1227
  }
1228
+ commitTransients(vertexId) {
1229
+ const vertex = this.state.getVertex(vertexId);
1230
+ if (!vertex) {
1231
+ return;
1232
+ }
1233
+ const transientProps = vertex.getTransientProperties();
1234
+ for (const prop of transientProps) {
1235
+ this.setVertexProperty(vertexId, prop.key, prop.value);
1236
+ }
1237
+ for (const prop of transientProps) {
1238
+ this.transientPropertiesAndTheirOpIds.delete(`${prop.key}@${vertexId}`);
1239
+ }
1240
+ vertex.clearAllTransientProperties();
1241
+ }
1110
1242
  setVertexProperty(vertexId, key, value) {
1111
1243
  this.lamportClock++;
1112
1244
  let opValue;