import { Disposable } from '@typed/disposable' ; import { createServerHistoryEnv , HistoryEnv , wrapInSubscription } from '@typed/history' ; import { serverStorage } from '@typed/storage' ; import { NodeFilter as ServerNodeFilter } from './NodeFilter' ; import { NodeIteratorImpl } from './NodeIterator' ; import { TreeWalkerImpl } from './TreeWalker' ; import { DomEnv , INodeFilter } from './types' ; export type CreateServerDomEnvOptions = { serverUrl ? : string ; localStorage ? : Map < string , string > ; sessionStorage ? : Map < string , string > ; customElements ? : CustomElementRegistry ; setGlobals ? : boolean ; window ? : any ; innerHeight ? : number ; innerWidth ? : number ; mediaType ? : string ; } ; const POPSTATE_EVENT_TYPE = 'popstate' ; export function createServerDomEnv < A > ( options = { } ) { const { createMatchMedia } = require ( './createMatchMedia' ) ; const { Crypto } = require ( '@peculiar/webcrypto' ) ; const basic = require ( 'basichtml' ) ; const { history , location , subscription } = wrapInSubscription ( createServerHistoryEnv < A > ( options . serverUrl || '/' ) ) ; const localStorage = serverStorage ( options . localStorage ) ; const sessionStorage = serverStorage ( options . sessionStorage ) ; const customElements = options . customElements || new basic . CustomElementRegistry ( ) ; const window = ( options . window || ( { } as any ) ) as Window ; const document = new basic . Document ( customElements ) ; if ( options . innerHeight !== void 0 ) { ; ( window as any ) . innerHeight = options . innerHeight ; } if ( options . innerWidth !== void 0 ) { ; ( window as any ) . innerWidth = options . innerWidth ; } document . createNodeIterator = ( root , whatToShow = NodeFilter . SHOW_ALL , filter ? ) => new NodeIteratorImpl ( root , whatToShow , filter ? filter : void 0 ) ; document . createTreeWalker = ( root , whatToShow = NodeFilter . SHOW_ALL , filter ? ) => new TreeWalkerImpl ( root , whatToShow , filter ? filter : void 0 ) ; const NodeImage = ( width ? , height ? ) => basic . Image ( document , width , height ) ; class NodeHTMLElement extends basic . HTMLElement { constructor ( name ) { super ( document , name ) ; } } basic . EventTarget . init ( window ) ; subscription . subscribe ( handleHistoryChange ( window ) ) ; if ( window . matchMedia === void 0 ) { window . matchMedia = createMatchMedia ( window , options . mediaType ) ; } const domEnv = { window , document , location , history , localStorage , sessionStorage , customElements , HTMLElement : ( NodeHTMLElement as any ) as typeof HTMLElement , NodeFilter : ServerNodeFilter , Event : basic . Event , CustomEvent : basic . CustomEvent , Image : ( NodeImage as any ) as typeof Image , crypto : new Crypto ( ) , } ; Object . keys ( domEnv ) . forEach ( ( key ) => ( ( window as any ) [ key ] = domEnv [ key as keyof DomEnv < A > ] ) ) ; if ( options . setGlobals ) { const win = global as any ; Object . keys ( domEnv ) . forEach ( ( key ) => ( win [ key ] = domEnv [ key as keyof DomEnv < A > ] ) ) ; } return domEnv ; } function handleHistoryChange ( window ) { const basic = require ( 'basichtml' ) ; return ( { history } ) => { const event = new basic . Event ( POPSTATE_EVENT_TYPE , { bubbles : true , cancelable : false } ) ; ( event as any ) . state = history . state ; window . dispatchEvent ( event ) ; if ( window . onpopstate ) { window . onpopstate ( event ) ; } return Disposable . None ; } ; }