import { getComponentId } from '../utils/utils' ; const REHYDRATED = '__REHYDRATED__' ; const TEMPLATE_END = '__T_END__' ; /**
 * A Renderer3 renderer that matches with existing DOM nodes from prerendering.
 */ class RehydrationRenderer { private current : Node | null = null ; private templateMode = false ; private templateNodes : Node [ ] = [ ] ; private componentId : number ; private constructor ( private host , private scoped ) { const hostEl = ( host as any as Element ) ; this . current = hostEl . firstChild ; if ( this . scoped ) { this . componentId = getComponentId ( document , hostEl . localName ) ; hostEl . setAttribute ( `_nghost-${ this . componentId }` , '' ) ; } } private static currentRenderer ? : RehydrationRenderer ; static create ( hostElement , scoped = false ) { if ( this . currentRenderer && this . currentRenderer . host === hostElement ) { return this . currentRenderer ; } else { return ( this . currentRenderer = new RehydrationRenderer ( hostElement , scoped ) ) ; } } private getCurrentNodeAndAdvance ( ) { if ( this . current == null ) { return null ; } const last = this . current ; let next = null ; if ( isBuiltInNode ( last ) ) { next = this . current . firstChild ; } if ( next == null ) { do { if ( this . current [ TEMPLATE_END ] ) { next = this . templateNodes . shift ( ) ; break ; } if ( this . current === ( this . host as any ) ) { break ; } next = this . current . nextSibling ; if ( next == null ) { this . current = this . current . parentNode ; } } while ( next == null && this . current != null ) ; } this . current = next ; if ( ! this . current && ! this . templateMode ) { this . templateMode = true ; this . current = this . templateNodes . shift ( ) ; } last [ REHYDRATED ] = true ; return last ; } createComment ( data ) { if ( this . current && this . current . nodeType === Node . COMMENT_NODE && ( this . current as Comment ) . data . startsWith ( 's' ) ) { const comment = this . current as Comment ; const endData = 'e' + comment . data . substring ( 1 ) ; let nodes = [ ] ; let node = this . current . nextSibling ; while ( node && node . nodeType !== Node . COMMENT_NODE && ( ( node as Comment ) . data !== endData ) ) { nodes . push ( node ) ; node = node . nextSibling ; } if ( ! node ) { this . templateMode = true ; this . current = null ; console . error ( 'Did not find closing template comment' ) ; } if ( nodes . length > 0 ) { nodes [ nodes . length - 1 ] [ TEMPLATE_END ] = true ; this . templateNodes . push ( nodes [ 0 ] ) ; } this . current = node ; return ( this . getCurrentNodeAndAdvance ( ) ) ; } else { return document . createComment ( data ) ; } } createElement ( localName ) { if ( this . current && this . current . nodeType === Node . ELEMENT_NODE && ( this . current as Element ) . localName === localName ) { return this . getCurrentNodeAndAdvance ( ) ; } else { const el = document . createElement ( localName ) ; if ( this . scoped ) { el . setAttribute ( `_ngcontent-${ this . componentId }` , '' ) ; } return el ; } } createElementNS ( namespace , localName ) { if ( this . current && this . current . nodeType === Node . ELEMENT_NODE && ( this . current as Element ) . localName === localName && ( this . current as Element ) . namespaceURI === namespace ) { return this . getCurrentNodeAndAdvance ( ) ; } else { const el = document . createElementNS ( namespace , localName ) ; if ( this . scoped ) { el . setAttribute ( `_ngcontent-${ this . componentId }` , '' ) ; } return el ; } } createTextNode ( data ) { if ( this . current && this . current . nodeType === Node . TEXT_NODE ) { return this . getCurrentNodeAndAdvance ( ) ; } else { return document . createTextNode ( data ) ; } } querySelector ( selectors ) { return document . querySelector ( selectors ) as any ; } } export const RehydrationRendererFactory = { createRenderer : ( hostElement , rendererType ) => { if ( hostElement == null ) { return document ; } return RehydrationRenderer . create ( hostElement , false ) ; } } ; export const ScopedRehydrationRendererFactory = { createRenderer : ( hostElement , rendererType ) => { if ( hostElement == null ) { return document ; } return RehydrationRenderer . create ( hostElement , true ) ; } } ; function isBuiltInNode ( n ) { if ( n . nodeType !== Node . ELEMENT_NODE ) { return true ; } const el = n as HTMLElement ; if ( el . localName . indexOf ( '-' ) > 0 || el . constructor === HTMLUnknownElement || customElements . get ( el . localName ) != null ) { return false ; } else { return true ; } }