99 type Declaration ,
1010 type Rule ,
1111} from './ast'
12+ import { createLineTable } from './source-maps/line-table'
1213import type { Source } from './source-maps/source'
1314
1415const BACKSLASH = 0x5c
@@ -36,29 +37,16 @@ export interface ParseOptions {
3637 from ?: string
3738}
3839
39- function getLineAndColumn ( input : string , position : number ) : { line : number ; column : number } {
40- let line = 1
41- let column = 1
42-
43- for ( let i = 0 ; i < position && i < input . length ; i ++ ) {
44- if ( input . charCodeAt ( i ) === LINE_BREAK ) {
45- line ++
46- column = 1
40+ export class CssSyntaxError extends Error {
41+ constructor ( message : string , source : Source | null , position : number ) {
42+ if ( ! source ) {
43+ super ( message )
4744 } else {
48- column ++
45+ const { line, column } = createLineTable ( source . code ) . find ( position )
46+ super ( `${ message } at ${ source . file } :${ line } :${ column } ` )
4947 }
48+ this . name = 'CssSyntaxError'
5049 }
51-
52- return { line, column }
53- }
54-
55- function formatError ( message : string , source : Source | null , position : number ) : string {
56- if ( ! source ) {
57- return message
58- }
59-
60- const { line, column } = getLineAndColumn ( source . code , position )
61- return `${ message } at ${ source . file } :${ line } :${ column } `
6250}
6351
6452export function parse ( input : string , opts ?: ParseOptions ) {
@@ -294,7 +282,7 @@ export function parse(input: string, opts?: ParseOptions) {
294282 }
295283
296284 let declaration = parseDeclaration ( buffer , colonIdx )
297- if ( ! declaration ) throw new Error ( formatError ( `Invalid custom property, expected a value` , source , start ) )
285+ if ( ! declaration ) throw new CssSyntaxError ( `Invalid custom property, expected a value` , source , start )
298286
299287 if ( source ) {
300288 declaration . src = [ source , start , i ]
@@ -359,7 +347,7 @@ export function parse(input: string, opts?: ParseOptions) {
359347 let declaration = parseDeclaration ( buffer )
360348 if ( ! declaration ) {
361349 if ( buffer . length === 0 ) continue
362- throw new Error ( formatError ( `Invalid declaration: \`${ buffer . trim ( ) } \`` , source , bufferStart ) )
350+ throw new CssSyntaxError ( `Invalid declaration: \`${ buffer . trim ( ) } \`` , source , bufferStart )
363351 }
364352
365353 if ( source ) {
@@ -416,7 +404,7 @@ export function parse(input: string, opts?: ParseOptions) {
416404 closingBracketStack [ closingBracketStack . length - 1 ] !== ')'
417405 ) {
418406 if ( closingBracketStack === '' ) {
419- throw new Error ( formatError ( 'Missing opening {' , source , i ) )
407+ throw new CssSyntaxError ( 'Missing opening {' , source , i )
420408 }
421409
422410 closingBracketStack = closingBracketStack . slice ( 0 , - 1 )
@@ -478,7 +466,7 @@ export function parse(input: string, opts?: ParseOptions) {
478466 // Attach the declaration to the parent.
479467 if ( parent ) {
480468 let node = parseDeclaration ( buffer , colonIdx )
481- if ( ! node ) throw new Error ( formatError ( `Invalid declaration: \`${ buffer . trim ( ) } \`` , source , bufferStart ) )
469+ if ( ! node ) throw new CssSyntaxError ( `Invalid declaration: \`${ buffer . trim ( ) } \`` , source , bufferStart )
482470
483471 if ( source ) {
484472 node . src = [ source , bufferStart , i ]
@@ -517,7 +505,7 @@ export function parse(input: string, opts?: ParseOptions) {
517505 // `)`
518506 else if ( currentChar === CLOSE_PAREN ) {
519507 if ( closingBracketStack [ closingBracketStack . length - 1 ] !== ')' ) {
520- throw new Error ( formatError ( 'Missing opening (' , source , i ) )
508+ throw new CssSyntaxError ( 'Missing opening (' , source , i )
521509 }
522510
523511 closingBracketStack = closingBracketStack . slice ( 0 , - 1 )
@@ -559,10 +547,10 @@ export function parse(input: string, opts?: ParseOptions) {
559547 // have a leftover `parent`, then it means that we have an unterminated block.
560548 if ( closingBracketStack . length > 0 && parent ) {
561549 if ( parent . kind === 'rule' ) {
562- throw new Error ( formatError ( `Missing closing } at ${ parent . selector } ` , source , input . length ) )
550+ throw new CssSyntaxError ( `Missing closing } at ${ parent . selector } ` , source , input . length )
563551 }
564552 if ( parent . kind === 'at-rule' ) {
565- throw new Error ( formatError ( `Missing closing } at ${ parent . name } ${ parent . params } ` , source , input . length ) )
553+ throw new CssSyntaxError ( `Missing closing } at ${ parent . name } ${ parent . params } ` , source , input . length )
566554 }
567555 }
568556
@@ -661,8 +649,8 @@ function parseString(input: string, startIdx: number, quoteChar: number, source:
661649 ( input . charCodeAt ( i + 1 ) === LINE_BREAK ||
662650 ( input . charCodeAt ( i + 1 ) === CARRIAGE_RETURN && input . charCodeAt ( i + 2 ) === LINE_BREAK ) )
663651 ) {
664- throw new Error (
665- formatError ( `Unterminated string: ${ input . slice ( startIdx , i + 1 ) + String . fromCharCode ( quoteChar ) } ` , source , startIdx )
652+ throw new CssSyntaxError (
653+ `Unterminated string: ${ input . slice ( startIdx , i + 1 ) + String . fromCharCode ( quoteChar ) } ` , source , startIdx
666654 )
667655 }
668656
@@ -680,8 +668,8 @@ function parseString(input: string, startIdx: number, quoteChar: number, source:
680668 peekChar === LINE_BREAK ||
681669 ( peekChar === CARRIAGE_RETURN && input . charCodeAt ( i + 1 ) === LINE_BREAK )
682670 ) {
683- throw new Error (
684- formatError ( `Unterminated string: ${ input . slice ( startIdx , i ) + String . fromCharCode ( quoteChar ) } ` , source , startIdx )
671+ throw new CssSyntaxError (
672+ `Unterminated string: ${ input . slice ( startIdx , i ) + String . fromCharCode ( quoteChar ) } ` , source , startIdx
685673 )
686674 }
687675 }
0 commit comments