@y/y
Version:
Shared Editing Library
420 lines • 15.1 kB
TypeScript
/**
* @typedef {{ inserts: IdSet, deletes: IdSet }} ContentIds
*/
/**
* @typedef {{ inserts: IdMap<any>, deletes: IdMap<any> }} ContentMap
*/
export class IdRange {
/**
* @param {number} clock
* @param {number} len
*/
constructor(clock: number, len: number);
/**
* @type {number}
*/
clock: number;
/**
* @type {number}
*/
len: number;
/**
* @param {number} clock
* @param {number} len
*/
copyWith(clock: number, len: number): IdRange;
/**
* Helper method making this compatible with IdMap.
*
* @return {Array<ContentAttribute<any>>}
*/
get attrs(): Array<ContentAttribute<any>>;
}
export class MaybeIdRange {
/**
* @param {number} clock
* @param {number} len
* @param {boolean} exists
*/
constructor(clock: number, len: number, exists: boolean);
/**
* @type {number}
*/
clock: number;
/**
* @type {number}
*/
len: number;
/**
* @type {boolean}
*/
exists: boolean;
}
export function createMaybeIdRange(clock: number, len: number, exists: boolean): MaybeIdRange;
export class IdRanges {
/**
* @param {Array<IdRange>} ids
*/
constructor(ids: Array<IdRange>);
sorted: boolean;
/**
* A typical use-case for IdSet is to append data. We heavily optimize this case by allowing the
* last item to be mutated if it isn't used currently.
* This flag is true if the last item was exposed to the outside.
*/
_lastIsUsed: boolean;
/**
* @private
*/
private _ids;
copy(): IdRanges;
/**
* @param {number} clock
* @param {number} length
*/
add(clock: number, length: number): void;
/**
* Return the list of immutable id ranges, sorted and merged.
*/
getIds(): IdRange[];
/**
* Test a predicate against every attribute held by these ranges. Does not mutate - see
* {@link AttrRanges#everyAttr}.
*
* This exists because an `IdMap` may hold `IdRanges`: {@link insertIntoIdMap}'s `src` may be an
* `IdSet`, and `_insertIntoIdSet` picks the container class from whichever `src` reaches a client
* first. For a pure `IdRanges` the loop is vacuous ({@link IdRange#attrs} is always `[]`), but it
* must *not* shortcut to `true`: the append branch of `_insertIntoIdSet` copies elements without
* checking their class, so an `IdRanges` reached by an `IdSet` first and an `IdMap` second holds
* real `AttrRange`s - which {@link $idMap} must still validate.
*
* @param {(attr:ContentAttribute<any>) => boolean} f
* @return {boolean}
*/
everyAttr(f: (attr: ContentAttribute<any>) => boolean): boolean;
}
/**
* @implements {traits.EqualityTrait}
*/
export class IdSet implements traits.EqualityTrait {
/**
* @type {Map<number,IdRanges>}
*/
clients: Map<number, IdRanges>;
isEmpty(): boolean;
/**
* @param {(idrange:IdRange, client:number) => void} f
*/
forEach(f: (idrange: IdRange, client: number) => void): void;
/**
* @param {ID} id
* @return {boolean}
*/
hasId(id: ID): boolean;
/**
* @param {number} client
* @param {number} clock
*/
has(client: number, clock: number): boolean;
/**
* Whether any id in the range `[clock, clock+len)` of `client` is contained in this set.
* Allocation-free (binary search).
*
* @param {number} client
* @param {number} clock
* @param {number} len
* @return {boolean}
*/
intersects(client: number, clock: number, len: number): boolean;
/**
* Whether the entire range `[clock, clock+len)` of `client` is contained in this set.
* Allocation-free (binary search). Because `getIds()` returns maximal, merged ranges, full
* coverage of a range implies it lies within a single range.
*
* @param {number} client
* @param {number} clock
* @param {number} len
* @return {boolean}
*/
covers(client: number, clock: number, len: number): boolean;
/**
* Total number of ids in `[clock, clock+len)` of `client` contained in this set.
* Allocation-free (binary search + linear scan of the overlapping ranges). Equivalent to
* `slice(client, clock, len).reduce((s, r) => r.exists ? s + r.len : s, 0)` without allocating.
*
* @param {number} client
* @param {number} clock
* @param {number} len
* @return {number}
*/
coveredLength(client: number, clock: number, len: number): number;
/**
* Return slices of ids that exist in this idset.
*
* @param {number} client
* @param {number} clock
* @param {number} len
* @return {Array<MaybeIdRange>}
*/
slice(client: number, clock: number, len: number): Array<MaybeIdRange>;
/**
* @param {number} client
* @param {number} clock
* @param {number} len
*/
add(client: number, clock: number, len: number): void;
/**
* @param {number} client
* @param {number} clock
* @param {number} len
*/
delete(client: number, clock: number, len: number): void;
$type: s.Schema<IdSet>;
/**
* @param {any} other
*/
[traits.EqualityTraitSymbol](other: any): boolean;
}
export function equalIdSets(ds1: IdSet, ds2: IdSet): boolean;
export function _deleteRangeFromIdSet(set: IdSet | IdMap<any>, client: number, clock: number, len: number): void;
export function iterateStructsByIdSet(transaction: Transaction, ds: IdSet, f: (arg0: GC | Item) => void): void;
export function gcIdSet(doc: Doc, ids: IdSet, gcFilter?: (arg0: Item) => boolean): void;
export function iterateStructsByIdSetWithoutSplits(store: StructStore, ds: IdSet, f: (struct: GC | Item | Skip, offset: number, len: number) => void): void;
export function findIndexInIdRanges(dis: Array<IdRange>, clock: number): number | null;
export function findRangeStartInIdRanges(dis: Array<IdRange>, clock: number): number | null;
export function mergeIdSets(idSets: Array<IdSet>): IdSet;
/**
* @template {IdSet | IdMap<any>} S
* @param {S} dest
* @param {S} src
*/
export function insertIntoIdSet<S extends IdSet | IdMap<any>>(dest: S, src: S): void;
/**
* Note that `src` may be an `IdSet`, in which case `dest` ends up holding `IdRanges` - which carry
* no attributes ({@link IdRange#attrs} is `[]`). This is by design; {@link $idMap} tolerates it.
*
* @type {(dest: IdMap<any>, src: IdMap<any>|IdSet) => void}
*/
export const insertIntoIdMap: (dest: IdMap<any>, src: IdMap<any> | IdSet) => void;
export function _diffSet<Set extends IdSet | IdMap<any>>(set: Set, exclude: IdSet | IdMap<any>): Set;
/**
* Remove all ranges from `exclude` from `idSet`. The result is a fresh IdSet containing all ranges from `idSet` that are not
* in `exclude`.
*
* @type {(idSet: IdSet, exclude: IdSet|IdMap<any>) => IdSet}
*/
export const diffIdSet: (idSet: IdSet, exclude: IdSet | IdMap<any>) => IdSet;
export function _intersectSets<SetA extends IdSet | IdMap<any>, SetB extends IdSet | IdMap<any>>(setA: SetA, setB: SetB): SetA extends IdMap<infer A> ? (SetB extends IdMap<infer B> ? IdMap<A | B> : IdMap<A>) : IdSet;
export function intersectSets<SetA extends IdSet | IdMap<any>, SetB extends IdSet | IdMap<any>>(setA: SetA, setB: SetB): SetA extends IdMap<infer A> ? (SetB extends IdMap<infer B> ? IdMap<A | B> : IdMap<A>) : IdSet;
export function createIdSet(): IdSet;
export function createDeleteSetFromStructStore(ss: StructStore): IdSet;
export function _createInsertSliceFromStructs(structs: Array<GC | Item | Skip>, filterDeleted: boolean): IdRange[];
export function createInsertSetFromStructStore(ss: StructStore, filterDeleted: boolean): IdSet;
export function writeIdSet(encoder: IdSetEncoderV1 | IdSetEncoderV2, idSet: IdSet): void;
export function readIdSet(decoder: IdSetDecoderV1 | IdSetDecoderV2): IdSet;
export function encodeIdSet(idSet: IdSet): Uint8Array<ArrayBuffer>;
export function decodeIdSet(data: Uint8Array): IdSet;
export function readAndApplyDeleteSet(decoder: IdSetDecoderV1 | IdSetDecoderV2, transaction: Transaction, store: StructStore): Uint8Array<ArrayBuffer> | null;
/**
* @template Attrs
*/
export class AttrRange<Attrs> {
/**
* @param {number} clock
* @param {number} len
* @param {Array<ContentAttribute<Attrs>>} attrs
*/
constructor(clock: number, len: number, attrs: Array<ContentAttribute<Attrs>>);
/**
* @readonly
*/
readonly clock: number;
/**
* @readonly
*/
readonly len: number;
/**
* @readonly
*/
readonly attrs: ContentAttribute<Attrs>[];
/**
* @param {number} clock
* @param {number} len
*/
copyWith(clock: number, len: number): AttrRange<Attrs>;
}
/**
* @todo rename this to `Attribute`
* @template V
*/
export class ContentAttribute<V> {
/**
* @param {string} name
* @param {V} val
*/
constructor(name: string, val: V);
name: string;
val: V;
hash(): string;
}
export function createContentAttribute<V>(name: string, val: V): ContentAttribute<V>;
export function createMaybeAttrRange<Attrs>(clock: number, len: number, attrs: Array<ContentAttribute<Attrs>> | null): MaybeAttrRange<Attrs>;
/**
* Whenever this is instantiated, it must receive a fresh array of ops, not something copied.
*
* @template Attrs
*/
export class AttrRanges<Attrs> {
/**
* @param {Array<AttrRange<Attrs>>} ids
*/
constructor(ids: Array<AttrRange<Attrs>>);
sorted: boolean;
/**
* @private
*/
private _ids;
copy(): AttrRanges<Attrs>;
/**
* @param {number} clock
* @param {number} length
* @param {Array<ContentAttribute<Attrs>>} attrs
*/
add(clock: number, length: number, attrs: Array<ContentAttribute<Attrs>>): void;
/**
* Return the list of id ranges, sorted and merged.
*/
getIds(): AttrRange<Attrs>[];
/**
* Test a predicate against every attribute held by these ranges.
*
* Unlike {@link AttrRanges#getIds} this does **not** sort/merge - i.e. it does not mutate its
* receiver, which matters because it backs {@link $idMap}`.check`. The *set* of attributes is
* invariant under sorting/merging (merging only ever concatenates existing attr arrays), so this
* observes exactly the attributes that `getIds()` would expose.
*
* @param {(attr:ContentAttribute<Attrs>) => boolean} f
* @return {boolean}
*/
everyAttr(f: (attr: ContentAttribute<Attrs>) => boolean): boolean;
}
/**
* @template Attrs
*/
export class IdMap<Attrs> {
/**
* @type {Map<number,AttrRanges<Attrs>>}
*/
clients: Map<number, AttrRanges<Attrs>>;
/**
* @type {Map<string, ContentAttribute<Attrs>>}
*/
attrsH: Map<string, ContentAttribute<Attrs>>;
/**
* @type {Set<ContentAttribute<Attrs>>}
*/
attrs: Set<ContentAttribute<Attrs>>;
/**
* @param {(attrRange:AttrRange<Attrs>, client:number) => void} f
*/
forEach(f: (attrRange: AttrRange<Attrs>, client: number) => void): void;
isEmpty(): boolean;
/**
* @param {ID} id
* @return {boolean}
*/
hasId(id: ID): boolean;
/**
* @param {number} client
* @param {number} clock
* @return {boolean}
*/
has(client: number, clock: number): boolean;
/**
* Total number of ids in `[clock, clock+len)` of `client` contained in this map (i.e. carrying
* an attribution, incl. an empty `[]`). Allocation-free (binary search + linear scan).
* Equivalent to `slice(client, clock, len).reduce((s, r) => r.attrs != null ? s + r.len : s, 0)`
* without allocating.
*
* @param {number} client
* @param {number} clock
* @param {number} len
* @return {number}
*/
coveredLength(client: number, clock: number, len: number): number;
/**
* Return attributions for a slice of ids.
*
* @param {ID} id
* @param {number} len
* @return {Array<MaybeAttrRange<Attrs>>}
*/
sliceId(id: ID, len: number): Array<MaybeAttrRange<Attrs>>;
/**
* Return attributions for a slice of ids.
*
* @param {number} client
* @param {number} clock
* @param {number} len
* @return {Array<MaybeAttrRange<Attrs>>}
*/
slice(client: number, clock: number, len: number): Array<MaybeAttrRange<Attrs>>;
/**
* @param {number} client
* @param {number} clock
* @param {number} len
* @param {Array<ContentAttribute<Attrs>>} attrs
*/
add(client: number, clock: number, len: number, attrs: Array<ContentAttribute<Attrs>>): void;
/**
* @param {number} client
* @param {number} clock
* @param {number} len
*/
delete(client: number, clock: number, len: number): void;
$type: s.Schema<IdMap<any>>;
}
export function idmapAttrsEqual<T>(a: Array<T>, b: Array<T>): boolean;
export function mergeIdMaps<T>(ams: Array<IdMap<T>>): IdMap<T>;
export function createIdMapFromIdSet(idset: IdSet, attrs: Array<ContentAttribute<any>>): IdMap<any>;
export function createIdSetFromIdMap(idmap: IdMap<any>): IdSet;
export function writeIdMap<Attr>(encoder: IdSetEncoderV1 | IdSetEncoderV2, idmap: IdMap<Attr>): void;
export function encodeIdMap(idmap: IdMap<any>): Uint8Array<ArrayBuffer>;
export function readIdMap(decoder: IdSetDecoderV1 | IdSetDecoderV2): IdMap<any>;
export function decodeIdMap(data: Uint8Array): IdMap<any>;
export function createIdMap(): IdMap<any>;
export function diffIdMap<ISet extends IdMap<any>>(set: ISet, exclude: IdSet | IdMap<any>): ISet;
export function intersectMaps<SetA extends IdSet | IdMap<any>, SetB extends IdSet | IdMap<any>>(setA: SetA, setB: SetB): SetA extends IdMap<infer A> ? (SetB extends IdMap<infer B> ? IdMap<A | B> : IdMap<A>) : IdSet;
export function filterIdMap<Attrs>(idmap: IdMap<Attrs>, predicate: (attr: Array<ContentAttribute<Attrs>>) => boolean): IdMap<Attrs>;
/**
* Schema of an {@link IdSet}.
*
* Nominal: `check` is a single identity compare against the globally interned `y:idSet` tag, so it
* stays sound across duplicate yjs installations (unlike `instanceof`) - the same reason
* {@link $renderer} uses `$type`.
*/
export const $idSet: s.Schema<IdSet>;
/**
* Schema of an {@link IdMap} with any mapped-value type. This is where the nominal `y:idMap` tag
* lives - {@link $idMap} builds on it. Mirrors lib0's `$deltaAny` / `$delta` split.
*/
export const $idMapAny: s.Schema<IdMap<any>>;
export function $idMap<Attrs>($attrs: s.Schema<Attrs>): s.Schema<IdMap<Attrs>>;
export type ContentIds = {
inserts: IdSet;
deletes: IdSet;
};
export type ContentMap = {
inserts: IdMap<any>;
deletes: IdMap<any>;
};
export type MaybeAttrRange<Attrs> = {
clock: number;
len: number;
attrs: Array<ContentAttribute<Attrs>> | null;
};
import * as traits from 'lib0/traits';
import * as s from 'lib0/schema';
import { IdSetEncoderV2 } from './UpdateEncoder.js';
import { IdSetDecoderV2 } from './UpdateDecoder.js';
//# sourceMappingURL=ids.d.ts.map