diff --git a/package.json b/package.json index dd3741bdcd..bd728e941f 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,8 @@ "coverage": "yarn test --collectCoverage", "typedoc": "typedoc", "build:pages": "rimraf gh-pages && mkdir -p gh-pages && cp -r typedocs/* gh-pages && cp -r coverage gh-pages/coverage", - "deploy:pages": "gh-pages -d gh-pages" + "deploy:pages": "gh-pages -d gh-pages", + "publish-coverage-and-typedocs": "yarn typedoc && yarn coverage && yarn build:pages && yarn deploy:pages" }, "keywords": [], "peerDependencies": { diff --git a/src/json-crdt-patch/Patch.ts b/src/json-crdt-patch/Patch.ts index 0e7974c31b..a7b667e560 100644 --- a/src/json-crdt-patch/Patch.ts +++ b/src/json-crdt-patch/Patch.ts @@ -1,20 +1,4 @@ -import { - NewConOp, - NewObjOp, - NewValOp, - NewVecOp, - NewStrOp, - NewBinOp, - NewArrOp, - InsValOp, - InsObjOp, - InsVecOp, - InsStrOp, - InsBinOp, - InsArrOp, - DelOp, - NopOp, -} from './operations'; +import * as operations from './operations'; import {ITimestampStruct, ts, toDisplayString} from './clock'; import {SESSION} from './constants'; import {encode, decode} from './codec/binary'; @@ -24,21 +8,21 @@ import type {Printable} from '../util/print/types'; * A union type of all possible JSON CRDT patch operations. */ export type JsonCrdtPatchOperation = - | NewConOp - | NewValOp - | NewVecOp - | NewObjOp - | NewStrOp - | NewBinOp - | NewArrOp - | InsValOp - | InsObjOp - | InsVecOp - | InsStrOp - | InsBinOp - | InsArrOp - | DelOp - | NopOp; + | operations.NewConOp + | operations.NewValOp + | operations.NewVecOp + | operations.NewObjOp + | operations.NewStrOp + | operations.NewBinOp + | operations.NewArrOp + | operations.InsValOp + | operations.InsObjOp + | operations.InsVecOp + | operations.InsStrOp + | operations.InsBinOp + | operations.InsArrOp + | operations.DelOp + | operations.NopOp; /** * Represents a JSON CRDT patch. @@ -135,27 +119,31 @@ export class Patch implements Printable { const patchOps = patch.ops; for (let i = 0; i < length; i++) { const op = ops[i]; - if (op instanceof DelOp) patchOps.push(new DelOp(ts(op.id), ts(op.obj), op.what)); - else if (op instanceof NewConOp) patchOps.push(new NewConOp(ts(op.id), op.val)); - else if (op instanceof NewVecOp) patchOps.push(new NewVecOp(ts(op.id))); - else if (op instanceof NewValOp) patchOps.push(new NewValOp(ts(op.id), ts(op.val))); - else if (op instanceof NewObjOp) patchOps.push(new NewObjOp(ts(op.id))); - else if (op instanceof NewStrOp) patchOps.push(new NewStrOp(ts(op.id))); - else if (op instanceof NewBinOp) patchOps.push(new NewBinOp(ts(op.id))); - else if (op instanceof NewArrOp) patchOps.push(new NewArrOp(ts(op.id))); - else if (op instanceof InsArrOp) patchOps.push(new InsArrOp(ts(op.id), ts(op.obj), ts(op.ref), op.data.map(ts))); - else if (op instanceof InsStrOp) patchOps.push(new InsStrOp(ts(op.id), ts(op.obj), ts(op.ref), op.data)); - else if (op instanceof InsBinOp) patchOps.push(new InsBinOp(ts(op.id), ts(op.obj), ts(op.ref), op.data)); - else if (op instanceof InsValOp) patchOps.push(new InsValOp(ts(op.id), ts(op.obj), ts(op.val))); - else if (op instanceof InsObjOp) + if (op instanceof operations.DelOp) patchOps.push(new operations.DelOp(ts(op.id), ts(op.obj), op.what)); + else if (op instanceof operations.NewConOp) patchOps.push(new operations.NewConOp(ts(op.id), op.val)); + else if (op instanceof operations.NewVecOp) patchOps.push(new operations.NewVecOp(ts(op.id))); + else if (op instanceof operations.NewValOp) patchOps.push(new operations.NewValOp(ts(op.id))); + else if (op instanceof operations.NewObjOp) patchOps.push(new operations.NewObjOp(ts(op.id))); + else if (op instanceof operations.NewStrOp) patchOps.push(new operations.NewStrOp(ts(op.id))); + else if (op instanceof operations.NewBinOp) patchOps.push(new operations.NewBinOp(ts(op.id))); + else if (op instanceof operations.NewArrOp) patchOps.push(new operations.NewArrOp(ts(op.id))); + else if (op instanceof operations.InsArrOp) + patchOps.push(new operations.InsArrOp(ts(op.id), ts(op.obj), ts(op.ref), op.data.map(ts))); + else if (op instanceof operations.InsStrOp) + patchOps.push(new operations.InsStrOp(ts(op.id), ts(op.obj), ts(op.ref), op.data)); + else if (op instanceof operations.InsBinOp) + patchOps.push(new operations.InsBinOp(ts(op.id), ts(op.obj), ts(op.ref), op.data)); + else if (op instanceof operations.InsValOp) + patchOps.push(new operations.InsValOp(ts(op.id), ts(op.obj), ts(op.val))); + else if (op instanceof operations.InsObjOp) patchOps.push( - new InsObjOp( + new operations.InsObjOp( ts(op.id), ts(op.obj), op.data.map(([key, value]) => [key, ts(value)]), ), ); - else if (op instanceof NopOp) patchOps.push(new NopOp(ts(op.id), op.len)); + else if (op instanceof operations.NopOp) patchOps.push(new operations.NopOp(ts(op.id), op.len)); } return patch; } diff --git a/src/json-crdt-patch/PatchBuilder.ts b/src/json-crdt-patch/PatchBuilder.ts index ef61ed1527..6da120f103 100644 --- a/src/json-crdt-patch/PatchBuilder.ts +++ b/src/json-crdt-patch/PatchBuilder.ts @@ -154,11 +154,12 @@ export class PatchBuilder { * * @param val Reference to another object. * @returns ID of the new operation. + * @todo Rename to `newVal`. */ - public val(val: ITimestampStruct): ITimestampStruct { + public val(): ITimestampStruct { this.pad(); const id = this.clock.tick(1); - this.patch.ops.push(new NewValOp(id, val)); + this.patch.ops.push(new NewValOp(id)); return id; } @@ -210,6 +211,7 @@ export class PatchBuilder { * Set value of a "val" object. * * @returns ID of the new operation. + * @todo Rename to "insVal". */ public setVal(obj: ITimestampStruct, val: ITimestampStruct): ITimestampStruct { this.pad(); @@ -349,8 +351,10 @@ export class PatchBuilder { * Run builder commands to create a JSON value. */ public jsonVal(value: unknown): ITimestampStruct { + const valId = this.val(); const id = this.const(value); - return this.val(id); + this.setVal(valId, id); + return valId; } /** diff --git a/src/json-crdt-patch/builder/schema.ts b/src/json-crdt-patch/builder/schema.ts index 47a6fed246..cee1faa71a 100644 --- a/src/json-crdt-patch/builder/schema.ts +++ b/src/json-crdt-patch/builder/schema.ts @@ -32,8 +32,10 @@ export namespace nodes { constructor(public readonly value: T) { super((builder) => { + const valId = builder.val(); const valueId = value.build(builder); - return builder.val(valueId); + builder.setVal(valId, valueId); + return valId; }); } } diff --git a/src/json-crdt-patch/codec/__tests__/PatchFuzzer.ts b/src/json-crdt-patch/codec/__tests__/PatchFuzzer.ts index b0419a9f0b..7ae8cab852 100644 --- a/src/json-crdt-patch/codec/__tests__/PatchFuzzer.ts +++ b/src/json-crdt-patch/codec/__tests__/PatchFuzzer.ts @@ -28,7 +28,7 @@ export class PatchFuzzer extends Fuzzer { () => builder.arr(), () => builder.str(), () => builder.bin(), - () => builder.val(ts()), + () => builder.val(), () => builder.const(RandomJson.generate()), () => builder.root(ts()), () => diff --git a/src/json-crdt-patch/codec/binary/Decoder.ts b/src/json-crdt-patch/codec/binary/Decoder.ts index b07a78c3be..39a49dd91d 100644 --- a/src/json-crdt-patch/codec/binary/Decoder.ts +++ b/src/json-crdt-patch/codec/binary/Decoder.ts @@ -73,7 +73,7 @@ export class Decoder extends CborDecoder { break; } case JsonCrdtPatchOpcode.new_val: { - builder.val(this.decodeId()); + builder.val(); break; } case JsonCrdtPatchOpcode.new_obj: { diff --git a/src/json-crdt-patch/codec/binary/Encoder.ts b/src/json-crdt-patch/codec/binary/Encoder.ts index dc9bb5a7c7..1ebe3cab7f 100644 --- a/src/json-crdt-patch/codec/binary/Encoder.ts +++ b/src/json-crdt-patch/codec/binary/Encoder.ts @@ -94,10 +94,7 @@ export class Encoder extends CborEncoder { break; } case operations.NewValOp: { - const operation = op; - const val = operation.val; writer.u8(JsonCrdtPatchOpcode.new_val); - this.encodeId(val); break; } case operations.NewObjOp: { diff --git a/src/json-crdt-patch/codec/compact/decode.ts b/src/json-crdt-patch/codec/compact/decode.ts index 072cba09ab..cad04d79bf 100644 --- a/src/json-crdt-patch/codec/compact/decode.ts +++ b/src/json-crdt-patch/codec/compact/decode.ts @@ -38,7 +38,7 @@ export const decode = (data: types.CompactCodecPatch): Patch => { break; } case JsonCrdtPatchOpcode.new_val: { - builder.val(timestamp(sid, op[1])); + builder.val(); break; } case JsonCrdtPatchOpcode.new_obj: { diff --git a/src/json-crdt-patch/codec/compact/encode.ts b/src/json-crdt-patch/codec/compact/encode.ts index d3f1390f06..03486f6c40 100644 --- a/src/json-crdt-patch/codec/compact/encode.ts +++ b/src/json-crdt-patch/codec/compact/encode.ts @@ -47,7 +47,7 @@ export const encode = (patch: Patch): types.CompactCodecPatch => { res.push([JsonCrdtPatchOpcode.new_con, val]); } } else if (op instanceof operations.NewValOp) { - res.push([JsonCrdtPatchOpcode.new_val, timestamp(sid, op.val)]); + res.push([JsonCrdtPatchOpcode.new_val]); } else if (op instanceof operations.NewObjOp) { res.push([JsonCrdtPatchOpcode.new_obj]); } else if (op instanceof operations.NewVecOp) { diff --git a/src/json-crdt-patch/codec/verbose/__tests__/bug-1.spec.ts b/src/json-crdt-patch/codec/verbose/__tests__/bug-1.spec.ts index 63c343d372..577ea1f6d2 100644 --- a/src/json-crdt-patch/codec/verbose/__tests__/bug-1.spec.ts +++ b/src/json-crdt-patch/codec/verbose/__tests__/bug-1.spec.ts @@ -9,7 +9,6 @@ const encoded1 = { }, { op: 'new_val', - value: 1, }, { op: 'new_bin', @@ -22,7 +21,6 @@ const encoded1 = { }, { op: 'new_val', - value: 2, }, { op: 'ins_obj', diff --git a/src/json-crdt-patch/codec/verbose/decode.ts b/src/json-crdt-patch/codec/verbose/decode.ts index 4bfd962813..49a4831eac 100644 --- a/src/json-crdt-patch/codec/verbose/decode.ts +++ b/src/json-crdt-patch/codec/verbose/decode.ts @@ -30,7 +30,7 @@ export const decode = (data: types.JsonCodecPatch): Patch => { break; } case 'new_val': { - builder.val(decodeId(op.value)); + builder.val(); break; } case 'new_obj': { diff --git a/src/json-crdt-patch/codec/verbose/encode.ts b/src/json-crdt-patch/codec/verbose/encode.ts index 422be1e255..e169b813c8 100644 --- a/src/json-crdt-patch/codec/verbose/encode.ts +++ b/src/json-crdt-patch/codec/verbose/encode.ts @@ -45,7 +45,7 @@ export const encode = (patch: Patch): types.JsonCodecPatch => { } else if (op instanceof operations.NewBinOp) { ops.push({op: 'new_bin'}); } else if (op instanceof operations.NewValOp) { - ops.push({op: 'new_val', value: encodeTimestamp(op.val)}); + ops.push({op: 'new_val'}); } else if (op instanceof operations.InsObjOp) { ops.push({ op: 'ins_obj', diff --git a/src/json-crdt-patch/codec/verbose/types.ts b/src/json-crdt-patch/codec/verbose/types.ts index 0ab56a9886..3554a3cb27 100644 --- a/src/json-crdt-patch/codec/verbose/types.ts +++ b/src/json-crdt-patch/codec/verbose/types.ts @@ -119,12 +119,7 @@ export interface JsonCodecNewConOperation extends JsonCodecOperationBase<'new_co * Operation which creates a new "val" CRDT data type, which is a * Last-Write-Wins Register of a pointer to another CRDT data type. */ -export interface JsonCodecNewValOperation extends JsonCodecOperationBase<'new_val'> { - /** - * ID of the "val" LWW-Register object latest value. - */ - value: JsonCodecTimestamp; -} +export type JsonCodecNewValOperation = JsonCodecOperationBase<'new_val'>; /** * Operation which creates a new "object" CRDT data type, which is a map of diff --git a/src/json-crdt-patch/operations.ts b/src/json-crdt-patch/operations.ts index f63b91e386..a405793b48 100644 --- a/src/json-crdt-patch/operations.ts +++ b/src/json-crdt-patch/operations.ts @@ -37,7 +37,7 @@ export class NewConOp implements IJsonCrdtPatchOperation { * @category Operations */ export class NewValOp implements IJsonCrdtPatchOperation { - constructor(public readonly id: ITimestampStruct, public readonly val: ITimestampStruct) {} + constructor(public readonly id: ITimestampStruct) {} public span(): number { return 1; @@ -48,7 +48,7 @@ export class NewValOp implements IJsonCrdtPatchOperation { } public toString(): string { - return `"${this.name()}" ${toDisplayString(this.id)} { ${toDisplayString(this.val)} }`; + return `"${this.name()}" ${toDisplayString(this.id)}`; } } @@ -165,6 +165,7 @@ export class NewArrOp implements IJsonCrdtPatchOperation { export class InsValOp implements IJsonCrdtPatchEditOperation { constructor( public readonly id: ITimestampStruct, + /** @todo Rename to `node`. */ public readonly obj: ITimestampStruct, public readonly val: ITimestampStruct, ) {} diff --git a/src/json-crdt/__tests__/recursion.spec.ts b/src/json-crdt/__tests__/recursion.spec.ts new file mode 100644 index 0000000000..9fdc3f68e3 --- /dev/null +++ b/src/json-crdt/__tests__/recursion.spec.ts @@ -0,0 +1,123 @@ +import {Model} from '../model'; + +describe('recursive node references are not allowed', () => { + describe('arr', () => { + describe('ins_arr', () => { + test('reference to parent object in same patch', () => { + const model = Model.withLogicalClock(); + const builder = model.api.builder; + const objId = builder.obj(); + const arrId = builder.arr(); + builder.insObj(objId, [['arr', arrId]]); + builder.insArr(arrId, arrId, [builder.const(1), objId]); + builder.root(objId); + const patch1 = builder.flush(); + model.applyPatch(patch1); + expect(model.view()).toStrictEqual({arr: [1]}); + }); + + test('reference to parent object in second patch', () => { + const model = Model.withLogicalClock(); + const builder = model.api.builder; + const objId = builder.obj(); + const arrId = builder.arr(); + builder.insObj(objId, [['arr', arrId]]); + builder.insArr(arrId, arrId, [builder.const(1)]); + builder.root(objId); + const patch1 = builder.flush(); + model.applyPatch(patch1); + builder.insArr(arrId, arrId, [objId]); + const patch2 = builder.flush(); + model.applyPatch(patch2); + expect(model.view()).toStrictEqual({arr: [1]}); + }); + }); + }); + + describe('obj', () => { + describe('ins_obj', () => { + test('reference to object self in own key', () => { + const model = Model.withLogicalClock(); + const builder = model.api.builder; + const objId = builder.obj(); + builder.insObj(objId, [ + ['con', builder.const(2)], + ['obj', objId], + ]); + builder.root(objId); + const patch1 = builder.flush(); + model.applyPatch(patch1); + expect(model.view()).toStrictEqual({con: 2}); + }); + + test('reference to object self in own key in separate patch', () => { + const model = Model.withLogicalClock(); + const builder = model.api.builder; + const objId = builder.obj(); + builder.insObj(objId, [['con', builder.const(2)]]); + builder.root(objId); + const patch1 = builder.flush(); + model.applyPatch(patch1); + builder.insObj(objId, [['obj', objId]]); + const patch2 = builder.flush(); + model.applyPatch(patch2); + expect(model.view()).toStrictEqual({con: 2}); + }); + }); + }); + + describe('vec', () => { + describe('ins_vec', () => { + test('reference to parent object in same patch', () => { + const model = Model.withLogicalClock(); + const builder = model.api.builder; + const vecId = builder.vec(); + builder.insVec(vecId, [ + [0, builder.const(1)], + [1, vecId], + ]); + builder.root(vecId); + const patch1 = builder.flush(); + model.applyPatch(patch1); + expect(model.view()).toStrictEqual([1]); + }); + + test('reference to parent object in second patch', () => { + const model = Model.withLogicalClock(); + const builder = model.api.builder; + const vecId = builder.vec(); + builder.insVec(vecId, [ + [0, builder.const(1)], + [1, vecId], + ]); + builder.root(vecId); + const patch1 = builder.flush(); + model.applyPatch(patch1); + builder.insVec(vecId, [[1, vecId]]); + const patch2 = builder.flush(); + model.applyPatch(patch2); + expect(model.view()).toStrictEqual([1]); + }); + }); + }); + + describe('val', () => { + describe('ins_val', () => { + test('reference to parent object in second patch', () => { + const model = Model.withLogicalClock(); + const builder = model.api.builder; + const objId = builder.obj(); + const valId = builder.val(); + builder.insObj(objId, [['val', valId]]); + builder.root(objId); + const patch1 = builder.flush(); + model.applyPatch(patch1); + expect((model.view() as any).val).toStrictEqual(undefined); + builder.setVal(valId, objId); + const patch2 = builder.flush(); + model.applyPatch(patch2); + expect((model.view() as any).val).toStrictEqual(undefined); + }); + }); + }); +}); diff --git a/src/json-crdt/model/Model.ts b/src/json-crdt/model/Model.ts index a663c58138..c7ab454497 100644 --- a/src/json-crdt/model/Model.ts +++ b/src/json-crdt/model/Model.ts @@ -187,10 +187,7 @@ export class Model implements Printabl if (!index.get(id)) index.set(id, new StrNode(id)); } else if (op instanceof operations.NewValOp) { const id = op.id; - if (!index.get(id)) { - const val = index.get(op.val); - if (val) index.set(id, new ValNode(this, id, op.val)); - } + if (!index.get(id)) index.set(id, new ValNode(this, id, ORIGIN)); } else if (op instanceof operations.NewConOp) { const id = op.id; if (!index.get(id)) index.set(id, new ConNode(id, op.val)); diff --git a/src/json-crdt/model/__tests__/Model.server-clock.spec.ts b/src/json-crdt/model/__tests__/Model.server-clock.spec.ts index 179df3d426..25bef11d38 100644 --- a/src/json-crdt/model/__tests__/Model.server-clock.spec.ts +++ b/src/json-crdt/model/__tests__/Model.server-clock.spec.ts @@ -7,7 +7,7 @@ describe('server clock', () => { const model = Model.withServerClock(); expect(model.clock.time).toBe(1); model.api.root(true); - expect(model.clock.time).toBe(4); + expect(model.clock.time).toBe(5); model.api.root({foo: 'bar'}); model.applyPatch(model.api.builder.patch); model.applyPatch(model.api.builder.patch); @@ -18,7 +18,7 @@ describe('server clock', () => { const model = Model.withServerClock(); expect(model.clock.time).toBe(1); model.api.root(true); - expect(model.clock.time).toBe(4); + expect(model.clock.time).toBe(5); const clock = model.clock.clone(); clock.tick(1); const builder = new PatchBuilder(clock); diff --git a/src/json-crdt/model/__tests__/Model.value.spec.ts b/src/json-crdt/model/__tests__/Model.value.spec.ts index 6029e768da..ca6d2d8850 100644 --- a/src/json-crdt/model/__tests__/Model.value.spec.ts +++ b/src/json-crdt/model/__tests__/Model.value.spec.ts @@ -7,8 +7,9 @@ describe('Document', () => { test('can create a value', () => { const doc = Model.withLogicalClock(); const builder = new PatchBuilder(doc.clock); + const numId = builder.val(); const val = builder.const([1, 2, 3]); - const numId = builder.val(val); + builder.setVal(numId, val); doc.applyPatch(builder.patch); const obj = doc.index.get(numId); expect(obj).toBeInstanceOf(ValNode); @@ -17,7 +18,8 @@ describe('Document', () => { test('can set value as document root', () => { const doc = Model.withLogicalClock(); const builder = new PatchBuilder(doc.clock); - const numId = builder.val(builder.const(10_000)); + const numId = builder.val(); + builder.setVal(numId, builder.const(10_000)); builder.root(numId); doc.applyPatch(builder.patch); expect(doc.view()).toEqual(10_000); @@ -26,7 +28,8 @@ describe('Document', () => { test('can update value to a number', () => { const doc = Model.withLogicalClock(); const builder = new PatchBuilder(doc.clock); - const objId = builder.val(builder.const(1)); + const objId = builder.val(); + builder.setVal(objId, builder.const(1)); builder.setVal(objId, builder.const(2)); builder.root(objId); doc.applyPatch(builder.patch); @@ -36,7 +39,8 @@ describe('Document', () => { test('can update value to a string', () => { const doc = Model.withLogicalClock(); const builder = new PatchBuilder(doc.clock); - const objId = builder.val(builder.const(1)); + const objId = builder.val(); + builder.setVal(objId, builder.const(1)); builder.setVal(objId, builder.const('boom')); builder.root(objId); doc.applyPatch(builder.patch); @@ -46,7 +50,8 @@ describe('Document', () => { test('can overwrite number value', () => { const doc = Model.withLogicalClock(); const builder = new PatchBuilder(doc.clock); - const valId = builder.val(builder.const(-1)); + const valId = builder.val(); + builder.setVal(valId, builder.const(-1)); builder.setVal(valId, builder.const(123)); builder.setVal(valId, builder.const(5.5)); builder.root(valId); @@ -58,7 +63,8 @@ describe('Document', () => { const doc = Model.withLogicalClock(); const builder = new PatchBuilder(doc.clock); const objId = builder.obj(); - const valId = builder.val(builder.const(25)); + const valId = builder.val(); + builder.setVal(valId, builder.const(25)); builder.insObj(objId, [['gg', valId]]); builder.setVal(valId, builder.const(123)); builder.setVal(valId, builder.const(99)); @@ -71,7 +77,8 @@ describe('Document', () => { const doc = Model.withLogicalClock(); const builder = new PatchBuilder(doc.clock); const objId = builder.obj(); - const valId = builder.val(builder.const(25)); + const valId = builder.val(); + builder.setVal(valId, builder.const(25)); builder.insObj(objId, [['gg', valId]]); builder.setVal(valId, builder.const(123)); builder.setVal(valId, builder.const(true)); @@ -84,7 +91,8 @@ describe('Document', () => { const doc = Model.withLogicalClock(); const builder = new PatchBuilder(doc.clock); const objId = builder.arr(); - const valId = builder.val(builder.const(25)); + const valId = builder.val(); + builder.setVal(valId, builder.const(25)); builder.insArr(objId, objId, [valId]); builder.setVal(valId, builder.const(123)); builder.setVal(valId, builder.const(true)); diff --git a/src/json-crdt/nodes/root/RootNode.ts b/src/json-crdt/nodes/root/RootNode.ts index 89882d1340..2ade5f44b9 100644 --- a/src/json-crdt/nodes/root/RootNode.ts +++ b/src/json-crdt/nodes/root/RootNode.ts @@ -1,6 +1,6 @@ -import {ORIGIN, SESSION} from '../../../json-crdt-patch/constants'; +import {ORIGIN} from '../../../json-crdt-patch/constants'; import {ValNode} from '../val/ValNode'; -import {Model, UNDEFINED} from '../../model/Model'; +import {Model} from '../../model/Model'; import type {ITimestampStruct} from '../../../json-crdt-patch/clock'; import type {JsonNode} from '../types'; @@ -18,8 +18,4 @@ export class RootNode extends ValNode constructor(doc: Model, val: ITimestampStruct) { super(doc, ORIGIN, val); } - - public node(): Value { - return this.val.sid === SESSION.SYSTEM ? UNDEFINED : super.node(); - } } diff --git a/src/json-crdt/nodes/val/ValNode.ts b/src/json-crdt/nodes/val/ValNode.ts index 6761c286d8..23dc8186a9 100644 --- a/src/json-crdt/nodes/val/ValNode.ts +++ b/src/json-crdt/nodes/val/ValNode.ts @@ -1,6 +1,7 @@ import {compare, ITimestampStruct, toDisplayString} from '../../../json-crdt-patch/clock'; import {SESSION} from '../../../json-crdt-patch/constants'; import {printTree} from '../../../util/print/printTree'; +import {UNDEFINED} from '../../model/Model'; import type {JsonNode, JsonNodeView} from '..'; import type {Model} from '../../model'; import type {Printable} from '../../../util/print/types'; @@ -31,6 +32,7 @@ export class ValNode implements JsonNode implements JsonNodeUNDEFINED : this.child()!; } // ----------------------------------------------------------------- JsonNode