blob: d6b369b8f003c8be93011edfe28803171c135d47 [file] [log] [blame]
Tim van der Lippe16b82282021-11-08 13:50:26 +00001'use strict'
Mathias Bynens79e2cf02020-05-29 16:46:17 +02002
Tim van der Lippe16b82282021-11-08 13:50:26 +00003let pico = require('picocolors')
Mathias Bynens79e2cf02020-05-29 16:46:17 +02004
Tim van der Lippe16b82282021-11-08 13:50:26 +00005let terminalHighlight = require('./terminal-highlight')
Mathias Bynens79e2cf02020-05-29 16:46:17 +02006
Tim van der Lippe16b82282021-11-08 13:50:26 +00007class CssSyntaxError extends Error {
8 constructor(message, line, column, source, file, plugin) {
9 super(message)
10 this.name = 'CssSyntaxError'
11 this.reason = message
Mathias Bynens79e2cf02020-05-29 16:46:17 +020012
13 if (file) {
Tim van der Lippe16b82282021-11-08 13:50:26 +000014 this.file = file
Alex Rudenko6c0f1612021-11-05 06:28:44 +000015 }
Tim van der Lippe2b4a9df2021-11-08 12:58:12 +000016 if (source) {
Tim van der Lippe16b82282021-11-08 13:50:26 +000017 this.source = source
Tim van der Lippe2b4a9df2021-11-08 12:58:12 +000018 }
Tim van der Lippe2b4a9df2021-11-08 12:58:12 +000019 if (plugin) {
Tim van der Lippe16b82282021-11-08 13:50:26 +000020 this.plugin = plugin
Tim van der Lippe2b4a9df2021-11-08 12:58:12 +000021 }
Tim van der Lippe2b4a9df2021-11-08 12:58:12 +000022 if (typeof line !== 'undefined' && typeof column !== 'undefined') {
Tim van der Lippe4cb09742022-01-07 14:25:03 +010023 if (typeof line === 'number') {
24 this.line = line
25 this.column = column
26 } else {
27 this.line = line.line
28 this.column = line.column
29 this.endLine = column.line
30 this.endColumn = column.column
31 }
Tim van der Lippe2b4a9df2021-11-08 12:58:12 +000032 }
33
Tim van der Lippe16b82282021-11-08 13:50:26 +000034 this.setMessage()
Mathias Bynens79e2cf02020-05-29 16:46:17 +020035
36 if (Error.captureStackTrace) {
Tim van der Lippe16b82282021-11-08 13:50:26 +000037 Error.captureStackTrace(this, CssSyntaxError)
Mathias Bynens79e2cf02020-05-29 16:46:17 +020038 }
Mathias Bynens79e2cf02020-05-29 16:46:17 +020039 }
40
Tim van der Lippe16b82282021-11-08 13:50:26 +000041 setMessage() {
42 this.message = this.plugin ? this.plugin + ': ' : ''
43 this.message += this.file ? this.file : '<css input>'
Mathias Bynens79e2cf02020-05-29 16:46:17 +020044 if (typeof this.line !== 'undefined') {
Tim van der Lippe16b82282021-11-08 13:50:26 +000045 this.message += ':' + this.line + ':' + this.column
Mathias Bynens79e2cf02020-05-29 16:46:17 +020046 }
Tim van der Lippe16b82282021-11-08 13:50:26 +000047 this.message += ': ' + this.reason
Mathias Bynens79e2cf02020-05-29 16:46:17 +020048 }
Mathias Bynens79e2cf02020-05-29 16:46:17 +020049
Tim van der Lippe16b82282021-11-08 13:50:26 +000050 showSourceCode(color) {
51 if (!this.source) return ''
Mathias Bynens79e2cf02020-05-29 16:46:17 +020052
Tim van der Lippe16b82282021-11-08 13:50:26 +000053 let css = this.source
54 if (color == null) color = pico.isColorSupported
55 if (terminalHighlight) {
56 if (color) css = terminalHighlight(css)
Mathias Bynens79e2cf02020-05-29 16:46:17 +020057 }
58
Tim van der Lippe16b82282021-11-08 13:50:26 +000059 let lines = css.split(/\r?\n/)
60 let start = Math.max(this.line - 3, 0)
61 let end = Math.min(this.line + 2, lines.length)
Mathias Bynens79e2cf02020-05-29 16:46:17 +020062
Tim van der Lippe16b82282021-11-08 13:50:26 +000063 let maxWidth = String(end).length
Mathias Bynens79e2cf02020-05-29 16:46:17 +020064
Tim van der Lippe16b82282021-11-08 13:50:26 +000065 let mark, aside
66 if (color) {
67 let { bold, red, gray } = pico.createColors(true)
68 mark = text => bold(red(text))
69 aside = text => gray(text)
70 } else {
71 mark = aside = str => str
Mathias Bynens79e2cf02020-05-29 16:46:17 +020072 }
73
Tim van der Lippe16b82282021-11-08 13:50:26 +000074 return lines
75 .slice(start, end)
76 .map((line, index) => {
77 let number = start + 1 + index
78 let gutter = ' ' + (' ' + number).slice(-maxWidth) + ' | '
79 if (number === this.line) {
80 let spacing =
81 aside(gutter.replace(/\d/g, ' ')) +
82 line.slice(0, this.column - 1).replace(/[^\t]/g, ' ')
83 return mark('>') + aside(gutter) + line + '\n ' + spacing + mark('^')
84 }
85 return ' ' + aside(gutter) + line
86 })
87 .join('\n')
Mathias Bynens79e2cf02020-05-29 16:46:17 +020088 }
Mathias Bynens79e2cf02020-05-29 16:46:17 +020089
Tim van der Lippe16b82282021-11-08 13:50:26 +000090 toString() {
91 let code = this.showSourceCode()
Mathias Bynens79e2cf02020-05-29 16:46:17 +020092 if (code) {
Tim van der Lippe16b82282021-11-08 13:50:26 +000093 code = '\n\n' + code + '\n'
Mathias Bynens79e2cf02020-05-29 16:46:17 +020094 }
Tim van der Lippe16b82282021-11-08 13:50:26 +000095 return this.name + ': ' + this.message + code
Tim van der Lippe2b4a9df2021-11-08 12:58:12 +000096 }
Tim van der Lippe16b82282021-11-08 13:50:26 +000097}
Tim van der Lippe2b4a9df2021-11-08 12:58:12 +000098
Tim van der Lippe16b82282021-11-08 13:50:26 +000099module.exports = CssSyntaxError
100CssSyntaxError.default = CssSyntaxError