( source: string, start: number | Pos = 0, end?: number | Pos, )
| 487 | const ELLIPSIS = '...' |
| 488 | |
| 489 | export function generateCodeFrame( |
| 490 | source: string, |
| 491 | start: number | Pos = 0, |
| 492 | end?: number | Pos, |
| 493 | ): string { |
| 494 | start = Math.max(posToNumber(source, start), 0) |
| 495 | end = Math.min( |
| 496 | end !== undefined ? posToNumber(source, end) : start, |
| 497 | source.length, |
| 498 | ) |
| 499 | const lastPosLine = |
| 500 | end !== undefined |
| 501 | ? numberToPos(source, end).line |
| 502 | : numberToPos(source, start).line + range |
| 503 | const lineNumberWidth = Math.max(3, String(lastPosLine).length + 1) |
| 504 | const lines = source.split(splitRE) |
| 505 | let count = 0 |
| 506 | const res: string[] = [] |
| 507 | for (let i = 0; i < lines.length; i++) { |
| 508 | count += lines[i].length |
| 509 | if (count >= start) { |
| 510 | for (let j = i - range; j <= i + range || end > count; j++) { |
| 511 | if (j < 0 || j >= lines.length) continue |
| 512 | const line = j + 1 |
| 513 | const lineLength = lines[j].length |
| 514 | const pad = Math.max(start - (count - lineLength), 0) |
| 515 | const underlineLength = Math.max( |
| 516 | 1, |
| 517 | end > count ? lineLength - pad : end - start, |
| 518 | ) |
| 519 | |
| 520 | let displayLine = lines[j] |
| 521 | let underlinePad = pad |
| 522 | if (lineLength > MAX_DISPLAY_LEN) { |
| 523 | let startIdx = 0 |
| 524 | if (j === i) { |
| 525 | if (underlineLength > MAX_DISPLAY_LEN) { |
| 526 | startIdx = pad |
| 527 | } else { |
| 528 | const center = pad + Math.floor(underlineLength / 2) |
| 529 | startIdx = Math.max(0, center - Math.floor(MAX_DISPLAY_LEN / 2)) |
| 530 | } |
| 531 | underlinePad = |
| 532 | Math.max(0, pad - startIdx) + (startIdx > 0 ? ELLIPSIS.length : 0) |
| 533 | } |
| 534 | const prefix = startIdx > 0 ? ELLIPSIS : '' |
| 535 | const suffix = lineLength - startIdx > MAX_DISPLAY_LEN ? ELLIPSIS : '' |
| 536 | const sliceLen = MAX_DISPLAY_LEN - prefix.length - suffix.length |
| 537 | displayLine = |
| 538 | prefix + displayLine.slice(startIdx, startIdx + sliceLen) + suffix |
| 539 | } |
| 540 | res.push( |
| 541 | `${line}${' '.repeat(lineNumberWidth - String(line).length)}| ${displayLine}`, |
| 542 | ) |
| 543 | if (j === i) { |
| 544 | // push underline |
| 545 | const underline = '^'.repeat( |
| 546 | Math.min(underlineLength, MAX_DISPLAY_LEN), |
no test coverage detected