blob: 3161f21fbc9930d7772e6677839e2aeaa505cc50 [file] [log] [blame]
Tim van der Lippef2ea2c92021-11-08 10:55:56 +00001'use strict'
Mathias Bynens79e2cf02020-05-29 16:46:17 +02002
Tim van der Lippef2ea2c92021-11-08 10:55:56 +00003let pico = require('picocolors')
Mathias Bynens79e2cf02020-05-29 16:46:17 +02004
Tim van der Lippef2ea2c92021-11-08 10:55:56 +00005let terminalHighlight = require('./terminal-highlight')
Mathias Bynens79e2cf02020-05-29 16:46:17 +02006
Tim van der Lippef2ea2c92021-11-08 10:55:56 +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 Lippef2ea2c92021-11-08 10:55:56 +000014 this.file = file
Mathias Bynens79e2cf02020-05-29 16:46:17 +020015 }
Alex Rudenko6c0f1612021-11-05 06:28:44 +000016 if (source) {
Tim van der Lippef2ea2c92021-11-08 10:55:56 +000017 this.source = source
Alex Rudenko6c0f1612021-11-05 06:28:44 +000018 }
Alex Rudenko6c0f1612021-11-05 06:28:44 +000019 if (plugin) {
Tim van der Lippef2ea2c92021-11-08 10:55:56 +000020 this.plugin = plugin
Alex Rudenko6c0f1612021-11-05 06:28:44 +000021 }
Alex Rudenko6c0f1612021-11-05 06:28:44 +000022 if (typeof line !== 'undefined' && typeof column !== 'undefined') {
Tim van der Lippef2ea2c92021-11-08 10:55:56 +000023 this.line = line
24 this.column = column
Alex Rudenko6c0f1612021-11-05 06:28:44 +000025 }
26
Tim van der Lippef2ea2c92021-11-08 10:55:56 +000027 this.setMessage()
Mathias Bynens79e2cf02020-05-29 16:46:17 +020028
29 if (Error.captureStackTrace) {
Tim van der Lippef2ea2c92021-11-08 10:55:56 +000030 Error.captureStackTrace(this, CssSyntaxError)
Mathias Bynens79e2cf02020-05-29 16:46:17 +020031 }
Mathias Bynens79e2cf02020-05-29 16:46:17 +020032 }
33
Tim van der Lippef2ea2c92021-11-08 10:55:56 +000034 setMessage() {
35 this.message = this.plugin ? this.plugin + ': ' : ''
36 this.message += this.file ? this.file : '<css input>'
Mathias Bynens79e2cf02020-05-29 16:46:17 +020037 if (typeof this.line !== 'undefined') {
Tim van der Lippef2ea2c92021-11-08 10:55:56 +000038 this.message += ':' + this.line + ':' + this.column
Mathias Bynens79e2cf02020-05-29 16:46:17 +020039 }
Tim van der Lippef2ea2c92021-11-08 10:55:56 +000040 this.message += ': ' + this.reason
Mathias Bynens79e2cf02020-05-29 16:46:17 +020041 }
Mathias Bynens79e2cf02020-05-29 16:46:17 +020042
Tim van der Lippef2ea2c92021-11-08 10:55:56 +000043 showSourceCode(color) {
44 if (!this.source) return ''
Mathias Bynens79e2cf02020-05-29 16:46:17 +020045
Tim van der Lippef2ea2c92021-11-08 10:55:56 +000046 let css = this.source
47 if (color == null) color = pico.isColorSupported
48 if (terminalHighlight) {
49 if (color) css = terminalHighlight(css)
Mathias Bynens79e2cf02020-05-29 16:46:17 +020050 }
51
Tim van der Lippef2ea2c92021-11-08 10:55:56 +000052 let lines = css.split(/\r?\n/)
53 let start = Math.max(this.line - 3, 0)
54 let end = Math.min(this.line + 2, lines.length)
Mathias Bynens79e2cf02020-05-29 16:46:17 +020055
Tim van der Lippef2ea2c92021-11-08 10:55:56 +000056 let maxWidth = String(end).length
Mathias Bynens79e2cf02020-05-29 16:46:17 +020057
Tim van der Lippef2ea2c92021-11-08 10:55:56 +000058 let mark, aside
59 if (color) {
60 let { bold, red, gray } = pico.createColors(true)
61 mark = text => bold(red(text))
62 aside = text => gray(text)
63 } else {
64 mark = aside = str => str
Mathias Bynens79e2cf02020-05-29 16:46:17 +020065 }
66
Tim van der Lippef2ea2c92021-11-08 10:55:56 +000067 return lines
68 .slice(start, end)
69 .map((line, index) => {
70 let number = start + 1 + index
71 let gutter = ' ' + (' ' + number).slice(-maxWidth) + ' | '
72 if (number === this.line) {
73 let spacing =
74 aside(gutter.replace(/\d/g, ' ')) +
75 line.slice(0, this.column - 1).replace(/[^\t]/g, ' ')
76 return mark('>') + aside(gutter) + line + '\n ' + spacing + mark('^')
77 }
78 return ' ' + aside(gutter) + line
79 })
80 .join('\n')
Mathias Bynens79e2cf02020-05-29 16:46:17 +020081 }
Mathias Bynens79e2cf02020-05-29 16:46:17 +020082
Tim van der Lippef2ea2c92021-11-08 10:55:56 +000083 toString() {
84 let code = this.showSourceCode()
Mathias Bynens79e2cf02020-05-29 16:46:17 +020085 if (code) {
Tim van der Lippef2ea2c92021-11-08 10:55:56 +000086 code = '\n\n' + code + '\n'
Mathias Bynens79e2cf02020-05-29 16:46:17 +020087 }
Tim van der Lippef2ea2c92021-11-08 10:55:56 +000088 return this.name + ': ' + this.message + code
Alex Rudenko6c0f1612021-11-05 06:28:44 +000089 }
Tim van der Lippef2ea2c92021-11-08 10:55:56 +000090}
Alex Rudenko6c0f1612021-11-05 06:28:44 +000091
Tim van der Lippef2ea2c92021-11-08 10:55:56 +000092module.exports = CssSyntaxError
93CssSyntaxError.default = CssSyntaxError