All files / istanbul-lib-report/src/reports/html insertion-text.ts

100% Statements 55/55
100% Branches 27/27
100% Functions 9/9
100% Lines 55/55

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 127 128 129 130                      11x                     36x 36x 36x 36x 36x 36x       36x 36x 36x   36x 191x 27x 27x     36x       36x 36x 36x   36x 43x 27x 27x     36x       50x       44x 44x 44x   44x 14x 5x   14x 6x       44x 44x 44x 44x 44x 44x       44x   44x     44x 30x 30x 26x   30x 9x     44x 8x   36x   44x                   14x 14x 14x       1x       28x          
/*
 Copyright 2012-2015, Yahoo Inc.
 Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
 */
 
/** a pending insertion offset tracked by {@link InsertionText} */
interface InsertionOffset {
  pos: number;
  len: number;
}
 
const WHITE_RE = /[ \f\n\r\t\v\u00A0\u2028\u2029]/;
 
class InsertionText {
  declare text: string;
  declare origLength: number;
  declare offsets: InsertionOffset[];
  declare consumeBlanks: boolean | undefined;
  declare startPos: number;
  declare endPos: number;
 
  constructor(text: string, consumeBlanks?: boolean) {
    this.text = text;
    this.origLength = text.length;
    this.offsets = [];
    this.consumeBlanks = consumeBlanks;
    this.startPos = this.findFirstNonBlank();
    this.endPos = this.findLastNonBlank();
  }
 
  findFirstNonBlank(): number {
    let pos = -1;
    const text = this.text;
    const len = text.length;
    let i;
    for (i = 0; i < len; i += 1) {
      if (!text.charAt(i).match(WHITE_RE)) {
        pos = i;
        break;
      }
    }
    return pos;
  }
 
  findLastNonBlank(): number {
    const text = this.text;
    const len = text.length;
    let pos = text.length + 1;
    let i;
    for (i = len - 1; i >= 0; i -= 1) {
      if (!text.charAt(i).match(WHITE_RE)) {
        pos = i;
        break;
      }
    }
    return pos;
  }
 
  originalLength(): number {
    return this.origLength;
  }
 
  insertAt(col: number, str: string, insertBefore?: boolean, consumeBlanks?: boolean): this {
    consumeBlanks = typeof consumeBlanks === "undefined" ? this.consumeBlanks : consumeBlanks;
    col = col > this.originalLength() ? this.originalLength() : col;
    col = col < 0 ? 0 : col;
 
    if (consumeBlanks) {
      if (col <= this.startPos) {
        col = 0;
      }
      if (col > this.endPos) {
        col = this.origLength;
      }
    }
 
    const len = str.length;
    const offset = this.findOffset(col, len, insertBefore);
    const realPos = col + offset;
    const text = this.text;
    this.text = text.substring(0, realPos) + str + text.substring(realPos);
    return this;
  }
 
  findOffset(pos: number, len: number, insertBefore?: boolean): number {
    const offsets = this.offsets;
    let offsetObj: InsertionOffset | undefined;
    let cumulativeOffset = 0;
    let i: number;
 
    for (i = 0; i < offsets.length; i += 1) {
      offsetObj = offsets[i];
      if (offsetObj.pos < pos || (offsetObj.pos === pos && !insertBefore)) {
        cumulativeOffset += offsetObj.len;
      }
      if (offsetObj.pos >= pos) {
        break;
      }
    }
    if (offsetObj && offsetObj.pos === pos) {
      offsetObj.len += len;
    } else {
      offsets.splice(i, 0, { pos, len });
    }
    return cumulativeOffset;
  }
 
  wrap(
    startPos: number,
    startText: string,
    endPos: number,
    endText: string,
    consumeBlanks?: boolean,
  ): this {
    this.insertAt(startPos, startText, true, consumeBlanks);
    this.insertAt(endPos, endText, false, consumeBlanks);
    return this;
  }
 
  wrapLine(startText: string, endText: string): void {
    this.wrap(0, startText, this.originalLength(), endText);
  }
 
  toString(): string {
    return this.text;
  }
}
 
export default InsertionText;