reptree 0.5.0 → 0.7.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/README.md +3 -3
- package/dist/index.cjs +118 -80
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -19
- package/dist/index.d.ts +11 -19
- package/dist/index.js +118 -79
- package/dist/index.js.map +1 -1
- package/package.json +2 -4
package/README.md
CHANGED
|
@@ -33,9 +33,10 @@ const qa = company.newNamedChild("qa");
|
|
|
33
33
|
// Create a vertex in another vertex
|
|
34
34
|
const alice = qa.newChild();
|
|
35
35
|
|
|
36
|
-
// Set properties
|
|
36
|
+
// Set properties (supports any JSON-serializable values)
|
|
37
37
|
alice.setProperty("name", "Alice");
|
|
38
38
|
alice.setProperty("age", 32);
|
|
39
|
+
alice.setProperty("meta", { department: "QA", skills: ["cypress", "playwright"], flags: { lead: false } });
|
|
39
40
|
|
|
40
41
|
// Move the vertex inside a different vertex
|
|
41
42
|
alice.moveTo(devs);
|
|
@@ -89,8 +90,7 @@ const logoFile = imagesFolder.newNamedChild("logo.png");
|
|
|
89
90
|
logoFile.setProperties({
|
|
90
91
|
type: "file",
|
|
91
92
|
size: 15360,
|
|
92
|
-
dimensions: "512x512",
|
|
93
|
-
format: "png",
|
|
93
|
+
meta: { dimensions: "512x512", format: "png" },
|
|
94
94
|
s3Path: "s3://my-bucket/images/logo.png",
|
|
95
95
|
});
|
|
96
96
|
|
package/dist/index.cjs
CHANGED
|
@@ -26,7 +26,6 @@ __export(index_exports, {
|
|
|
26
26
|
Vertex: () => Vertex,
|
|
27
27
|
VertexState: () => VertexState,
|
|
28
28
|
bindVertex: () => bindVertex,
|
|
29
|
-
defaultAliases: () => defaultAliases,
|
|
30
29
|
isAnyPropertyOp: () => isAnyPropertyOp,
|
|
31
30
|
isMoveVertexOp: () => isMoveVertexOp,
|
|
32
31
|
newMoveVertexOp: () => newMoveVertexOp,
|
|
@@ -355,7 +354,7 @@ var TreeState = class {
|
|
|
355
354
|
const vertex = this.getVertex(vertexId);
|
|
356
355
|
if (vertex) {
|
|
357
356
|
for (const prop of vertex.getAllProperties()) {
|
|
358
|
-
if (prop.key === "
|
|
357
|
+
if (prop.key === "name") {
|
|
359
358
|
vertexName = prop.value;
|
|
360
359
|
}
|
|
361
360
|
const propPrefix = indent + (isLast ? " " : "\u2502 ") + "\u2022 ";
|
|
@@ -368,8 +367,8 @@ var TreeState = class {
|
|
|
368
367
|
const sortedChildren = [...children].sort((a, b) => {
|
|
369
368
|
const vertexA = this.getVertex(a);
|
|
370
369
|
const vertexB = this.getVertex(b);
|
|
371
|
-
const nameA = vertexA?.getProperty("
|
|
372
|
-
const nameB = vertexB?.getProperty("
|
|
370
|
+
const nameA = vertexA?.getProperty("name");
|
|
371
|
+
const nameB = vertexB?.getProperty("name");
|
|
373
372
|
if (nameA && nameB) {
|
|
374
373
|
return nameA.localeCompare(nameB);
|
|
375
374
|
}
|
|
@@ -386,37 +385,17 @@ var TreeState = class {
|
|
|
386
385
|
}
|
|
387
386
|
};
|
|
388
387
|
|
|
389
|
-
// src/uuid.ts
|
|
388
|
+
// src/utils/uuid.ts
|
|
390
389
|
var removeDashes = (guid) => guid.replace(/-/g, "");
|
|
391
390
|
function uuid() {
|
|
392
391
|
return removeDashes(crypto.randomUUID());
|
|
393
392
|
}
|
|
394
393
|
|
|
395
394
|
// src/reactive.ts
|
|
396
|
-
var defaultAliases = [
|
|
397
|
-
{ publicKey: "name", internalKey: "_n" },
|
|
398
|
-
{
|
|
399
|
-
publicKey: "createdAt",
|
|
400
|
-
internalKey: "_c",
|
|
401
|
-
toPublic: (v) => typeof v === "string" ? new Date(v) : v,
|
|
402
|
-
toInternal: (v) => v instanceof Date ? v.toISOString() : v
|
|
403
|
-
}
|
|
404
|
-
];
|
|
405
|
-
function buildAliasMaps(aliases) {
|
|
406
|
-
const publicToInternal = /* @__PURE__ */ new Map();
|
|
407
|
-
const internalToPublic = /* @__PURE__ */ new Map();
|
|
408
|
-
for (const rule of aliases) {
|
|
409
|
-
publicToInternal.set(rule.publicKey, rule);
|
|
410
|
-
internalToPublic.set(rule.internalKey, rule);
|
|
411
|
-
}
|
|
412
|
-
return { publicToInternal, internalToPublic };
|
|
413
|
-
}
|
|
414
395
|
function bindVertex(tree, id, schemaOrOptions) {
|
|
415
|
-
const isOptions = typeof schemaOrOptions === "object" && schemaOrOptions !== null && (Object.prototype.hasOwnProperty.call(schemaOrOptions, "
|
|
396
|
+
const isOptions = typeof schemaOrOptions === "object" && schemaOrOptions !== null && (Object.prototype.hasOwnProperty.call(schemaOrOptions, "includeInternalKeys") || Object.prototype.hasOwnProperty.call(schemaOrOptions, "schema"));
|
|
416
397
|
const options = isOptions ? schemaOrOptions : { schema: schemaOrOptions };
|
|
417
398
|
const schema = options.schema;
|
|
418
|
-
const aliases = options.aliases ?? defaultAliases;
|
|
419
|
-
const { publicToInternal } = buildAliasMaps(aliases);
|
|
420
399
|
const obj = {};
|
|
421
400
|
Object.defineProperties(obj, {
|
|
422
401
|
$vertex: { get: () => tree.getVertex(id), enumerable: false, configurable: true },
|
|
@@ -453,19 +432,14 @@ function bindVertex(tree, id, schemaOrOptions) {
|
|
|
453
432
|
const transientProxy = new Proxy({}, {
|
|
454
433
|
set(_, prop, value) {
|
|
455
434
|
if (typeof prop === "string") {
|
|
456
|
-
|
|
457
|
-
const internalKey = rule?.internalKey ?? prop;
|
|
458
|
-
const internalValue = rule?.toInternal ? rule.toInternal(value) : value;
|
|
459
|
-
tree.setTransientVertexProperty(id, internalKey, internalValue);
|
|
435
|
+
tree.setTransientVertexProperty(id, prop, value);
|
|
460
436
|
}
|
|
461
437
|
return true;
|
|
462
438
|
},
|
|
463
439
|
get(_, prop) {
|
|
464
440
|
if (typeof prop !== "string") return void 0;
|
|
465
|
-
const
|
|
466
|
-
|
|
467
|
-
const rawValue = tree.getVertexProperty(id, internalKey, true);
|
|
468
|
-
return rule?.toPublic ? rule.toPublic(rawValue) : rawValue;
|
|
441
|
+
const rawValue = tree.getVertexProperty(id, prop, true);
|
|
442
|
+
return rawValue;
|
|
469
443
|
}
|
|
470
444
|
});
|
|
471
445
|
fn(transientProxy);
|
|
@@ -495,10 +469,8 @@ function bindVertex(tree, id, schemaOrOptions) {
|
|
|
495
469
|
if (prop in target) {
|
|
496
470
|
return Reflect.get(target, prop, receiver);
|
|
497
471
|
}
|
|
498
|
-
const
|
|
499
|
-
|
|
500
|
-
const rawValue = tree.getVertexProperty(id, internalKey, true);
|
|
501
|
-
return rule?.toPublic ? rule.toPublic(rawValue) : rawValue;
|
|
472
|
+
const rawValue = tree.getVertexProperty(id, prop, true);
|
|
473
|
+
return rawValue;
|
|
502
474
|
},
|
|
503
475
|
set(target, prop, value) {
|
|
504
476
|
if (typeof prop !== "string") {
|
|
@@ -512,19 +484,14 @@ function bindVertex(tree, id, schemaOrOptions) {
|
|
|
512
484
|
value = res.data;
|
|
513
485
|
}
|
|
514
486
|
}
|
|
515
|
-
|
|
516
|
-
const internalKey = rule?.internalKey ?? prop;
|
|
517
|
-
const internalValue = rule?.toInternal ? rule.toInternal(value) : value;
|
|
518
|
-
tree.setVertexProperty(id, internalKey, internalValue);
|
|
487
|
+
tree.setVertexProperty(id, prop, value);
|
|
519
488
|
return true;
|
|
520
489
|
},
|
|
521
490
|
deleteProperty(_target, prop) {
|
|
522
491
|
if (typeof prop !== "string") {
|
|
523
492
|
return true;
|
|
524
493
|
}
|
|
525
|
-
|
|
526
|
-
const internalKey = rule?.internalKey ?? prop;
|
|
527
|
-
tree.setVertexProperty(id, internalKey, void 0);
|
|
494
|
+
tree.setVertexProperty(id, prop, void 0);
|
|
528
495
|
return true;
|
|
529
496
|
}
|
|
530
497
|
});
|
|
@@ -541,10 +508,10 @@ var Vertex = class _Vertex {
|
|
|
541
508
|
return this.state.id;
|
|
542
509
|
}
|
|
543
510
|
get name() {
|
|
544
|
-
return this.getProperty("
|
|
511
|
+
return this.getProperty("name");
|
|
545
512
|
}
|
|
546
513
|
set name(name) {
|
|
547
|
-
this.tree.setVertexProperty(this.id, "
|
|
514
|
+
this.tree.setVertexProperty(this.id, "name", name);
|
|
548
515
|
}
|
|
549
516
|
get createdAt() {
|
|
550
517
|
const createdAt = this.getProperty("_c");
|
|
@@ -588,7 +555,7 @@ var Vertex = class _Vertex {
|
|
|
588
555
|
if (props && typeof props === "object" && "children" in props) {
|
|
589
556
|
throw new Error("Passing children inside props is not supported at the moment");
|
|
590
557
|
}
|
|
591
|
-
const normalized = _Vertex.normalizePropsForCreation(props
|
|
558
|
+
const normalized = _Vertex.normalizePropsForCreation(props);
|
|
592
559
|
return this.tree.newNamedVertex(this.id, name, normalized);
|
|
593
560
|
}
|
|
594
561
|
setProperty(key, value) {
|
|
@@ -664,30 +631,35 @@ var Vertex = class _Vertex {
|
|
|
664
631
|
}
|
|
665
632
|
/**
|
|
666
633
|
* Normalizes an input props object for vertex creation:
|
|
667
|
-
* - Aliases name -> _n, createdAt -> _c (Date -> ISO string)
|
|
668
634
|
* - Filters unsupported field types with a console warning
|
|
669
635
|
* - When a name param is provided to newNamedChild, ignores conflicting name in props
|
|
670
636
|
*/
|
|
671
|
-
static normalizePropsForCreation(props
|
|
637
|
+
static normalizePropsForCreation(props) {
|
|
672
638
|
if (!props) return null;
|
|
673
639
|
const input = props;
|
|
674
640
|
const out = {};
|
|
675
641
|
const skipped = [];
|
|
642
|
+
const isJsonValue2 = (v) => {
|
|
643
|
+
if (v === null) return true;
|
|
644
|
+
const t = typeof v;
|
|
645
|
+
if (t === "string" || t === "number" || t === "boolean") return true;
|
|
646
|
+
if (Array.isArray(v)) return v.every(isJsonValue2);
|
|
647
|
+
if (t === "object") {
|
|
648
|
+
const proto = Object.getPrototypeOf(v);
|
|
649
|
+
if (proto !== Object.prototype && proto !== null) return false;
|
|
650
|
+
for (const val of Object.values(v)) {
|
|
651
|
+
if (!isJsonValue2(val)) return false;
|
|
652
|
+
}
|
|
653
|
+
return true;
|
|
654
|
+
}
|
|
655
|
+
return false;
|
|
656
|
+
};
|
|
676
657
|
for (const [rawKey, rawValue] of Object.entries(input)) {
|
|
677
658
|
if (rawValue === void 0) {
|
|
678
659
|
continue;
|
|
679
660
|
}
|
|
680
661
|
if (rawKey === "children") continue;
|
|
681
662
|
let key = rawKey;
|
|
682
|
-
if (rawKey === "name") {
|
|
683
|
-
if (explicitName !== void 0) {
|
|
684
|
-
console.warn('newNamedChild: "name" in props is ignored because a name argument was provided');
|
|
685
|
-
continue;
|
|
686
|
-
}
|
|
687
|
-
key = "_n";
|
|
688
|
-
} else if (rawKey === "createdAt") {
|
|
689
|
-
key = "_c";
|
|
690
|
-
}
|
|
691
663
|
let value = rawValue;
|
|
692
664
|
if (key === "_c") {
|
|
693
665
|
if (value instanceof Date) {
|
|
@@ -698,23 +670,14 @@ var Vertex = class _Vertex {
|
|
|
698
670
|
continue;
|
|
699
671
|
}
|
|
700
672
|
}
|
|
701
|
-
|
|
702
|
-
if (Array.isArray(value)) {
|
|
703
|
-
if (!value.every(isPrimitive)) {
|
|
704
|
-
skipped.push(rawKey);
|
|
705
|
-
continue;
|
|
706
|
-
}
|
|
707
|
-
} else if (typeof value === "object" && value !== null) {
|
|
708
|
-
skipped.push(rawKey);
|
|
709
|
-
continue;
|
|
710
|
-
} else if (!isPrimitive(value)) {
|
|
673
|
+
if (!isJsonValue2(value)) {
|
|
711
674
|
skipped.push(rawKey);
|
|
712
675
|
continue;
|
|
713
676
|
}
|
|
714
677
|
out[key] = value;
|
|
715
678
|
}
|
|
716
679
|
if (skipped.length > 0) {
|
|
717
|
-
|
|
680
|
+
throw new Error(`Unsupported property types for keys: ${skipped.join(", ")}`);
|
|
718
681
|
}
|
|
719
682
|
return Object.keys(out).length > 0 ? out : null;
|
|
720
683
|
}
|
|
@@ -905,6 +868,61 @@ var StateVector = class _StateVector {
|
|
|
905
868
|
}
|
|
906
869
|
};
|
|
907
870
|
|
|
871
|
+
// src/utils/deepEqual.ts
|
|
872
|
+
function deepEqual(a, b) {
|
|
873
|
+
if (a === b) return true;
|
|
874
|
+
if (a === null || b === null) return a === b;
|
|
875
|
+
const ta = typeof a;
|
|
876
|
+
const tb = typeof b;
|
|
877
|
+
if (ta !== tb) return false;
|
|
878
|
+
if (ta !== "object") return false;
|
|
879
|
+
const aIsArr = Array.isArray(a);
|
|
880
|
+
const bIsArr = Array.isArray(b);
|
|
881
|
+
if (aIsArr || bIsArr) {
|
|
882
|
+
if (!(aIsArr && bIsArr)) return false;
|
|
883
|
+
if (a.length !== b.length) return false;
|
|
884
|
+
for (let i = 0; i < a.length; i++) {
|
|
885
|
+
if (!deepEqual(a[i], b[i])) return false;
|
|
886
|
+
}
|
|
887
|
+
return true;
|
|
888
|
+
}
|
|
889
|
+
const aProto = Object.getPrototypeOf(a);
|
|
890
|
+
const bProto = Object.getPrototypeOf(b);
|
|
891
|
+
if (aProto !== Object.prototype && aProto !== null || bProto !== Object.prototype && bProto !== null) {
|
|
892
|
+
return false;
|
|
893
|
+
}
|
|
894
|
+
const aKeys = Object.keys(a);
|
|
895
|
+
const bKeys = Object.keys(b);
|
|
896
|
+
if (aKeys.length !== bKeys.length) return false;
|
|
897
|
+
for (const key of aKeys) {
|
|
898
|
+
if (!Object.prototype.hasOwnProperty.call(b, key)) return false;
|
|
899
|
+
if (!deepEqual(a[key], b[key])) return false;
|
|
900
|
+
}
|
|
901
|
+
return true;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
// src/utils/isJsonValue.ts
|
|
905
|
+
function isJsonValue(v) {
|
|
906
|
+
if (v === void 0) return true;
|
|
907
|
+
if (v === null) return true;
|
|
908
|
+
const t = typeof v;
|
|
909
|
+
if (t === "string" || t === "number" || t === "boolean") return true;
|
|
910
|
+
if (t === "bigint" || t === "function" || t === "symbol") return false;
|
|
911
|
+
if (Array.isArray(v)) return v.every(isJsonValue);
|
|
912
|
+
if (t === "object") {
|
|
913
|
+
if (v instanceof Date) return false;
|
|
914
|
+
if (v instanceof Map || v instanceof Set || v instanceof RegExp) return false;
|
|
915
|
+
if (ArrayBuffer.isView(v)) return false;
|
|
916
|
+
const proto = Object.getPrototypeOf(v);
|
|
917
|
+
if (proto !== Object.prototype && proto !== null) return false;
|
|
918
|
+
for (const val of Object.values(v)) {
|
|
919
|
+
if (!isJsonValue(val)) return false;
|
|
920
|
+
}
|
|
921
|
+
return true;
|
|
922
|
+
}
|
|
923
|
+
return false;
|
|
924
|
+
}
|
|
925
|
+
|
|
908
926
|
// src/RepTree.ts
|
|
909
927
|
var _RepTree = class _RepTree {
|
|
910
928
|
/**
|
|
@@ -1054,7 +1072,7 @@ var _RepTree = class _RepTree {
|
|
|
1054
1072
|
if (typedProps) {
|
|
1055
1073
|
this.setVertexProperties(vertexId, typedProps);
|
|
1056
1074
|
}
|
|
1057
|
-
this.setVertexProperty(vertexId, "
|
|
1075
|
+
this.setVertexProperty(vertexId, "name", name);
|
|
1058
1076
|
const vertex = this.state.getVertex(vertexId);
|
|
1059
1077
|
if (!vertex) {
|
|
1060
1078
|
throw new Error("Failed to create named vertex");
|
|
@@ -1071,6 +1089,9 @@ var _RepTree = class _RepTree {
|
|
|
1071
1089
|
this.moveVertex(vertexId, _RepTree.NULL_VERTEX_ID);
|
|
1072
1090
|
}
|
|
1073
1091
|
setTransientVertexProperty(vertexId, key, value) {
|
|
1092
|
+
if (!isJsonValue(value)) {
|
|
1093
|
+
throw new Error(`Unsupported transient property value for key "${key}"`);
|
|
1094
|
+
}
|
|
1074
1095
|
this.lamportClock++;
|
|
1075
1096
|
const op = newSetTransientVertexPropertyOp(this.lamportClock, this.peerId, vertexId, key, value);
|
|
1076
1097
|
this.localOps.push(op);
|
|
@@ -1096,6 +1117,29 @@ var _RepTree = class _RepTree {
|
|
|
1096
1117
|
vertex.clearAllTransientProperties();
|
|
1097
1118
|
}
|
|
1098
1119
|
setVertexProperty(vertexId, key, value) {
|
|
1120
|
+
const isJsonValue2 = (v) => {
|
|
1121
|
+
if (v === void 0) return true;
|
|
1122
|
+
if (v === null) return true;
|
|
1123
|
+
const t = typeof v;
|
|
1124
|
+
if (t === "string" || t === "number" || t === "boolean") return true;
|
|
1125
|
+
if (t === "bigint" || t === "function" || t === "symbol") return false;
|
|
1126
|
+
if (Array.isArray(v)) return v.every(isJsonValue2);
|
|
1127
|
+
if (t === "object") {
|
|
1128
|
+
if (v instanceof Date) return false;
|
|
1129
|
+
if (v instanceof Map || v instanceof Set || v instanceof RegExp) return false;
|
|
1130
|
+
if (ArrayBuffer.isView(v)) return false;
|
|
1131
|
+
const proto = Object.getPrototypeOf(v);
|
|
1132
|
+
if (proto !== Object.prototype && proto !== null) return false;
|
|
1133
|
+
for (const val of Object.values(v)) {
|
|
1134
|
+
if (!isJsonValue2(val)) return false;
|
|
1135
|
+
}
|
|
1136
|
+
return true;
|
|
1137
|
+
}
|
|
1138
|
+
return false;
|
|
1139
|
+
};
|
|
1140
|
+
if (!isJsonValue2(value)) {
|
|
1141
|
+
throw new Error(`Unsupported property value for key "${key}"`);
|
|
1142
|
+
}
|
|
1099
1143
|
this.lamportClock++;
|
|
1100
1144
|
const op = newSetVertexPropertyOp(this.lamportClock, this.peerId, vertexId, key, value);
|
|
1101
1145
|
this.localOps.push(op);
|
|
@@ -1128,7 +1172,7 @@ var _RepTree = class _RepTree {
|
|
|
1128
1172
|
const targetName = path[0];
|
|
1129
1173
|
const children = this.getChildren(vertex.id);
|
|
1130
1174
|
for (const child of children) {
|
|
1131
|
-
if (child.getProperty("
|
|
1175
|
+
if (child.getProperty("name") === targetName) {
|
|
1132
1176
|
return this.getVertexByPathArray(child, path.slice(1));
|
|
1133
1177
|
}
|
|
1134
1178
|
}
|
|
@@ -1257,12 +1301,8 @@ var _RepTree = class _RepTree {
|
|
|
1257
1301
|
}
|
|
1258
1302
|
for (const propA of propertiesA) {
|
|
1259
1303
|
const propB = propertiesB.find((p) => p.key === propA.key);
|
|
1260
|
-
if (!propB)
|
|
1261
|
-
|
|
1262
|
-
}
|
|
1263
|
-
if (propA.value !== propB.value) {
|
|
1264
|
-
return false;
|
|
1265
|
-
}
|
|
1304
|
+
if (!propB) return false;
|
|
1305
|
+
if (!deepEqual(propA.value, propB.value)) return false;
|
|
1266
1306
|
}
|
|
1267
1307
|
}
|
|
1268
1308
|
for (const childId of childrenA) {
|
|
@@ -1392,7 +1432,6 @@ var _RepTree = class _RepTree {
|
|
|
1392
1432
|
}
|
|
1393
1433
|
}
|
|
1394
1434
|
}
|
|
1395
|
-
// Non-LWW modify-property flow removed
|
|
1396
1435
|
applyOperation(op) {
|
|
1397
1436
|
if (isMoveVertexOp(op)) {
|
|
1398
1437
|
this.applyMove(op);
|
|
@@ -1516,7 +1555,6 @@ var RepTree = _RepTree;
|
|
|
1516
1555
|
Vertex,
|
|
1517
1556
|
VertexState,
|
|
1518
1557
|
bindVertex,
|
|
1519
|
-
defaultAliases,
|
|
1520
1558
|
isAnyPropertyOp,
|
|
1521
1559
|
isMoveVertexOp,
|
|
1522
1560
|
newMoveVertexOp,
|