import { InDiv } from '../indiv' ; import { parseTag } from './parse-tag' ; import { Vnode } from './vnode' ; export type ParseOptions = { components : string [ ] ; directives : string [ ] ; } ; export param { string } template param { ParseOptions } options returns { Vnode [ ] } export function parseTemplateToVnode ( template , options = { components : [ ] , directives : [ ] } ) { const tagRegex = /(<(?!!--)(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>)|((?:[^>]\s|^)<!--(?!<!)[^\[>][\s\S]*?-->)/g ; const result = [ ] ; let current = null ; let level = - 1 ; const arr = [ ] ; const byTag = { } ; let inComponent = false ; const componentStack = [ ] ; template . replace ( tagRegex , ( tag , tagMatch , commentMatch , index ) : string => { if ( inComponent && componentStack . length > 0 && tag === `</${ componentStack [ componentStack . length - 1 ] . tagName }>` ) { componentStack . pop ( ) ; if ( componentStack . length === 0 ) inComponent = false ; } const isOpen = tag . charAt ( 1 ) !== '/' ; const start = index + tag . length ; const nextChar = template . charAt ( start ) ; let parent = null ; if ( isOpen ) { level ++ ; if ( commentMatch ) current = { type : 'comment' , nodeValue : tag . replace ( /^\s*<!--/ , '' ) . replace ( /-->\s*$/ , '' ) , parentVnode : current , template : tag , voidElement : true , } ; if ( tagMatch && ! commentMatch ) current = parseTag ( tag , options . directives ) ; if ( inComponent ) current . inComponent = inComponent ; if ( current . type === 'tag' && options . components . indexOf ( current . tagName ) !== - 1 ) { current . type = 'component' ; inComponent = true ; componentStack . push ( current ) ; } const testNodeValue = template . slice ( start , template . indexOf ( '<' , start ) ) ; if ( ! current . voidElement && nextChar && nextChar !== '<' && ! /^\s*$/ . test ( testNodeValue ) ) { current . childNodes . push ( { type : 'text' , nodeValue : testNodeValue , parentVnode : current , template : testNodeValue , voidElement : true , inComponent , } ) ; } ( byTag as any ) [ ( current as any ) . tagName ] = current ; if ( level === 0 ) result . push ( current ) ; parent = arr [ level - 1 ] ; if ( parent && parent . tagName !== ( InDiv . globalApplication . getRouteDOMKey || 'router-render' ) ) { current . parentVnode = parent ; parent . childNodes . push ( current ) ; } arr [ level ] = current ; } if ( ! isOpen || current . voidElement ) { level -- ; if ( nextChar !== '<' && nextChar ) { parent = level === - 1 ? null : arr [ level ] ; const end = template . indexOf ( '<' , start ) ; const nodeValue = template . slice ( start , end === - 1 ? undefined : end ) ; if ( ! /^\s*$/ . test ( nodeValue ) && ! parent ) result . push ( { type : 'text' , nodeValue : nodeValue , parentVnode : parent , template : nodeValue , voidElement : true , inComponent , } ) ; if ( ! /^\s*$/ . test ( nodeValue ) && parent && parent . tagName !== ( InDiv . globalApplication . getRouteDOMKey || 'router-render' ) ) arr [ level ] . childNodes . push ( { type : 'text' , nodeValue : nodeValue , parentVnode : parent , template : nodeValue , voidElement : true , inComponent , } ) ; } } return tag ; } ) ; return result ; }