@@ -43,83 +43,165 @@ export function parse(value: string | view.Template, context: any): view.View {
43
43
}
44
44
45
45
function 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 ) ) ;
51
55
52
- var templateBuilder : templateBuilderDef . TemplateBuilder ;
56
+ start . parseString ( value ) ;
57
+
58
+ return ui . rootComponentModule ;
59
+ }
53
60
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
+ }
55
110
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 ) => {
59
113
var source = new debug . Source ( uri , p . line , p . column ) ;
60
114
e = new debug . SourceError ( e , source , "Building UI from XML." ) ;
61
115
return e ;
62
116
}
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 ) {
71
124
if ( isPlatform ( args . elementName ) ) {
72
125
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." ) ;
75
128
}
76
129
77
- currentPlatformContext = args . elementName ;
78
- return ;
130
+ this . currentPlatformContext = args . elementName ;
131
+ return this ;
79
132
}
80
133
}
81
134
82
135
if ( args . eventType === xml . ParserEventType . EndElement ) {
83
136
if ( isPlatform ( args . elementName ) ) {
84
- currentPlatformContext = undefined ;
85
- return ;
137
+ this . currentPlatformContext = undefined ;
138
+ return this ;
86
139
}
87
140
}
88
141
89
- if ( currentPlatformContext && ! isCurentPlatform ( currentPlatformContext ) ) {
90
- return ;
142
+ if ( this . currentPlatformContext && ! isCurentPlatform ( this . currentPlatformContext ) ) {
143
+ return this ;
91
144
}
145
+
146
+ return super . parse ( args ) ;
147
+ }
148
+ }
92
149
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 ;
103
166
}
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 {
104
186
105
187
// 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 ] ;
108
190
109
191
// Create component instance from every element declaration.
110
192
if ( args . eventType === xml . ParserEventType . StartElement ) {
111
193
if ( isComplexProperty ( args . elementName ) ) {
112
194
113
195
var name = getComplexProperty ( args . elementName ) ;
114
196
115
- complexProperties . push ( {
197
+ this . complexProperties . push ( {
116
198
parent : parent ,
117
199
name : name ,
118
200
items : [ ] ,
119
201
} ) ;
120
202
121
203
if ( templateBuilderDef . isKnownTemplate ( name , parent . exports ) ) {
122
- templateBuilder = new templateBuilderDef . TemplateBuilder ( {
204
+ return new TemplateParser ( this , {
123
205
context : parent ? getExports ( parent . component ) : null , // Passing 'context' won't work if you set "codeFile" on the page
124
206
parent : parent ,
125
207
name : name ,
@@ -134,39 +216,31 @@ function parseInternal(value: string, context: any, uri?: string): componentBuil
134
216
135
217
if ( args . prefix && args . namespace ) {
136
218
// 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 ) ;
138
220
} else {
139
221
// 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 ) ;
141
223
}
142
224
143
225
if ( componentModule ) {
144
226
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 ) {
154
228
// Add component to complex property of parent component.
155
229
addToComplexProperty ( parent , complexProperty , componentModule ) ;
156
230
} else if ( ( < any > parent . component ) . _addChildFromBuilder ) {
157
231
( < any > parent . component ) . _addChildFromBuilder ( args . elementName , componentModule . component ) ;
158
232
}
159
- } else if ( parents . length === 0 ) {
233
+ } else if ( this . parents . length === 0 ) {
160
234
// Set root component.
161
- rootComponentModule = componentModule ;
235
+ this . rootComponentModule = componentModule ;
162
236
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 ;
165
239
}
166
240
}
167
241
168
242
// Add the component instance to the parents scope collection.
169
- parents . push ( componentModule ) ;
243
+ this . parents . push ( componentModule ) ;
170
244
}
171
245
}
172
246
@@ -180,27 +254,17 @@ function parseInternal(value: string, context: any, uri?: string): componentBuil
180
254
}
181
255
}
182
256
// Remove the last complexProperty from the complexProperties collection (move to the previous complexProperty scope).
183
- complexProperties . pop ( ) ;
257
+ this . complexProperties . pop ( ) ;
184
258
185
259
} else {
186
260
// Remove the last parent from the parents collection (move to the previous parent scope).
187
- parents . pop ( ) ;
261
+ this . parents . pop ( ) ;
188
262
}
189
263
}
190
-
191
- } catch ( e ) {
192
- throw wrapSource ( e , args . position ) ;
264
+
265
+ return this ;
193
266
}
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 ) ;
201
267
}
202
-
203
- return rootComponentModule ;
204
268
}
205
269
206
270
function loadCustomComponent ( componentPath : string , componentName ?: string , attributes ?: Object , context ?: Object , parentPage ?: page . Page ) : componentBuilder . ComponentModule {
0 commit comments