import { View , Template , KeyedTemplate } from '../core/view' ; import { ViewBase } from '../core/view-base' ; import { ViewEntry } from '../frame' ; import { Page } from '../page' ; import { debug } from '../../utils/debug' ; import { isDefined } from '../../utils/types' ; import { setPropertyValue , getComponentModule } from './component-builder' ; import type { ComponentModule } from './component-builder' ; import { platformNames } from '../../platform' ; import { sanitizeModuleName } from './module-name-sanitizer' ; import { resolveModuleName } from '../../module-name-resolver' ; import { xml2ui } from './xml2ui' ; export const ios = platformNames . ios . toLowerCase ( ) ; export const android = platformNames . android . toLowerCase ( ) ; export const defaultNameSpaceMatcher = /tns\.xsd$/i ; export interface LoadOptions { path : string ; name : string ; attributes ? : any ; exports ? : any ; page ? : Page ; } export class Builder { static knownTemplates : Set < string > = new Set ( [ 'itemTemplate' ] ) ; static knownMultiTemplates : Set < string > = new Set ( [ 'itemTemplates' ] ) ; static knownCollections : Set < string > = new Set ( [ 'items' , 'spans' , 'actionItems' ] ) ; static createViewFromEntry ( entry ) { if ( entry . create ) { const view = entry . create ( ) ; if ( ! view ) { throw new Error ( 'Failed to create View with entry.create() function.' ) ; } return view ; } else if ( entry . moduleName ) { const moduleName = sanitizeModuleName ( entry . moduleName ) ; const resolvedCodeModuleName = resolveModuleName ( moduleName , '' ) ; const moduleExports = resolvedCodeModuleName ? global . loadModule ( resolvedCodeModuleName , true ) : null ; if ( moduleExports && moduleExports . createPage ) { const view = moduleExports . createPage ( ) ; const resolvedCssModuleName = resolveModuleName ( moduleName , 'css' ) ; if ( resolvedCssModuleName ) { view . addCssFile ( resolvedCssModuleName ) ; } return view ; } else { const componentModule = loadInternal ( moduleName , moduleExports ) ; const componentView = componentModule && componentModule . component ; return componentView ; } } throw new Error ( 'Failed to load page XML file for module: ' + entry . moduleName ) ; } static parse ( value , context ? ) { if ( typeof value === 'function' ) { return ( < Template > value ) ( ) ; } else { const exports = context ? getExports ( context ) : undefined ; const componentModule = parseInternal ( value , exports ) ; return componentModule && componentModule . component ; } } static load ( pathOrOptions , context ? ) { let componentModule ; if ( typeof pathOrOptions === 'string' ) { const moduleName = sanitizeModuleName ( pathOrOptions ) ; componentModule = loadInternal ( moduleName , context ) ; } else { componentModule = loadCustomComponent ( pathOrOptions . path , pathOrOptions . name , pathOrOptions . attributes , pathOrOptions . exports , pathOrOptions . page , true ) ; } return componentModule && componentModule . component ; } static parseMultipleTemplates ( value , context ) { const dummyComponent = `<ListView><ListView.itemTemplates>${ value }</ListView.itemTemplates></ListView>` ; return parseInternal ( dummyComponent , context ) . component [ 'itemTemplates' ] ; } } export function parse ( value , context ? ) { console . log ( 'parse() is deprecated. Use Builder.parse() instead.' ) ; return Builder . parse ( value , context ) ; } export function parseMultipleTemplates ( value , context ) { console . log ( 'parseMultipleTemplates() is deprecated. Use Builder.parseMultipleTemplates() instead.' ) ; return Builder . parseMultipleTemplates ( value , context ) ; } export function load ( pathOrOptions , context ? ) { console . log ( 'load() is deprecated. Use Builder.load() instead.' ) ; return Builder . load ( pathOrOptions , context ) ; } export function createViewFromEntry ( entry ) { console . log ( 'createViewFromEntry() is deprecated. Use Builder.createViewFromEntry() instead.' ) ; return Builder . createViewFromEntry ( entry ) ; } function loadInternal ( moduleName , moduleExports ) { let componentModule ; const resolvedXmlModule = resolveModuleName ( moduleName , 'xml' ) ; if ( resolvedXmlModule ) { const text = global . loadModule ( resolvedXmlModule , true ) ; componentModule = parseInternal ( text , moduleExports , resolvedXmlModule , moduleName ) ; } const componentView = componentModule && componentModule . component ; if ( componentView ) { ( < any > componentView ) . exports = moduleExports ; componentView . _moduleName = moduleName ; } if ( ! componentModule ) { throw new Error ( 'Failed to load component from module: ' + moduleName ) ; } return componentModule ; } export function loadCustomComponent ( componentNamespace , componentName ? , attributes ? , context ? , parentPage ? , isRootComponent = true , moduleNamePath ? ) { if ( ! parentPage && context ) { parentPage = context [ '_parentPage' ] ; delete context [ '_parentPage' ] ; } let result ; componentNamespace = sanitizeModuleName ( componentNamespace ) ; const moduleName = `${ componentNamespace }/${ componentName }` ; const resolvedCodeModuleName = resolveModuleName ( moduleName , '' ) ; const resolvedXmlModuleName = resolveModuleName ( moduleName , 'xml' ) ; let resolvedCssModuleName = resolveModuleName ( moduleName , 'css' ) ; if ( resolvedXmlModuleName ) { let subExports = context ; if ( resolvedCodeModuleName ) { subExports = global . loadModule ( resolvedCodeModuleName , true ) ; } if ( ! subExports ) { subExports = { } ; } subExports [ '_parentPage' ] = parentPage ; result = loadInternal ( moduleName , subExports ) ; if ( isDefined ( result ) && isDefined ( result . component ) && isDefined ( attributes ) ) { for ( const attr in attributes ) { setPropertyValue ( result . component , subExports , context , attr , attributes [ attr ] ) ; } } } else { result = getComponentModule ( componentName , componentNamespace , attributes , context , moduleNamePath , isRootComponent ) ; if ( ! resolvedCssModuleName ) { resolvedCssModuleName = resolveModuleName ( componentNamespace , 'css' ) ; } } if ( parentPage && resolvedCssModuleName ) { parentPage . addCssFile ( resolvedCssModuleName ) ; } return result ; } export function getExports ( instance ) { const isView = ! ! instance . _domId ; if ( ! isView ) { return ( < any > instance ) . exports || instance ; } let exportObject = ( < any > instance ) . exports ; let parent = instance . parent ; while ( exportObject === undefined && parent ) { exportObject = ( < any > parent ) . exports ; parent = parent . parent ; } return exportObject ; } function parseInternal ( value , context , xmlModule ? , moduleName ? ) { if ( __UI_USE_XML_PARSER__ ) { let start ; let ui ; const errorFormat = debug && xmlModule ? xml2ui . SourceErrorFormat ( xmlModule ) : xml2ui . PositionErrorFormat ; const componentSourceTracker = debug && xmlModule ? xml2ui . ComponentSourceTracker ( xmlModule ) : ( ) => { } ; ( start = new xml2ui . XmlStringParser ( errorFormat ) ) . pipe ( new xml2ui . PlatformFilter ( ) ) . pipe ( new xml2ui . XmlStateParser ( ( ui = new xml2ui . ComponentParser ( context , errorFormat , componentSourceTracker , moduleName ) ) ) ) ; start . parse ( value ) ; return ui . rootComponentModule ; } else { return null ; } }