All files / shared/src codeframe.ts

100% Statements 50/50
100% Branches 23/23
100% Functions 1/1
100% Lines 50/50

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 653x   3x 87x 87x 87x 87x   87x 87x   87x           86x     86x 86x   86x 86x 87x 208x 208x 208x 208x 86x 438x 261x 261x 261x 261x 261x 261x 261x 261x 438x   438x   86x 86x 86x 86x 86x 86x 438x 91x 18x 18x 18x   91x 91x 438x 86x 86x 208x 86x 86x  
const range: number = 2
 
export function generateCodeFrame(
  source: string,
  start = 0,
  end: number = source.length,
): string {
  // Ensure start and end are within the source length
  start = Math.max(0, Math.min(start, source.length))
  end = Math.max(0, Math.min(end, source.length))
 
  if (start > end) return ''
 
  // Split the content into individual lines but capture the newline sequence
  // that separated each line. This is important because the actual sequence is
  // needed to properly take into account the full line length for offset
  // comparison
  let lines = source.split(/(\r?\n)/)
 
  // Separate the lines and newline sequences into separate arrays for easier referencing
  const newlineSequences = lines.filter((_, idx) => idx % 2 === 1)
  lines = lines.filter((_, idx) => idx % 2 === 0)
 
  let count = 0
  const res: string[] = []
  for (let i = 0; i < lines.length; i++) {
    count +=
      lines[i].length +
      ((newlineSequences[i] && newlineSequences[i].length) || 0)
    if (count >= start) {
      for (let j = i - range; j <= i + range || end > count; j++) {
        if (j < 0 || j >= lines.length) continue
        const line = j + 1
        res.push(
          `${line}${' '.repeat(Math.max(3 - String(line).length, 0))}|  ${
            lines[j]
          }`,
        )
        const lineLength = lines[j].length
        const newLineSeqLength =
          (newlineSequences[j] && newlineSequences[j].length) || 0
 
        if (j === i) {
          // push underline
          const pad = start - (count - (lineLength + newLineSeqLength))
          const length = Math.max(
            1,
            end > count ? lineLength - pad : end - start,
          )
          res.push(`   |  ` + ' '.repeat(pad) + '^'.repeat(length))
        } else if (j > i) {
          if (end > count) {
            const length = Math.max(Math.min(end - count, lineLength), 1)
            res.push(`   |  ` + '^'.repeat(length))
          }
 
          count += lineLength + newLineSeqLength
        }
      }
      break
    }
  }
  return res.join('\n')
}