import { isQuote , consumeQuoted } from './quotes' ; import { BackwardScanner , consume , sol , consumeWhile , peek } from './reader' ; import { Brackets , bracePairs } from './brackets' ; const enum Chars { Tab = 9 , Space = 32 , /** `-` character */ Dash = 45 , /** `/` character */ Slash = 47 , /** `:` character */ Colon = 58 , /** `=` character */ Equals = 61 , /** `<` character */ AngleLeft = 60 , /** `>` character */ AngleRight = 62 } /**
 * Check if given reader’s current position points at the end of HTML tag
 */ export default function isHtml ( scanner ) { const start = scanner . pos ; if ( ! consume ( scanner , Chars . AngleRight ) ) { return false ; } let ok = false ; consume ( scanner , Chars . Slash ) ; while ( ! sol ( scanner ) ) { consumeWhile ( scanner , isWhiteSpace ) ; if ( consumeIdent ( scanner ) ) { if ( consume ( scanner , Chars . Slash ) ) { ok = consume ( scanner , Chars . AngleLeft ) ; break ; } else if ( consume ( scanner , Chars . AngleLeft ) ) { ok = true ; break ; } else if ( consume ( scanner , isWhiteSpace ) ) { continue ; } else if ( consume ( scanner , Chars . Equals ) ) { if ( consumeIdent ( scanner ) ) { continue ; } break ; } else if ( consumeAttributeWithUnquotedValue ( scanner ) ) { ok = true ; break ; } break ; } if ( consumeAttribute ( scanner ) ) { continue ; } break ; } scanner . pos = start ; return ok ; } return function consumeAttribute ( scanner ) { return consumeAttributeWithQuotedValue ( scanner ) || consumeAttributeWithUnquotedValue ( scanner ) ; } function consumeAttributeWithQuotedValue ( scanner ) { const start = scanner . pos ; if ( consumeQuoted ( scanner ) && consume ( scanner , Chars . Equals ) && consumeIdent ( scanner ) ) { return true ; } scanner . pos = start ; return false ; } function consumeAttributeWithUnquotedValue ( scanner ) { const start = scanner . pos ; const stack = [ ] ; while ( ! sol ( scanner ) ) { const ch = peek ( scanner ) ; if ( isCloseBracket ( ch ) ) { stack . push ( ch ) ; } else if ( isOpenBracket ( ch ) ) { if ( stack . pop ( ) !== bracePairs [ ch ] ) { break ; } } else if ( ! isUnquotedValue ( ch ) ) { break ; } scanner . pos -- ; } if ( start !== scanner . pos && consume ( scanner , Chars . Equals ) && consumeIdent ( scanner ) ) { return true ; } scanner . pos = start ; return false ; } /**
 * Consumes HTML identifier from stream
 */ function consumeIdent ( scanner ) { return consumeWhile ( scanner , isIdent ) ; } /**
 * Check if given character code belongs to HTML identifier
 */ function isIdent ( ch ) { return ch === Chars . Colon || ch === Chars . Dash || isAlpha ( ch ) || isNumber ( ch ) ; } /**
 * Check if given character code is alpha code (letter though A to Z)
 */ function isAlpha ( ch ) { ch &= ~ 32 ; return ch >= 65 && ch <= 90 ; } /**
 * Check if given code is a number
 */ function isNumber ( ch ) { return ch > 47 && ch < 58 ; } /**
 * Check if given code is a whitespace
 */ function isWhiteSpace ( ch ) { return ch === Chars . Space || ch === Chars . Tab ; } /**
 * Check if given code may belong to unquoted attribute value
 */ function isUnquotedValue ( ch ) { return ! isNaN ( ch ) && ch !== Chars . Equals && ! isWhiteSpace ( ch ) && ! isQuote ( ch ) ; } function isOpenBracket ( ch ) { return ch === Brackets . CurlyL || ch === Brackets . RoundL || ch === Brackets . SquareL ; } function isCloseBracket ( ch ) { return ch === Brackets . CurlyR || ch === Brackets . RoundR || ch === Brackets . SquareR ; }