From 95677a805e1ad7ac646ab1bad2e824359e2f9a37 Mon Sep 17 00:00:00 2001 From: streamich Date: Tue, 28 Nov 2023 11:27:45 +0100 Subject: [PATCH 01/10] =?UTF-8?q?feat(json-crdt):=20=F0=9F=8E=B8=20add=20.?= =?UTF-8?q?length()=20method=20to=20api=20nodes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/api/__tests__/ArrayApi.spec.ts | 9 +++++++ .../model/api/__tests__/BinaryApi.spec.ts | 8 ++++++ .../model/api/__tests__/StringApi.spec.ts | 8 ++++++ .../model/api/__tests__/TupleApi.spec.ts | 9 ++++++- src/json-crdt/model/api/nodes.ts | 27 +++++++++++++++++++ 5 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/json-crdt/model/api/__tests__/ArrayApi.spec.ts b/src/json-crdt/model/api/__tests__/ArrayApi.spec.ts index 7873cc4ec2..a9dc4b88fa 100644 --- a/src/json-crdt/model/api/__tests__/ArrayApi.spec.ts +++ b/src/json-crdt/model/api/__tests__/ArrayApi.spec.ts @@ -12,3 +12,12 @@ test('can insert a value and delete all previous ones', () => { arr.ins(1, [69]); expect(arr.view()).toEqual([42, 69]); }); + +test('.length()', () => { + const doc = Model.withLogicalClock(); + doc.api.root({ + arr: [1, 2, 3], + }); + const arr = doc.api.arr(['arr']); + expect(arr.length()).toBe(3); +}); diff --git a/src/json-crdt/model/api/__tests__/BinaryApi.spec.ts b/src/json-crdt/model/api/__tests__/BinaryApi.spec.ts index 67bccd236f..41261005b4 100644 --- a/src/json-crdt/model/api/__tests__/BinaryApi.spec.ts +++ b/src/json-crdt/model/api/__tests__/BinaryApi.spec.ts @@ -1,3 +1,4 @@ +import {s} from '../../../../json-crdt-patch'; import {Model} from '../../Model'; test('can edit a simple binary', () => { @@ -25,3 +26,10 @@ test('can delete across two chunks', () => { bin.del(1, 7); expect(bin.view()).toEqual(new Uint8Array([3, 1])); }); + +test('.length()', () => { + const doc = Model.withLogicalClock().setSchema(s.obj({ + bin: s.bin(new Uint8Array([1, 2, 3])), + })); + expect(doc.find.val.bin.toApi().length()).toBe(3); +}); diff --git a/src/json-crdt/model/api/__tests__/StringApi.spec.ts b/src/json-crdt/model/api/__tests__/StringApi.spec.ts index fab97a677c..0423680c0d 100644 --- a/src/json-crdt/model/api/__tests__/StringApi.spec.ts +++ b/src/json-crdt/model/api/__tests__/StringApi.spec.ts @@ -1,3 +1,4 @@ +import {s} from '../../../../json-crdt-patch'; import {Model} from '../../Model'; test('can edit a simple string', () => { @@ -25,6 +26,13 @@ test('can delete across two chunks', () => { expect(str.view()).toEqual('ca'); }); +test('.length()', () => { + const doc = Model.withLogicalClock().setSchema(s.obj({ + str: s.str('hello world'), + })); + expect(doc.find.val.str.toApi().length()).toBe(11); +}); + describe('events', () => { test('can subscribe to "view" events', async () => { const doc = Model.withLogicalClock(); diff --git a/src/json-crdt/model/api/__tests__/TupleApi.spec.ts b/src/json-crdt/model/api/__tests__/TupleApi.spec.ts index 211c77e141..ef4d1d5b56 100644 --- a/src/json-crdt/model/api/__tests__/TupleApi.spec.ts +++ b/src/json-crdt/model/api/__tests__/TupleApi.spec.ts @@ -1,4 +1,4 @@ -import {vec} from '../../../../json-crdt-patch'; +import {s, vec} from '../../../../json-crdt-patch'; import {Model} from '../../Model'; test('can edit a tuple', () => { @@ -9,6 +9,13 @@ test('can edit a tuple', () => { expect(api.vec([]).view()).toEqual([undefined, 'a']); }); +test('.length()', () => { + const doc = Model.withLogicalClock().setSchema(s.obj({ + vec: s.vec(s.con(1), s.con(2)), + })); + expect(doc.find.val.vec.toApi().length()).toBe(2); +}); + describe('events', () => { test('can subscribe and un-subscribe to "view" events', async () => { const doc = Model.withLogicalClock(); diff --git a/src/json-crdt/model/api/nodes.ts b/src/json-crdt/model/api/nodes.ts index fb4d39abec..ac2966bd8d 100644 --- a/src/json-crdt/model/api/nodes.ts +++ b/src/json-crdt/model/api/nodes.ts @@ -252,6 +252,15 @@ export class VecApi = VecNode> extends NodeApi { return this; } + /** + * Get the length of the vector without materializing it to a view. + * + * @returns Length of the vector. + */ + public length(): number { + return this.node.elements.length + } + /** * Returns a proxy object for this node. Allows to access vector elements by * index. @@ -395,6 +404,15 @@ export class StrApi extends NodeApi { return this; } + /** + * Get the length of the string without materializing it to a view. + * + * @returns Length of the string. + */ + public length(): number { + return this.node.length(); + } + /** * Returns a proxy object for this node. */ @@ -445,6 +463,15 @@ export class BinApi extends NodeApi { return this; } + /** + * Get the length of the binary blob without materializing it to a view. + * + * @returns Length of the binary blob. + */ + public length(): number { + return this.node.length(); + } + /** * Returns a proxy object for this node. */ From b900f9da23abbe7fe5288b45e6450f6ebe4b34e3 Mon Sep 17 00:00:00 2001 From: streamich Date: Tue, 28 Nov 2023 11:33:39 +0100 Subject: [PATCH 02/10] =?UTF-8?q?feat(json-crdt):=20=F0=9F=8E=B8=20add=20V?= =?UTF-8?q?ecApi.push()=20helper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__tests__/{TupleApi.spec.ts => VecApi.spec.ts} | 11 +++++++++++ src/json-crdt/model/api/nodes.ts | 7 ++++++- 2 files changed, 17 insertions(+), 1 deletion(-) rename src/json-crdt/model/api/__tests__/{TupleApi.spec.ts => VecApi.spec.ts} (88%) diff --git a/src/json-crdt/model/api/__tests__/TupleApi.spec.ts b/src/json-crdt/model/api/__tests__/VecApi.spec.ts similarity index 88% rename from src/json-crdt/model/api/__tests__/TupleApi.spec.ts rename to src/json-crdt/model/api/__tests__/VecApi.spec.ts index ef4d1d5b56..044b557bfe 100644 --- a/src/json-crdt/model/api/__tests__/TupleApi.spec.ts +++ b/src/json-crdt/model/api/__tests__/VecApi.spec.ts @@ -16,6 +16,17 @@ test('.length()', () => { expect(doc.find.val.vec.toApi().length()).toBe(2); }); +test('.push()', () => { + const doc = Model.withLogicalClock().setSchema(s.obj({ + vec: s.vec(s.con(1), s.con(2)), + })); + expect(doc.view().vec).toEqual([1, 2]); + doc.find.val.vec.toApi().push(3); + expect(doc.view().vec).toEqual([1, 2, 3]); + doc.find.val.vec.toApi().push(4, 5, '6'); + expect(doc.view().vec).toEqual([1, 2, 3, 4, 5, '6']); +}); + describe('events', () => { test('can subscribe and un-subscribe to "view" events', async () => { const doc = Model.withLogicalClock(); diff --git a/src/json-crdt/model/api/nodes.ts b/src/json-crdt/model/api/nodes.ts index ac2966bd8d..56f261b934 100644 --- a/src/json-crdt/model/api/nodes.ts +++ b/src/json-crdt/model/api/nodes.ts @@ -249,7 +249,12 @@ export class VecApi = VecNode> extends NodeApi { entries.map(([index, json]) => [index, builder.constOrJson(json)]), ); api.apply(); - return this; + return this; // TODO: remove this ...? + } + + public push(...values: unknown[]): void { + const length = this.length(); + this.set(values.map((value, index) => [length + index, value])); } /** From 66ccdbb09fb129d2abede10a28552e494d51de8c Mon Sep 17 00:00:00 2001 From: streamich Date: Tue, 28 Nov 2023 11:44:36 +0100 Subject: [PATCH 03/10] =?UTF-8?q?refactor(json-crdt):=20=F0=9F=92=A1=20rem?= =?UTF-8?q?ove=20Readonly<>=20annotations=20for=20node=20views?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/json-crdt/model/api/__tests__/VecApi.spec.ts | 8 ++++++++ src/json-crdt/nodes/arr/ArrNode.ts | 4 ++-- src/json-crdt/nodes/bin/BinNode.ts | 2 +- src/json-crdt/nodes/con/ConNode.ts | 2 +- src/json-crdt/nodes/obj/ObjNode.ts | 8 ++++---- src/json-crdt/nodes/val/ValNode.ts | 6 +++--- src/json-crdt/nodes/vec/VecNode.ts | 4 ++-- 7 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/json-crdt/model/api/__tests__/VecApi.spec.ts b/src/json-crdt/model/api/__tests__/VecApi.spec.ts index 044b557bfe..7d107469e8 100644 --- a/src/json-crdt/model/api/__tests__/VecApi.spec.ts +++ b/src/json-crdt/model/api/__tests__/VecApi.spec.ts @@ -27,6 +27,14 @@ test('.push()', () => { expect(doc.view().vec).toEqual([1, 2, 3, 4, 5, '6']); }); +test('.view() is not readonly', () => { + const doc = Model.withLogicalClock().setSchema(s.obj({ + vec: s.vec(s.con(1), s.con(2)), + })); + const view = doc.find.val.vec.toApi().view(); + view[1] = 12; +}); + describe('events', () => { test('can subscribe and un-subscribe to "view" events', async () => { const doc = Model.withLogicalClock(); diff --git a/src/json-crdt/nodes/arr/ArrNode.ts b/src/json-crdt/nodes/arr/ArrNode.ts index 6b42013a0f..fd06fc4644 100644 --- a/src/json-crdt/nodes/arr/ArrNode.ts +++ b/src/json-crdt/nodes/arr/ArrNode.ts @@ -75,7 +75,7 @@ export class ArrChunk implements Chunk { */ export class ArrNode extends AbstractRga - implements JsonNode[]>>, Printable + implements JsonNode[]>, Printable { constructor(public readonly doc: Model, id: ITimestampStruct) { super(id); @@ -144,7 +144,7 @@ export class ArrNode private _tick: number = 0; /** @ignore */ private _view = Empty; - public view(): Readonly[]> { + public view(): JsonNodeView[] { const doc = this.doc; const tick = doc.clock.time + doc.tick; const _view = this._view; diff --git a/src/json-crdt/nodes/bin/BinNode.ts b/src/json-crdt/nodes/bin/BinNode.ts index 051c1bc594..1149e8c361 100644 --- a/src/json-crdt/nodes/bin/BinNode.ts +++ b/src/json-crdt/nodes/bin/BinNode.ts @@ -77,7 +77,7 @@ export class BinNode extends AbstractRga implements JsonNode { + public view(): Uint8Array { if (this._view) return this._view; const res = new Uint8Array(this.length()); let offset = 0; diff --git a/src/json-crdt/nodes/con/ConNode.ts b/src/json-crdt/nodes/con/ConNode.ts index 2c52f44138..62c15a2d96 100644 --- a/src/json-crdt/nodes/con/ConNode.ts +++ b/src/json-crdt/nodes/con/ConNode.ts @@ -40,7 +40,7 @@ export class ConNode implements JsonNode { + public view(): View { return this.val; } diff --git a/src/json-crdt/nodes/obj/ObjNode.ts b/src/json-crdt/nodes/obj/ObjNode.ts index 88121979d2..fb4ad60a68 100644 --- a/src/json-crdt/nodes/obj/ObjNode.ts +++ b/src/json-crdt/nodes/obj/ObjNode.ts @@ -13,7 +13,7 @@ import type {JsonNode, JsonNodeView} from '..'; */ export class ObjNode = Record> - implements JsonNode>>, Printable + implements JsonNode>, Printable { /** * @ignore @@ -97,17 +97,17 @@ export class ObjNode = Record>; + private _view = {} as JsonNodeView; /** * @ignore */ - public view(): Readonly> { + public view(): JsonNodeView { const doc = this.doc; const tick = doc.clock.time + doc.tick; const _view = this._view; if (this._tick === tick) return _view; - const view = {} as Readonly>; + const view = {} as JsonNodeView; const index = doc.index; let useCache = true; this.keys.forEach((id, key) => { diff --git a/src/json-crdt/nodes/val/ValNode.ts b/src/json-crdt/nodes/val/ValNode.ts index 84122a87b1..a518763c98 100644 --- a/src/json-crdt/nodes/val/ValNode.ts +++ b/src/json-crdt/nodes/val/ValNode.ts @@ -13,7 +13,7 @@ import type {Printable} from '../../../util/print/types'; * * @category CRDT Node */ -export class ValNode implements JsonNode>>, Printable { +export class ValNode implements JsonNode>, Printable { constructor( /** * @ignore @@ -50,8 +50,8 @@ export class ValNode implements JsonNode> { - return this.node()?.view() as Readonly>; + public view(): JsonNodeView { + return this.node()?.view() as JsonNodeView; } /** diff --git a/src/json-crdt/nodes/vec/VecNode.ts b/src/json-crdt/nodes/vec/VecNode.ts index dab0721bef..4b359c5d4c 100644 --- a/src/json-crdt/nodes/vec/VecNode.ts +++ b/src/json-crdt/nodes/vec/VecNode.ts @@ -16,7 +16,7 @@ import type {Printable} from '../../../util/print/types'; * @category CRDT Node */ export class VecNode - implements JsonNode>>, Printable + implements JsonNode>, Printable { /** * @ignore @@ -146,7 +146,7 @@ export class VecNode /** * @ignore */ - public view(): Readonly> { + public view(): JsonNodeView { const extNode = this.ext(); if (extNode) return extNode.view() as any; let useCache = true; From e15fa5dfc5e4fcb6d80864d9463cf46811ecc093 Mon Sep 17 00:00:00 2001 From: streamich Date: Tue, 28 Nov 2023 11:45:00 +0100 Subject: [PATCH 04/10] =?UTF-8?q?style(json-crdt):=20=F0=9F=92=84=20run=20?= =?UTF-8?q?Prettier?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/api/__tests__/BinaryApi.spec.ts | 8 ++++--- .../model/api/__tests__/StringApi.spec.ts | 8 ++++--- .../model/api/__tests__/VecApi.spec.ts | 24 ++++++++++++------- src/json-crdt/model/api/nodes.ts | 2 +- src/json-crdt/nodes/vec/VecNode.ts | 4 +--- 5 files changed, 27 insertions(+), 19 deletions(-) diff --git a/src/json-crdt/model/api/__tests__/BinaryApi.spec.ts b/src/json-crdt/model/api/__tests__/BinaryApi.spec.ts index 41261005b4..ec4f45b498 100644 --- a/src/json-crdt/model/api/__tests__/BinaryApi.spec.ts +++ b/src/json-crdt/model/api/__tests__/BinaryApi.spec.ts @@ -28,8 +28,10 @@ test('can delete across two chunks', () => { }); test('.length()', () => { - const doc = Model.withLogicalClock().setSchema(s.obj({ - bin: s.bin(new Uint8Array([1, 2, 3])), - })); + const doc = Model.withLogicalClock().setSchema( + s.obj({ + bin: s.bin(new Uint8Array([1, 2, 3])), + }), + ); expect(doc.find.val.bin.toApi().length()).toBe(3); }); diff --git a/src/json-crdt/model/api/__tests__/StringApi.spec.ts b/src/json-crdt/model/api/__tests__/StringApi.spec.ts index 0423680c0d..4e1a713def 100644 --- a/src/json-crdt/model/api/__tests__/StringApi.spec.ts +++ b/src/json-crdt/model/api/__tests__/StringApi.spec.ts @@ -27,9 +27,11 @@ test('can delete across two chunks', () => { }); test('.length()', () => { - const doc = Model.withLogicalClock().setSchema(s.obj({ - str: s.str('hello world'), - })); + const doc = Model.withLogicalClock().setSchema( + s.obj({ + str: s.str('hello world'), + }), + ); expect(doc.find.val.str.toApi().length()).toBe(11); }); diff --git a/src/json-crdt/model/api/__tests__/VecApi.spec.ts b/src/json-crdt/model/api/__tests__/VecApi.spec.ts index 7d107469e8..adba25fb01 100644 --- a/src/json-crdt/model/api/__tests__/VecApi.spec.ts +++ b/src/json-crdt/model/api/__tests__/VecApi.spec.ts @@ -10,16 +10,20 @@ test('can edit a tuple', () => { }); test('.length()', () => { - const doc = Model.withLogicalClock().setSchema(s.obj({ - vec: s.vec(s.con(1), s.con(2)), - })); + const doc = Model.withLogicalClock().setSchema( + s.obj({ + vec: s.vec(s.con(1), s.con(2)), + }), + ); expect(doc.find.val.vec.toApi().length()).toBe(2); }); test('.push()', () => { - const doc = Model.withLogicalClock().setSchema(s.obj({ - vec: s.vec(s.con(1), s.con(2)), - })); + const doc = Model.withLogicalClock().setSchema( + s.obj({ + vec: s.vec(s.con(1), s.con(2)), + }), + ); expect(doc.view().vec).toEqual([1, 2]); doc.find.val.vec.toApi().push(3); expect(doc.view().vec).toEqual([1, 2, 3]); @@ -28,9 +32,11 @@ test('.push()', () => { }); test('.view() is not readonly', () => { - const doc = Model.withLogicalClock().setSchema(s.obj({ - vec: s.vec(s.con(1), s.con(2)), - })); + const doc = Model.withLogicalClock().setSchema( + s.obj({ + vec: s.vec(s.con(1), s.con(2)), + }), + ); const view = doc.find.val.vec.toApi().view(); view[1] = 12; }); diff --git a/src/json-crdt/model/api/nodes.ts b/src/json-crdt/model/api/nodes.ts index 56f261b934..23a02771b0 100644 --- a/src/json-crdt/model/api/nodes.ts +++ b/src/json-crdt/model/api/nodes.ts @@ -263,7 +263,7 @@ export class VecApi = VecNode> extends NodeApi { * @returns Length of the vector. */ public length(): number { - return this.node.elements.length + return this.node.elements.length; } /** diff --git a/src/json-crdt/nodes/vec/VecNode.ts b/src/json-crdt/nodes/vec/VecNode.ts index 4b359c5d4c..7e073b03bd 100644 --- a/src/json-crdt/nodes/vec/VecNode.ts +++ b/src/json-crdt/nodes/vec/VecNode.ts @@ -15,9 +15,7 @@ import type {Printable} from '../../../util/print/types'; * * @category CRDT Node */ -export class VecNode - implements JsonNode>, Printable -{ +export class VecNode implements JsonNode>, Printable { /** * @ignore */ From 9be71fd557ac1a511ea1d8ff3da743efcf1c9d57 Mon Sep 17 00:00:00 2001 From: streamich Date: Tue, 28 Nov 2023 14:26:30 +0100 Subject: [PATCH 05/10] =?UTF-8?q?feat(json-crdt):=20=F0=9F=8E=B8=20add=20a?= =?UTF-8?q?bility=20to=20convert=20str=20position=20to=20ID=20and=20back?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{StringApi.spec.ts => StrApi.spec.ts} | 30 ++++++++++++++++ src/json-crdt/model/api/nodes.ts | 35 +++++++++++++++++++ 2 files changed, 65 insertions(+) rename src/json-crdt/model/api/__tests__/{StringApi.spec.ts => StrApi.spec.ts} (77%) diff --git a/src/json-crdt/model/api/__tests__/StringApi.spec.ts b/src/json-crdt/model/api/__tests__/StrApi.spec.ts similarity index 77% rename from src/json-crdt/model/api/__tests__/StringApi.spec.ts rename to src/json-crdt/model/api/__tests__/StrApi.spec.ts index 4e1a713def..e871d3140e 100644 --- a/src/json-crdt/model/api/__tests__/StringApi.spec.ts +++ b/src/json-crdt/model/api/__tests__/StrApi.spec.ts @@ -1,4 +1,5 @@ import {s} from '../../../../json-crdt-patch'; +import {ITimestampStruct} from '../../../../json-crdt-patch/clock'; import {Model} from '../../Model'; test('can edit a simple string', () => { @@ -35,6 +36,35 @@ test('.length()', () => { expect(doc.find.val.str.toApi().length()).toBe(11); }); +describe('position tracking', () => { + test('can convert position into global coordinates and back', () => { + const doc = Model.withLogicalClock().setSchema( + s.obj({ + str: s.str('hello world'), + }), + ); + const str = doc.find.val.str.toApi(); + for (let i = -1; i < str.length(); i++) { + const id = str.findId(i); + expect(str.findPos(id)).toBe(i); + } + }); + + test('shifts position when text is inserted in the middle', () => { + const doc = Model.withLogicalClock().setSchema( + s.obj({ + str: s.str('123456'), + }), + ); + const str = doc.find.val.str.toApi(); + const ids: ITimestampStruct[] = []; + for (let i = -1; i < str.length(); i++) ids.push(str.findId(i)); + str.ins(3, 'abc'); + for (let i = 0; i <= 3; i++) expect(str.findPos(ids[i])).toBe(i - 1); + for (let i = 4; i < ids.length; i++) expect(str.findPos(ids[i])).toBe(i + 3 - 1); + }); +}); + describe('events', () => { test('can subscribe to "view" events', async () => { const doc = Model.withLogicalClock(); diff --git a/src/json-crdt/model/api/nodes.ts b/src/json-crdt/model/api/nodes.ts index 23a02771b0..755c0a328c 100644 --- a/src/json-crdt/model/api/nodes.ts +++ b/src/json-crdt/model/api/nodes.ts @@ -409,6 +409,41 @@ export class StrApi extends NodeApi { return this; } + /** + * Given a character index in local coordinates, find the ID of the character + * in the global coordinates. + * + * @param index Index of the character or `-1` for before the first character. + * @returns ID of the character after which the given position is located. + */ + public findId(index: number | -1): ITimestampStruct { + const node = this.node; + const length = node.length(); + const max = length - 1; + if (index > max) index = max; + if (index < 0) return node.id; + const id = node.find(index); + return id || node.id; + } + + /** + * Given a position in global coordinates, find the position in local + * coordinates. + * + * @param id ID of the character. + * @returns Index of the character in local coordinates. Returns -1 if the + * the position refers to the beginning of the string. + */ + public findPos(id: ITimestampStruct): number | -1 { + const node = this.node; + const nodeId = node.id; + if (nodeId.sid === id.sid && nodeId.time === id.time) return -1; + const chunk = node.findById(id); + if (!chunk) return -1; + const pos = node.pos(chunk); + return pos + (chunk.del ? 0 : id.time - chunk.id.time); + } + /** * Get the length of the string without materializing it to a view. * From fa4a8fba75bb7c302d7589ab99d7fdc0a2cfc238 Mon Sep 17 00:00:00 2001 From: streamich Date: Tue, 28 Nov 2023 15:49:42 +0100 Subject: [PATCH 06/10] =?UTF-8?q?test(json-crdt):=20=F0=9F=92=8D=20fix=20t?= =?UTF-8?q?ests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/json-crdt/model/api/__tests__/ModelApi.proxy.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/json-crdt/model/api/__tests__/ModelApi.proxy.spec.ts b/src/json-crdt/model/api/__tests__/ModelApi.proxy.spec.ts index 053647d147..6c35bf0aec 100644 --- a/src/json-crdt/model/api/__tests__/ModelApi.proxy.spec.ts +++ b/src/json-crdt/model/api/__tests__/ModelApi.proxy.spec.ts @@ -68,7 +68,7 @@ describe('supports all node types', () => { const objApi: ObjApi = obj.toApi(); expect(objApi).toBeInstanceOf(ObjApi); expect(objApi.node).toBeInstanceOf(ObjNode); - const keys = new Set(Object.keys(objApi.view())); + const keys = new Set(Object.keys(objApi.view() as any)); expect(keys.has('obj')).toBe(true); expect(keys.has('vec')).toBe(true); }); @@ -79,7 +79,7 @@ describe('supports all node types', () => { const objApi: ObjApi = obj.toApi(); expect(objApi).toBeInstanceOf(ObjApi); expect(objApi.node).toBeInstanceOf(ObjNode); - const keys = new Set(Object.keys(objApi.view())); + const keys = new Set(Object.keys(objApi.view() as any)); expect(keys.has('str')).toBe(true); expect(keys.has('num')).toBe(true); }); From 1e3d7aa695312c418c2d4800bdc2007773fd56aa Mon Sep 17 00:00:00 2001 From: streamich Date: Tue, 28 Nov 2023 15:57:55 +0100 Subject: [PATCH 07/10] =?UTF-8?q?refactor(json-crdt):=20=F0=9F=92=A1=20har?= =?UTF-8?q?den=20return=20values,=20replace=20void=20by=20undefined?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/json-crdt/nodes/rga/AbstractRga.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/json-crdt/nodes/rga/AbstractRga.ts b/src/json-crdt/nodes/rga/AbstractRga.ts index c4603856c3..27a3347c87 100644 --- a/src/json-crdt/nodes/rga/AbstractRga.ts +++ b/src/json-crdt/nodes/rga/AbstractRga.ts @@ -292,7 +292,7 @@ export abstract class AbstractRga { if (last) this.mergeTombstones2(start, last); } - public find(position: number): void | ITimestampStruct { + public find(position: number): undefined | ITimestampStruct { let curr = this.root; while (curr) { const l = curr.l; @@ -311,9 +311,10 @@ export abstract class AbstractRga { curr = curr.r; } } + return; } - public findChunk(position: number): void | [chunk: Chunk, offset: number] { + public findChunk(position: number): undefined | [chunk: Chunk, offset: number] { let curr = this.root; while (curr) { const l = curr.l; @@ -330,6 +331,7 @@ export abstract class AbstractRga { curr = curr.r; } } + return; } public findInterval(position: number, length: number): ITimespanStruct[] { From a5d8b7534d13f88e7f25fef3c33a3399d86f2e9f Mon Sep 17 00:00:00 2001 From: streamich Date: Tue, 28 Nov 2023 16:19:49 +0100 Subject: [PATCH 08/10] =?UTF-8?q?chore:=20=F0=9F=A4=96=20do=20not=20instal?= =?UTF-8?q?l=20typedoc=20by=20default?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 +-- yarn.lock | 52 +--------------------------------------------------- 2 files changed, 2 insertions(+), 53 deletions(-) diff --git a/package.json b/package.json index 03f4207d33..925e84ba06 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "demo:json-pointer": "ts-node src/json-pointer/__demos__/json-pointer.ts", "demo:reactive-rpc:server": "ts-node src/reactive-rpc/__demos__/server.ts", "coverage": "yarn test --collectCoverage", - "typedoc": "typedoc", + "typedoc": "npx 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", "publish-coverage-and-typedocs": "yarn typedoc && yarn coverage && yarn build:pages && yarn deploy:pages" @@ -152,7 +152,6 @@ "tslib": "^2.5.0", "tslint": "^6.1.3", "tslint-config-common": "^1.6.2", - "typedoc": "^0.25.3", "typescript": "^5.2.2", "uWebSockets.js": "uNetworking/uWebSockets.js#v20.23.0", "webpack": "^5.84.1", diff --git a/yarn.lock b/yarn.lock index cad24e5ea5..6d9eb8c86b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1357,11 +1357,6 @@ ansi-regex@^6.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== -ansi-sequence-parser@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz#e0aa1cdcbc8f8bb0b5bca625aac41f5f056973cf" - integrity sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg== - ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -3701,11 +3696,6 @@ json5@^2.2.3: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== -jsonc-parser@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" - integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w== - jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" @@ -3851,11 +3841,6 @@ lru-cache@^6.0.0: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.3.tgz#b40014d7d2d16d94130b87297a04a1f24874ae7c" integrity sha512-B7gr+F6MkqB3uzINHXNctGieGsRTMwIBgxkp0yq/5BwcuDzD4A8wQpHQW6vDAm1uKSLQghmRdD9sKqf2vJ1cEg== -lunr@^2.3.9: - version "2.3.9" - resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1" - integrity sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow== - make-dir@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" @@ -3893,11 +3878,6 @@ markdown-it@^13.0.1: mdurl "^1.0.1" uc.micro "^1.0.5" -marked@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/marked/-/marked-4.3.0.tgz#796362821b019f734054582038b116481b456cf3" - integrity sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A== - mdn-data@2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" @@ -3982,7 +3962,7 @@ minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" -minimatch@^9.0.1, minimatch@^9.0.3: +minimatch@^9.0.1: version "9.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== @@ -4925,16 +4905,6 @@ shell-quote@^1.8.1: resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== -shiki@^0.14.1: - version "0.14.5" - resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.14.5.tgz#375dd214e57eccb04f0daf35a32aa615861deb93" - integrity sha512-1gCAYOcmCFONmErGTrS1fjzJLA7MGZmKzrBNX7apqSwhyITJg2O102uFzXUeBxNnEkDA9vHIKLyeKq0V083vIw== - dependencies: - ansi-sequence-parser "^1.1.0" - jsonc-parser "^3.2.0" - vscode-oniguruma "^1.7.0" - vscode-textmate "^8.0.0" - side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -5423,16 +5393,6 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typedoc@^0.25.3: - version "0.25.3" - resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.25.3.tgz#53c6d668e1001b3d488e9a750fcdfb05433554c0" - integrity sha512-Ow8Bo7uY1Lwy7GTmphRIMEo6IOZ+yYUyrc8n5KXIZg1svpqhZSWgni2ZrDhe+wLosFS8yswowUzljTAV/3jmWw== - dependencies: - lunr "^2.3.9" - marked "^4.3.0" - minimatch "^9.0.3" - shiki "^0.14.1" - typescript@^5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" @@ -5536,16 +5496,6 @@ vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== -vscode-oniguruma@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz#439bfad8fe71abd7798338d1cd3dc53a8beea94b" - integrity sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA== - -vscode-textmate@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-8.0.0.tgz#2c7a3b1163ef0441097e0b5d6389cd5504b59e5d" - integrity sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg== - walker@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" From 39aa560c9f041f7ca2472e22eca274b4939622d1 Mon Sep 17 00:00:00 2001 From: streamich Date: Tue, 28 Nov 2023 19:54:51 +0100 Subject: [PATCH 09/10] =?UTF-8?q?chore:=20=F0=9F=A4=96=20imrove=20CRDT=20e?= =?UTF-8?q?xports=20from=20index=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/json-crdt-patch/index.ts | 1 + src/json-crdt/codec/indexed/binary/index.ts | 3 +++ src/json-crdt/codec/sidecar/binary/index.ts | 2 ++ src/json-crdt/codec/structural/binary/index.ts | 4 ++++ src/json-crdt/codec/structural/compact/index.ts | 3 +++ src/json-crdt/codec/structural/verbose/index.ts | 3 +++ src/json-crdt/index.ts | 2 ++ tsconfig.json | 7 +++++-- 8 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 src/json-crdt/codec/indexed/binary/index.ts create mode 100644 src/json-crdt/codec/sidecar/binary/index.ts create mode 100644 src/json-crdt/codec/structural/binary/index.ts create mode 100644 src/json-crdt/codec/structural/compact/index.ts create mode 100644 src/json-crdt/codec/structural/verbose/index.ts diff --git a/src/json-crdt-patch/index.ts b/src/json-crdt-patch/index.ts index 5f8fd62ae4..cac23a2810 100644 --- a/src/json-crdt-patch/index.ts +++ b/src/json-crdt-patch/index.ts @@ -111,6 +111,7 @@ */ export * from './types'; +export * from './clock'; export * from './operations'; export * from './Patch'; export * from './PatchBuilder'; diff --git a/src/json-crdt/codec/indexed/binary/index.ts b/src/json-crdt/codec/indexed/binary/index.ts new file mode 100644 index 0000000000..95ace423f7 --- /dev/null +++ b/src/json-crdt/codec/indexed/binary/index.ts @@ -0,0 +1,3 @@ +export * from './types'; +export * from './Encoder'; +export * from './Decoder'; diff --git a/src/json-crdt/codec/sidecar/binary/index.ts b/src/json-crdt/codec/sidecar/binary/index.ts new file mode 100644 index 0000000000..337c46079c --- /dev/null +++ b/src/json-crdt/codec/sidecar/binary/index.ts @@ -0,0 +1,2 @@ +export * from './Encoder'; +export * from './Decoder'; diff --git a/src/json-crdt/codec/structural/binary/index.ts b/src/json-crdt/codec/structural/binary/index.ts new file mode 100644 index 0000000000..3bf5ef8d7e --- /dev/null +++ b/src/json-crdt/codec/structural/binary/index.ts @@ -0,0 +1,4 @@ +export * from './constants'; +export * from './Encoder'; +export * from './Decoder'; +export * from './ViewDecoder'; diff --git a/src/json-crdt/codec/structural/compact/index.ts b/src/json-crdt/codec/structural/compact/index.ts new file mode 100644 index 0000000000..95ace423f7 --- /dev/null +++ b/src/json-crdt/codec/structural/compact/index.ts @@ -0,0 +1,3 @@ +export * from './types'; +export * from './Encoder'; +export * from './Decoder'; diff --git a/src/json-crdt/codec/structural/verbose/index.ts b/src/json-crdt/codec/structural/verbose/index.ts new file mode 100644 index 0000000000..95ace423f7 --- /dev/null +++ b/src/json-crdt/codec/structural/verbose/index.ts @@ -0,0 +1,3 @@ +export * from './types'; +export * from './Encoder'; +export * from './Decoder'; diff --git a/src/json-crdt/index.ts b/src/json-crdt/index.ts index 9a53cede7d..aef4b139ce 100644 --- a/src/json-crdt/index.ts +++ b/src/json-crdt/index.ts @@ -1,3 +1,5 @@ export * from './nodes'; export * from './extensions/types'; export * from './model'; + +export * from '../json-crdt-patch'; diff --git a/tsconfig.json b/tsconfig.json index 360473d009..fbb26b92f5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -42,8 +42,11 @@ "entryPoints": [ "src/binary-rx/index.ts", "src/json-crdt/index.ts", - "src/json-crdt-patch/index.ts", - "src/json-crdt-patch/clock/index.ts", + "src/json-crdt/codec/structural/binary/index.ts", + "src/json-crdt/codec/structural/compact/index.ts", + "src/json-crdt/codec/structural/verbose/index.ts", + "src/json-crdt/codec/indexed/binary/index.ts", + "src/json-crdt/codec/sidecar/binary/index.ts", "src/json-crdt-patch/codec/json/index.ts", "src/json-crdt-patch/codec/compact/index.ts", "src/json-crdt-patch/codec/binary/index.ts", From 7e190c6f0eea5ed3bbb7402cbd7fb3a71ce223c4 Mon Sep 17 00:00:00 2001 From: streamich Date: Tue, 28 Nov 2023 19:56:16 +0100 Subject: [PATCH 10/10] =?UTF-8?q?docs(json-crdt-patch):=20=E2=9C=8F?= =?UTF-8?q?=EF=B8=8F=20fix=20verbose=20encoding=20path?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index fbb26b92f5..784aaa52d8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -47,7 +47,7 @@ "src/json-crdt/codec/structural/verbose/index.ts", "src/json-crdt/codec/indexed/binary/index.ts", "src/json-crdt/codec/sidecar/binary/index.ts", - "src/json-crdt-patch/codec/json/index.ts", + "src/json-crdt-patch/codec/verbose/index.ts", "src/json-crdt-patch/codec/compact/index.ts", "src/json-crdt-patch/codec/binary/index.ts", "src/json-pack/index.ts",