UNPKG

fugue

Version:

Fractional indexing without conflicts.

124 lines (122 loc) 4.25 kB
declare const FIRST = ""; declare const LAST = "~"; type FuguePosition<TClientID extends string = string> = `${string}${TClientID}.${string}` | typeof FIRST | typeof LAST; type FugueOptions<TClientID extends string = string> = { /** * The unique ID for this client. */ clientID: TClientID; }; declare class Fugue<TClientID extends string = string> { /** * A string that is less than all positions. */ static readonly FIRST = ""; /** * A string that is greater than all positions. */ static readonly LAST = "~"; /** * The unique ID for this client. */ readonly clientID: TClientID; /** * The waypoints' long name: `,${clientID}.`. */ private readonly longName; /** * Variant of longName used for a position's first ID: `${clientID}.`. * (Otherwise every position would start with a redundant ','.) */ private readonly firstName; /** * For each waypoint that we created, maps a prefix (see getPrefix) * for that waypoint to its last (most recent) valueSeq. * We always store the right-side version (odd valueSeq). */ private lastValueSeqs; private readonly maxCachedPrefixes; constructor(clientID: TClientID); /** * Creates a new position between two existing positions. * The new position will be greater than `a` and less than `b`. * * @param a - An existing position to insert after, or null to insert at the beginning * @param b - An existing position to insert before, or null to insert at the end * @returns A new position that satisfies `a < new < b` * * @example * ```typescript * const fugue = new Fugue("client1"); * const pos1 = fugue.between(null, null); // First position * const pos2 = fugue.between(pos1, null); // Insert after pos1 * const pos3 = fugue.between(pos1, pos2); // Insert between pos1 and pos2 * // pos1 < pos3 < pos2 * ``` * * @throws Will warn and adjust inputs if: * - `a >= b` (when both are non-null) * - `b > Fugue.LAST` */ between(a: string | null, b: string | null): FuguePosition<TClientID> & {}; /** * Creates a new position immediately after the given position. * This is equivalent to calling `between(position, null)`. * * @param position - The existing position to insert after * @returns A new position that is greater than the given position * * @example * ```typescript * const fugue = new Fugue("client1"); * const pos1 = fugue.between(null, null); // First position * const pos2 = fugue.after(pos1); // Insert after pos1 * // pos1 < pos2 * ``` */ after(position: string): "" | "~" | `${string}${TClientID}.${string}`; /** * Creates a new position immediately before the given position. * This is equivalent to calling `between(null, position)`. * * @param position - The existing position to insert before * @returns A new position that is less than the given position * * @example * ```typescript * const fugue = new Fugue("client1"); * const pos1 = fugue.between(null, null); // First position * const pos2 = fugue.before(pos1); // Insert before pos1 * // pos2 < pos1 * ``` */ before(position: string): "" | "~" | `${string}${TClientID}.${string}`; /** * Creates the first position in a sequence. * This is equivalent to calling `between(null, null)`. * * @returns A new position that is greater than all existing positions * * @example * ```typescript * const fugue = new Fugue("client1"); * const pos1 = fugue.first(); // First position * const pos2 = fugue.after(pos1); // Insert after pos1 * // pos1 < pos2 * ``` */ first(): "" | "~" | `${string}${TClientID}.${string}`; /** * Appends a waypoint to the ancestor. */ private appendWaypoint; /** * The number of prefixes in the cache. */ get cacheSize(): number; /** * Cleans up the cache of last value sequences. */ private cleanupLastValueSeqs; } export { Fugue, type FugueOptions, type FuguePosition };