All files / js metaformat.tsx

100% Statements 59/59
94.11% Branches 32/34
100% Functions 9/9
100% Lines 57/57

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    39x 39x       16x 1x   25x 15x 15x   8x   15x       7x 7x       9x 9x 9x 9x     11x 7x 7x 7x       9x 24x 24x   24x 2x 2x 22x 14x 4x 4x 3x     11x   8x 8x 21x 7x 7x 7x 3x   4x 4x           9x 9x       7x   7x 21x 7x 1x   7x 3x 3x 3x 3x 1x   3x 7x     4x       7x    
/** Check whether the (trimmed) line is at least 3 chars wide and only dashes. */
export function lineIsDashes(rawLine: string): boolean {
  const line = rawLine.trim();
  return line.length >= 3 && line.match(/[^-]/) === null;
}
 
export function processBuf(buf: string[]): string[] {
  if (buf.length === 0) {
    return buf;
  }
  const lines = buf.map((line) => (lineIsDashes(line) ? line.substr(1) : line));
  const lastLine = lines[lines.length - 1];
  if (lastLine[lastLine.length - 1] === "\n") {
    // trim newline at the end of the last line.
    lines[lines.length - 1] = lastLine.substr(0, lastLine.length - 1);
  }
  return lines;
}
 
function trimTabsAndSpaces(str: string): string {
  const match = str.match(/^[\t ]*(.*?)[\t ]*$/m);
  return match ? match[1] : "";
}
 
export function tokenize(lines: string[]): [string, string[]][] {
  let key: string | null = null;
  let buf: string[] = [];
  let wantNewline = false;
  const rv: [string, string[]][] = [];
 
  function flushItem() {
    if (key !== null) {
      rv.push([key, processBuf(buf)]);
      key = null;
      buf = [];
    }
  }
 
  for (let i = 0; i < lines.length; i++) {
    const match = lines[i].match(/^(.*?)(\r?\n)*$/m);
    const line = match ? `${match[1]}\n` : "\n";
 
    if (line.trimRight() === "---") {
      wantNewline = false;
      flushItem();
    } else if (key !== null) {
      if (wantNewline) {
        wantNewline = false;
        if (line.match(/^\s*$/)) {
          continue;
        }
      }
      buf.push(line);
    } else {
      const bits = line.split(":");
      if (bits.length >= 2) {
        const [rawKey, ...rest] = bits;
        key = rawKey.trim();
        const firstBit = trimTabsAndSpaces(rest.join(":"));
        if (!firstBit.match(/^\s*$/)) {
          buf = [firstBit];
        } else {
          buf = [];
          wantNewline = true;
        }
      }
    }
  }
 
  flushItem();
  return rv;
}
 
export function serialize(blocks: [string, string][]): string[] {
  const rv: string[] = [];
 
  blocks.forEach((item, idx) => {
    const [key, value] = item;
    if (idx > 0) {
      rv.push("---\n");
    }
    if (value.match(/([\r\n]|(^[\t ])|([\t ]$))/m)) {
      rv.push(key + ":\n");
      rv.push("\n");
      const lines = value.split(/\n/);
      if (lines[lines.length - 1] === "") {
        lines.pop();
      }
      lines.forEach((line) => {
        rv.push(lineIsDashes(line) ? `-${line}\n` : `${line}\n`);
      });
    } else {
      rv.push(key + ": " + value + "\n");
    }
  });
 
  return rv;
}