All files / json-crdt/nodes/str StrNode.ts

97.87% Statements 46/47
75% Branches 6/8
93.33% Functions 14/15
97.77% Lines 44/45

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127175x 175x 175x             175x                             3099750x 3099750x 3099750x 3099750x 3099750x 3099750x 3099750x 3099750x 3099750x 3099750x 3099750x 3099750x       750718x 750718x       749338x 658774x 658774x 658774x 658774x   90564x 90564x 90564x       746267x 746267x       14x 14x       7636x                   175x                         1x       208759x   194148x 174984x 174984x   3827044x 174984x       208759x     5023x             1598917x         2094558x       2513x      
import {type ITimestampStruct, tick} from '../../../json-crdt-patch/clock';
import {AbstractRga, type Chunk} from '../rga/AbstractRga';
import {next} from 'sonic-forest/lib/util';
import type {JsonNode} from '..';
 
/**
 * @ignore
 * @category CRDT Node
 */
export class StrChunk implements Chunk<string> {
  public readonly id: ITimestampStruct;
  public span: number;
  public del: boolean;
  public data: string;
  public len: number;
  public p: StrChunk | undefined;
  public l: StrChunk | undefined;
  public r: StrChunk | undefined;
  public p2: StrChunk | undefined;
  public l2: StrChunk | undefined;
  public r2: StrChunk | undefined;
  public s: StrChunk | undefined;
 
  constructor(id: ITimestampStruct, span: number, str: string) {
    this.id = id;
    this.span = span;
    this.len = str ? span : 0;
    this.del = !str;
    this.p = undefined;
    this.l = undefined;
    this.r = undefined;
    this.p2 = undefined;
    this.l2 = undefined;
    this.r2 = undefined;
    this.s = undefined;
    this.data = str;
  }
 
  public merge(str: string) {
    this.data += str;
    this.span = this.data.length;
  }
 
  public split(ticks: number): StrChunk {
    if (!this.del) {
      const chunk = new StrChunk(tick(this.id, ticks), this.span - ticks, this.data.slice(ticks));
      this.data = this.data.slice(0, ticks);
      this.span = ticks;
      return chunk;
    }
    const chunk = new StrChunk(tick(this.id, ticks), this.span - ticks, '');
    this.span = ticks;
    return chunk;
  }
 
  public delete(): void {
    this.del = true;
    this.data = '';
  }
 
  public clone(): StrChunk {
    const chunk = new StrChunk(this.id, this.span, this.data);
    return chunk;
  }
 
  public view(): string {
    return this.data;
  }
}
 
/**
 * Represents the `str` type in JSON CRDT. The `str` type is a RGA (Replicated
 * Growable Array) of UTF-16 code units.
 *
 * @category CRDT Node
 */
export class StrNode<T extends string = string> extends AbstractRga<string> implements JsonNode<string> {
  // ----------------------------------------------------------------- JsonNode
 
  /** @ignore */
  public children() {}
 
  /** @ignore */
  public child() {
    return undefined;
  }
 
  /** @ignore */
  public container(): JsonNode | undefined {
    return undefined;
  }
 
  /** @ignore */
  private _view: string = '';
  public view(): T {
    if (this._view) return this._view as T;
    let str = '';
    for (let chunk = this.first(); chunk; chunk = next(chunk))
      // TODO: Check if this optimization improves performance: if (!chunk.del) str += chunk.data;
      str += chunk.data;
    return (this._view = str) as T;
  }
 
  /** @ignore */
  public api: undefined | unknown = undefined;
 
  public name(): string {
    return 'str';
  }
 
  // -------------------------------------------------------------- AbstractRga
 
  /** @ignore */
  public createChunk(id: ITimestampStruct, str: string | undefined): StrChunk {
    return new StrChunk(id, str ? str.length : 0, str || '');
  }
 
  /** @ignore */
  protected onChange(): void {
    this._view = '';
  }
 
  protected toStringName(): string {
    return this.name();
  }
}