UNPKG

json-joy

Version:

Collection of libraries for building collaborative editing apps.

127 lines (126 loc) 5.67 kB
import { type ITimestampStruct, type ITimespanStruct } from '../../../json-crdt-patch/clock'; /** * @category CRDT Node */ export interface Chunk<T> { /** Unique sortable ID of this chunk and its span. */ id: ITimestampStruct; /** Length of the logical clock interval of this chunk. */ span: number; /** Whether this chunk is deleted. */ del: boolean; /** Actual content of the chunk, may be undefined if chunk is deleted. */ data: T | undefined; /** Length of content in this subtree (this node and its children). */ len: number; /** Parent. */ p: Chunk<T> | undefined; /** Left. */ l: Chunk<T> | undefined; /** Right. */ r: Chunk<T> | undefined; /** Parent 2. */ p2: Chunk<T> | undefined; /** Left 2. */ l2: Chunk<T> | undefined; /** Right 2. */ r2: Chunk<T> | undefined; /** Split link, next chunk which was split from this chunk. */ s: Chunk<T> | undefined; /** Add more content to this chunk. */ merge(content: T): void; /** * Split this chunk after given clock ticks. Minimal `ticks` is 1. */ split(ticks: number): Chunk<T>; /** Mark chunk as deleted. */ delete(): void; /** Return a deep copy of itself. */ clone(): Chunk<T>; /** Return the data of the chunk, if not deleted. */ view(): T & { slice: (start: number, end: number) => T; }; } /** * @category CRDT Node */ export declare abstract class AbstractRga<T> { readonly id: ITimestampStruct; root: Chunk<T> | undefined; ids: Chunk<T> | undefined; count: number; abstract view(): unknown; protected abstract createChunk(id: ITimestampStruct, content: T | undefined): Chunk<T>; protected abstract onChange(): void; constructor(id: ITimestampStruct); ins(after: ITimestampStruct, id: ITimestampStruct, content: T): void; insAt(position: number, id: ITimestampStruct, content: T): ITimestampStruct | undefined; protected insAfterRoot(after: ITimestampStruct, id: ITimestampStruct, content: T): void; protected insAfterChunk(after: ITimestampStruct, chunk: Chunk<T>, chunkOffset: number, id: ITimestampStruct, content: T): void; delete(spans: ITimespanStruct[]): void; protected deleteSpan(span: ITimespanStruct): void; find(position: number): undefined | ITimestampStruct; findChunk(position: number): undefined | [chunk: Chunk<T>, offset: number]; findInterval(position: number, length: number): ITimespanStruct[]; /** Rename to .rangeX() method? */ findInterval2(from: ITimestampStruct, to: ITimestampStruct): ITimespanStruct[]; /** * @note All ".rangeX()" method are not performance optimized. For hot paths * it is better to hand craft the loop. * * @param startChunk Chunk from which to start the range. If undefined, the * chunk containing `from` will be used. This is an optimization * to avoid a lookup. * @param from ID of the first element in the range. * @param to ID of the last element in the range. * @param callback Function to call for each chunk slice in the range. If it * returns truthy value, the iteration will stop. * @returns Reference to the last chunk in the range. */ range0(startChunk: Chunk<T> | undefined, from: ITimestampStruct, to: ITimestampStruct, callback: (chunk: Chunk<T>, off: number, len: number) => boolean | void): Chunk<T> | void; first(): Chunk<T> | undefined; last(): Chunk<T> | undefined; lastId(): ITimestampStruct | undefined; /** @todo Maybe use implementation from tree utils, if does not impact performance. */ /** @todo Or better remove this method completely, as it does not require "this". */ next(curr: Chunk<T>): Chunk<T> | undefined; /** @todo Maybe use implementation from tree utils, if does not impact performance. */ /** @todo Or better remove this method completely, as it does not require "this". */ prev(curr: Chunk<T>): Chunk<T> | undefined; /** Content length. */ length(): number; /** Number of chunks. */ size(): number; /** Returns the position of the first element in the chunk. */ pos(chunk: Chunk<T>): number; setRoot(chunk: Chunk<T>): void; insertBefore(chunk: Chunk<T>, before: Chunk<T>): void; insertAfter(chunk: Chunk<T>, after: Chunk<T>): void; protected insertAfterRef(chunk: Chunk<T>, ref: ITimestampStruct, left: Chunk<T>): void; protected mergeContent(chunk: Chunk<T>, content: T): void; protected insertInside(chunk: Chunk<T>, at: Chunk<T>, offset: number): void; protected split(chunk: Chunk<T>, ticks: number): Chunk<T>; protected mergeTombstones(ch1: Chunk<T>, ch2: Chunk<T>): boolean; protected mergeTombstones2(start: Chunk<T>, end: Chunk<T>): void; removeTombstones(): void; deleteChunk(chunk: Chunk<T>): void; insertId(chunk: Chunk<T>): void; insertIdFast(chunk: Chunk<T>): void; protected deleteId(chunk: Chunk<T>): void; findById(after: ITimestampStruct): Chunk<T> | undefined; /** * @param id ID of character to start the search from. * @returns Previous ID in the RGA sequence. */ prevId(id: ITimestampStruct): ITimestampStruct | undefined; spanView(span: ITimespanStruct): T[]; splay(chunk: Chunk<T>): void; iterator(): () => Chunk<T> | undefined; ingest(size: number, next: () => Chunk<T>): void; private _ingest; protected toStringName(): string; toString(tab?: string): string; protected printChunk(tab: string, chunk: Chunk<T>): string; protected formatChunk(chunk: Chunk<T>): string; }