import Scanner , { MatchFunction , SourceData } from './scanner' ; import type { Identifier , LiteralValue , Literal , Node , Expression , FunctionDeclaration , ArrowFunctionExpression , Position , SourceLocation } from './ast' ; export const SINGLE_QUOTE = 39 ; export const DOUBLE_QUOTE = 34 ; export const ESCAPE = 92 ; export const UNDERSCORE = 95 ; export const NAMESPACE_DELIMITER = 58 ; export const DASH = 45 ; export const TAG_START = 60 ; export const TAG_END = 62 ; export const TAG_CLOSE = 47 ; export const ATTR_DELIMITER = 61 ; export const DOT = 46 ; const emptyPos = { line : 0 , column : 0 , offset : 0 } ; const emptyLoc = { start : emptyPos , end : emptyPos , } ; const emptySourceData = { start : 0 , end : 0 , loc : emptyLoc } ; /**
 * Check if given character can be used as a start of tag name or attribute
 */ export function nameStartChar ( ch ) { return isAlpha ( ch ) || ch === UNDERSCORE || ch === NAMESPACE_DELIMITER ; } /**
 * Check if given character can be used as a tag name
 */ export function nameChar ( ch ) { return nameStartChar ( ch ) || isNumber ( ch ) || ch === DASH || ch === DOT ; } /**
 * Factory function for creating `Identifier` AST node
 */ export function identifier ( name , loc ? ) { return { type : 'Identifier' , name , ... toSourceData ( loc ) } ; } /**
 * Factory function for creating `Literal` AST node
 */ export function literal ( value , raw ? , loc ? ) { return { type : 'Literal' , value , raw , ... toSourceData ( loc ) } ; } /**
 * Check if given node is `Identifier`
 */ export function isIdentifier ( node ? ) { return node && node . type === 'Identifier' ; } /**
 * Check if given node is `Literal`
 */ export function isLiteral ( node ? ) { return node && node . type === 'Literal' ; } /**
 * Check if given node is a function
 */ export function isFunction ( node ) { return node . type === 'FunctionDeclaration' || node . type === 'ArrowFunctionExpression' ; } export function toSourceData ( node ? ) { return node ? { start : node . start || 0 , end : node . end || 0 , loc : node . loc || emptyLoc } : emptySourceData ; } /**
 * Tries to consume content from given stream that matches `fn` test. If consumed,
 * moves `.start` property of stream to the beginning of consumed token
 */ export function consume ( scanner , fn ) { const pos = scanner . pos ; if ( scanner . eatWhile ( fn ) ) { scanner . start = pos ; return true ; } scanner . pos = pos ; return false ; } param scanner param codes export function eatArray ( scanner , codes ) { const start = scanner . pos ; for ( let i = 0 ; i < codes . length ; i ++ ) { if ( ! scanner . eat ( codes [ i ] ) ) { scanner . pos = start ; return false ; } } scanner . start = start ; return true ; } param allowUnclosed export function eatSection ( scanner , open , close , allowUnclosed = false ) { const start = scanner . pos ; if ( eatArray ( scanner , open ) ) { scanner . start = start ; while ( ! scanner . eof ( ) ) { if ( eatArray ( scanner , close ) ) { return true ; } scanner . next ( ) ; } if ( allowUnclosed ) { return true ; } else { throw scanner . error ( `Expected ${ close . map ( ch => String . fromCharCode ( ch ) ) . join ( '' ) }` ) ; } } return false ; } /**
 * Converts given string into array of character codes
 */ export function toCharCodes ( str ) { return str . split ( '' ) . map ( ch => ch . charCodeAt ( 0 ) ) ; } /**
 * Consumes 'single' or "double"-quoted string from given string, if possible
 */ export function eatQuoted ( scanner ) { const start = scanner . pos ; const quote = scanner . peek ( ) ; if ( scanner . eat ( isQuote ) ) { while ( ! scanner . eof ( ) ) { switch ( scanner . next ( ) ) { case quote : scanner . start = start ; return true ; case ESCAPE : scanner . next ( ) ; break ; } } throw scanner . error ( 'Missing closing quote for string' , start ) ; } return false ; } param scanner param open param close export function eatPair ( scanner , open , close ) { const start = scanner . pos ; if ( scanner . eat ( open ) ) { let stack = 1 ; let ch ; while ( ! scanner . eof ( ) ) { if ( eatQuoted ( scanner ) ) { continue ; } ch = scanner . next ( ) ; if ( ch === open ) { stack ++ ; } else if ( ch === close ) { stack -- ; if ( ! stack ) { scanner . start = start ; return true ; } } else if ( ch === ESCAPE ) { scanner . next ( ) ; } } throw scanner . error ( `Unable to find matching pair for ${ String . fromCharCode ( open ) }` ) ; } return false ; } /**
 * Check if given character code is a quote
 */ export function isQuote ( code ) { return code === SINGLE_QUOTE || code === DOUBLE_QUOTE ; } /**
 * Check if given code is a number
 */ export function isNumber ( code ) { return code > 47 && code < 58 ; } /**
 * Check if given character code is alpha code (letter through A to Z)
 */ export function isAlpha ( code , from = 65 , to = 90 ) { code &= ~ 32 ; return code >= from && code <= to ; } /**
 * Check if given character code is alpha-numeric (letter through A to Z or number)
 */ export function isAlphaNumeric ( code ) { return isNumber ( code ) || isAlpha ( code ) ; } /**
 * Check if given character code is a whitespace character
 */ export function isWhiteSpace ( code ) { return code === 32 || code === 9 || code === 160 ; } /**
 * Check if given character code is a space character
 */ export function isSpace ( code ) { return isWhiteSpace ( code ) || code === 10 || code === 13 ; }