@@ -43,83 +43,165 @@ export function parse(value: string | view.Template, context: any): view.View {
4343}
4444
4545function parseInternal ( value : string , context : any , uri ?: string ) : componentBuilder . ComponentModule {
46- var currentPage : page . Page ;
47- var rootComponentModule : componentBuilder . ComponentModule ;
48- // Temporary collection used for parent scope.
49- var parents = new Array < componentBuilder . ComponentModule > ( ) ;
50- var complexProperties = new Array < ComplexProperty > ( ) ;
46+
47+ var start : xml2ui . XmlStringParser ;
48+ var ui : xml2ui . UIParser ;
49+
50+ var errorFormat = ( debug . debug && uri ) ? xml2ui . SourceErrorFormat ( uri ) : xml2ui . PositionErrorFormat ;
51+
52+ ( start = new xml2ui . XmlStringParser ( errorFormat ) )
53+ . pipe ( new xml2ui . PlatformFilter ( ) )
54+ . pipe ( ui = new xml2ui . UIParser ( context ) ) ;
5155
52- var templateBuilder : templateBuilderDef . TemplateBuilder ;
56+ start . parseString ( value ) ;
57+
58+ return ui . rootComponentModule ;
59+ }
5360
54- var currentPlatformContext : string ;
61+ namespace xml2ui {
62+
63+ export class XmlStream {
64+ private next : XmlStream ;
65+
66+ public pipe < Next extends XmlStream > ( next : Next ) : Next {
67+ this . next = next ;
68+ return next ;
69+ }
70+
71+ public parse ( args : xml . ParserEvent ) : XmlStream {
72+ this . next = this . next . parse ( args ) ;
73+ return this ;
74+ }
75+ }
76+
77+ export class XmlStringParser extends XmlStream {
78+ private error : ErrorFormatter ;
79+
80+ constructor ( error ?: ErrorFormatter ) {
81+ super ( ) ;
82+ this . error = error || PositionErrorFormat ;
83+ }
84+
85+ public parseString ( value : string ) {
86+ var xmlParser = new xml . XmlParser ( ( args : xml . ParserEvent ) => {
87+ try {
88+ super . parse ( args ) ;
89+ } catch ( e ) {
90+ throw this . error ( e , args . position ) ;
91+ }
92+ } , ( e , p ) => {
93+ throw this . error ( e , p ) ;
94+ } , true ) ;
95+
96+ if ( types . isString ( value ) ) {
97+ value = value . replace ( / x m l n s = ( " | ' ) h t t p : \/ \/ ( ( w w w ) | ( s c h e m a s ) ) \. n a t i v e s c r i p t \. o r g \/ t n s \. x s d \1/ , "" ) ;
98+ xmlParser . parse ( value ) ;
99+ }
100+ }
101+ }
102+
103+ interface ErrorFormatter {
104+ ( e : Error , p : xml . Position ) : Error ;
105+ }
106+
107+ export function PositionErrorFormat ( e : Error , p : xml . Position ) : Error {
108+ return new debug . ScopeError ( e , "Parsing XML at " + p . line + ":" + p . column ) ;
109+ }
55110
56- var wrapSource : ( e : Error , p : xml . Position ) => Error ;
57- if ( debug . debug && uri ) {
58- wrapSource = ( e : Error , p : xml . Position ) => {
111+ export function SourceErrorFormat ( uri ) : ErrorFormatter {
112+ return ( e : Error , p : xml . Position ) => {
59113 var source = new debug . Source ( uri , p . line , p . column ) ;
60114 e = new debug . SourceError ( e , source , "Building UI from XML." ) ;
61115 return e ;
62116 }
63- } else {
64- wrapSource = e => e ; // no-op identity
65- }
66-
67- // Parse the XML.
68- var xmlParser = new xml . XmlParser ( ( args : xml . ParserEvent ) => {
69- try {
70- if ( args . eventType === xml . ParserEventType . StartElement ) {
117+ }
118+
119+ export class PlatformFilter extends XmlStream {
120+ private currentPlatformContext : string ;
121+
122+ public parse ( args : xml . ParserEvent ) : XmlStream {
123+ if ( args . eventType === xml . ParserEventType . StartElement ) {
71124 if ( isPlatform ( args . elementName ) ) {
72125
73- if ( currentPlatformContext ) {
74- throw new Error ( "Already in '" + currentPlatformContext + "' platform context and cannot switch to '" + args . elementName + "' platform! Platform tags cannot be nested." ) ;
126+ if ( this . currentPlatformContext ) {
127+ throw new Error ( "Already in '" + this . currentPlatformContext + "' platform context and cannot switch to '" + args . elementName + "' platform! Platform tags cannot be nested." ) ;
75128 }
76129
77- currentPlatformContext = args . elementName ;
78- return ;
130+ this . currentPlatformContext = args . elementName ;
131+ return this ;
79132 }
80133 }
81134
82135 if ( args . eventType === xml . ParserEventType . EndElement ) {
83136 if ( isPlatform ( args . elementName ) ) {
84- currentPlatformContext = undefined ;
85- return ;
137+ this . currentPlatformContext = undefined ;
138+ return this ;
86139 }
87140 }
88141
89- if ( currentPlatformContext && ! isCurentPlatform ( currentPlatformContext ) ) {
90- return ;
142+ if ( this . currentPlatformContext && ! isCurentPlatform ( this . currentPlatformContext ) ) {
143+ return this ;
91144 }
145+
146+ return super . parse ( args ) ;
147+ }
148+ }
92149
93- if ( templateBuilder ) {
94- var finished = templateBuilder . handleElement ( args ) ;
95- if ( finished ) {
96- // Clean-up and continnue
97- templateBuilder = undefined ;
98- }
99- else {
100- // Skip processing untill the template builder finishes his job.
101- return ;
102- }
150+ export class TemplateParser extends XmlStream {
151+
152+ private templateBuilder : templateBuilderDef . TemplateBuilder ;
153+ private previous : XmlStream ;
154+
155+ constructor ( previous : XmlStream , template : templateBuilderDef . TemplateProperty ) {
156+ super ( ) ;
157+ this . previous = previous ;
158+ this . templateBuilder = new templateBuilderDef . TemplateBuilder ( template ) ;
159+ }
160+
161+ public parse ( args : xml . ParserEvent ) : XmlStream {
162+ if ( this . templateBuilder . handleElement ( args ) ) {
163+ return this . previous ;
164+ } else {
165+ return this ;
103166 }
167+ }
168+ }
169+
170+ export class UIParser extends XmlStream {
171+
172+ public rootComponentModule : componentBuilder . ComponentModule ;
173+
174+ private context : any ;
175+
176+ private currentPage : page . Page ;
177+ private parents = new Array < componentBuilder . ComponentModule > ( ) ;
178+ private complexProperties = new Array < ComplexProperty > ( ) ;
179+
180+ constructor ( context : any ) {
181+ super ( ) ;
182+ this . context = context ;
183+ }
184+
185+ public parse ( args : xml . ParserEvent ) : XmlStream {
104186
105187 // Get the current parent.
106- var parent = parents [ parents . length - 1 ] ;
107- var complexProperty = complexProperties [ complexProperties . length - 1 ] ;
188+ var parent = this . parents [ this . parents . length - 1 ] ;
189+ var complexProperty = this . complexProperties [ this . complexProperties . length - 1 ] ;
108190
109191 // Create component instance from every element declaration.
110192 if ( args . eventType === xml . ParserEventType . StartElement ) {
111193 if ( isComplexProperty ( args . elementName ) ) {
112194
113195 var name = getComplexProperty ( args . elementName ) ;
114196
115- complexProperties . push ( {
197+ this . complexProperties . push ( {
116198 parent : parent ,
117199 name : name ,
118200 items : [ ] ,
119201 } ) ;
120202
121203 if ( templateBuilderDef . isKnownTemplate ( name , parent . exports ) ) {
122- templateBuilder = new templateBuilderDef . TemplateBuilder ( {
204+ return new TemplateParser ( this , {
123205 context : parent ? getExports ( parent . component ) : null , // Passing 'context' won't work if you set "codeFile" on the page
124206 parent : parent ,
125207 name : name ,
@@ -134,39 +216,31 @@ function parseInternal(value: string, context: any, uri?: string): componentBuil
134216
135217 if ( args . prefix && args . namespace ) {
136218 // Custom components
137- componentModule = loadCustomComponent ( args . namespace , args . elementName , args . attributes , context , currentPage ) ;
219+ componentModule = loadCustomComponent ( args . namespace , args . elementName , args . attributes , this . context , this . currentPage ) ;
138220 } else {
139221 // Default components
140- componentModule = componentBuilder . getComponentModule ( args . elementName , args . namespace , args . attributes , context ) ;
222+ componentModule = componentBuilder . getComponentModule ( args . elementName , args . namespace , args . attributes , this . context ) ;
141223 }
142224
143225 if ( componentModule ) {
144226 if ( parent ) {
145- if ( componentModule . component instanceof view . View ) {
146- if ( complexProperty ) {
147- // Add to complex property to component.
148- addToComplexProperty ( parent , complexProperty , componentModule )
149- } else if ( ( < any > parent . component ) . _addChildFromBuilder ) {
150- // Add component to visual tree
151- ( < any > parent . component ) . _addChildFromBuilder ( args . elementName , componentModule . component ) ;
152- }
153- } else if ( complexProperty ) {
227+ if ( complexProperty ) {
154228 // Add component to complex property of parent component.
155229 addToComplexProperty ( parent , complexProperty , componentModule ) ;
156230 } else if ( ( < any > parent . component ) . _addChildFromBuilder ) {
157231 ( < any > parent . component ) . _addChildFromBuilder ( args . elementName , componentModule . component ) ;
158232 }
159- } else if ( parents . length === 0 ) {
233+ } else if ( this . parents . length === 0 ) {
160234 // Set root component.
161- rootComponentModule = componentModule ;
235+ this . rootComponentModule = componentModule ;
162236
163- if ( rootComponentModule && rootComponentModule . component instanceof page . Page ) {
164- currentPage = < page . Page > rootComponentModule . component ;
237+ if ( this . rootComponentModule && this . rootComponentModule . component instanceof page . Page ) {
238+ this . currentPage = < page . Page > this . rootComponentModule . component ;
165239 }
166240 }
167241
168242 // Add the component instance to the parents scope collection.
169- parents . push ( componentModule ) ;
243+ this . parents . push ( componentModule ) ;
170244 }
171245 }
172246
@@ -180,27 +254,17 @@ function parseInternal(value: string, context: any, uri?: string): componentBuil
180254 }
181255 }
182256 // Remove the last complexProperty from the complexProperties collection (move to the previous complexProperty scope).
183- complexProperties . pop ( ) ;
257+ this . complexProperties . pop ( ) ;
184258
185259 } else {
186260 // Remove the last parent from the parents collection (move to the previous parent scope).
187- parents . pop ( ) ;
261+ this . parents . pop ( ) ;
188262 }
189263 }
190-
191- } catch ( e ) {
192- throw wrapSource ( e , args . position ) ;
264+
265+ return this ;
193266 }
194- } , ( e , p ) => {
195- throw wrapSource ( new Error ( "XML parse error: " + e . message ) , p ) ;
196- } , true ) ;
197-
198- if ( types . isString ( value ) ) {
199- value = value . replace ( / x m l n s = ( " | ' ) h t t p : \/ \/ ( ( w w w ) | ( s c h e m a s ) ) \. n a t i v e s c r i p t \. o r g \/ t n s \. x s d \1/ , "" ) ;
200- xmlParser . parse ( value ) ;
201267 }
202-
203- return rootComponentModule ;
204268}
205269
206270function loadCustomComponent ( componentPath : string , componentName ?: string , attributes ?: Object , context ?: Object , parentPage ?: page . Page ) : componentBuilder . ComponentModule {
0 commit comments