import * as SourceLocation from "./SourceLocation" ; export type Position = SourceLocation . SourcePosition ; export type ErrorWithoutPosition = Partial < SourceLocation . SourceFile > ; export type ErrorWithPosition = Required < SourceLocation . SourceRange > ; export type ErrorWithMappedPosition = SourceLocation . MappedSourceRange ; export type ErrorLocation = ErrorWithoutPosition | ErrorWithPosition | ErrorWithMappedPosition ; export function hasMappedPosition ( loc ) { return ( typeof ( < ErrorWithMappedPosition > loc ) . generated === "object" ) ; } export function errorHasRange ( location ) { return location && typeof ( < ErrorWithPosition > location ) . start === "object" || false ; } interface HasPrefix { prefix ? : string ; } /**
 * Custom CSS Blocks error base class. Will format `SourceLocation` into thrown
 * error message if provided.
 */ export class CssBlockError extends Error { static prefix = "Error" ; origMessage : string ; location ? : ErrorLocation ; constructor ( message , location ? ) { super ( message ) ; this . origMessage = message ; this . location = location ; super . message = this . annotatedMessage ( ) ; } private annotatedMessage ( ) { let loc = this . location ; if ( loc ) { let prefix = ( < HasPrefix > this . constructor ) . prefix ; return `[css-blocks] ${ prefix || CssBlockError . prefix }: ${ this . origMessage } (${ charInFile ( loc ) })` ; } else { return this . origMessage ; } } } function hasSourcePosition ( filenameOrPosition ) { return typeof ( < SourceLocation . SourceLocation > filenameOrPosition ) . line === "number" ; } export function charInFile ( filename , position ) ; export function charInFile ( position ) ; export function charInFile ( filename , line , column ) ; export function charInFile ( filenameOrPosition , lineOrPosition ? , column ? ) { let filename ; let line ; if ( typeof filenameOrPosition === "object" ) { filename = filenameOrPosition . filename || "<unknown file>" ; if ( errorHasRange ( filenameOrPosition ) ) { line = filenameOrPosition . start . line ; column = filenameOrPosition . start . column ; } else if ( hasSourcePosition ( filenameOrPosition ) ) { line = filenameOrPosition . line ; column = filenameOrPosition . column ; } } else { filename = filenameOrPosition ; } if ( typeof lineOrPosition === "object" ) { line = lineOrPosition . line ; column = lineOrPosition . column ; } else if ( typeof lineOrPosition === "number" ) { line = lineOrPosition ; } if ( typeof line === "number" && typeof column === "number" ) { return `${ filename }:${ line }:${ column }` ; } else { return filename ; } } /**
 * Custom CSS Blocks error type for template analysis errors.
 */ export class TemplateAnalysisError extends CssBlockError { static prefix = "TemplateError" ; constructor ( message , location ? , details ? ) { super ( message , location ) ; if ( details ) { this . message += `\n${ details }` ; } } } /**
 * Custom CSS Blocks error for missing source path from PostCSS
 */ export class MissingSourcePath extends CssBlockError { static prefix = "SourcePathError" ; constructor ( ) { super ( "PostCSS `from` option is missing. The source filename is required for CSS Blocks to work correctly." ) ; } } /**
 * Custom CSS Blocks error for Block syntax error
 */ export class InvalidBlockSyntax extends CssBlockError { static prefix = "BlockSyntaxError" ; constructor ( message , location ? ) { super ( message , location ) ; } } /**
 * Custom CSS Blocks error type for malformed BlockPath errors.
 */ export class BlockPathError extends CssBlockError { static prefix = "MalformedBlockPath" ; constructor ( message , location ? , details ? ) { super ( message , location ) ; if ( details ) { this . message += `\n${ details }` ; } } } /**
 * Acts as a collection of CssBlockErrors along with utility methods to add and
 * clear errors
 */ export class MultipleCssBlockErrors extends CssBlockError { static prefix = "Caused by multiple errors" ; private _errors : CssBlockError [ ] = [ ] ; constructor ( errors , location ? , details ? ) { super ( MultipleCssBlockErrors . prefix , location ) ; for ( let err of errors ) { if ( err instanceof MultipleCssBlockErrors ) { for ( let e of err . errors ) { this . _errors . push ( e ) ; } } else { this . _errors . push ( err ) ; } } if ( ! details ) { details = ":" ; details += errorDetails ( this ) ; } this . message += details ; } add ( error ) { this . _errors . push ( error ) ; } get errors ( ) : CssBlockError [ ] { return this . _errors ; } clear ( ) { this . _errors = [ ] ; } } export class CascadingError extends CssBlockError { static prefix = "CascadingError" ; cause : CssBlockError ; constructor ( message , rootCause , location ? ) { super ( message , location ) ; this . cause = rootCause ; } } function errorDetails ( error , indent = "" ) { let details = "" ; let i = 0 ; for ( let err of error . errors ) { details += `\n${ indent }${ ++ i }. ${ err }` ; if ( err instanceof CascadingError ) { if ( err . cause instanceof MultipleCssBlockErrors && err . cause . errors . length > 1 ) { details += `\n${ indent }   ${ i > 9 ? " " : "" }Caused by multiple errors:` ; details += errorDetails ( err . cause , indent + "\t" ) ; } else { let cause = err . cause instanceof MultipleCssBlockErrors ? err . cause . errors [ 0 ] : err . cause ; details += `\n${ indent }    ${ i > 9 ? " " : "" }Caused by:` ; details += `\n${ indent } ${ cause }` ; } } } return details ; }