()
| 23 | } |
| 24 | |
| 25 | toString() { |
| 26 | const lines = this.source.split(/\r?\n/); |
| 27 | const startLine = Math.max(this.line - 3, 0); |
| 28 | const endLine = Math.min(this.line + 2, lines.length); |
| 29 | const lineNumberWidth = String(endLine).length; |
| 30 | const startColumn = Math.max(this.column - 54, 0); |
| 31 | const endColumn = Math.max(this.column + 20, 80); |
| 32 | const code = lines |
| 33 | .slice(startLine, endLine) |
| 34 | .map((line, index) => { |
| 35 | const lineSlice = line.slice(startColumn, endColumn); |
| 36 | let ellipsisPrefix = ''; |
| 37 | let ellipsisSuffix = ''; |
| 38 | if (startColumn !== 0) { |
| 39 | ellipsisPrefix = startColumn > line.length - 1 ? ' ' : '…'; |
| 40 | } |
| 41 | if (endColumn < line.length - 1) { |
| 42 | ellipsisSuffix = '…'; |
| 43 | } |
| 44 | const number = startLine + 1 + index; |
| 45 | const gutter = ` ${number.toString().padStart(lineNumberWidth)} | `; |
| 46 | if (number === this.line) { |
| 47 | const gutterSpacing = gutter.replace(/[^|]/g, ' '); |
| 48 | const lineSpacing = ( |
| 49 | ellipsisPrefix + line.slice(startColumn, this.column - 1) |
| 50 | ).replace(/[^\t]/g, ' '); |
| 51 | const spacing = gutterSpacing + lineSpacing; |
| 52 | return `>${gutter}${ellipsisPrefix}${lineSlice}${ellipsisSuffix}\n ${spacing}^`; |
| 53 | } |
| 54 | return ` ${gutter}${ellipsisPrefix}${lineSlice}${ellipsisSuffix}`; |
| 55 | }) |
| 56 | .join('\n'); |
| 57 | return `${this.name}: ${this.message}\n\n${code}\n`; |
| 58 | } |
| 59 | } |
| 60 | |
| 61 | const entityDeclaration = /<!ENTITY\s+(\S+)\s+(?:'([^']+)'|"([^"]+)")\s*>/g; |
no outgoing calls