@@ -9,6 +9,7 @@ import definition = require("ui/builder");
99import page = require( "ui/page" ) ;
1010import fileResolverModule = require( "file-system/file-name-resolver" ) ;
1111import trace = require( "trace" ) ;
12+ import debug = require( "utils/debug" ) ;
1213
1314var KNOWNCOLLECTIONS = "knownCollections" ;
1415
@@ -41,7 +42,7 @@ export function parse(value: string | view.Template, context: any): view.View {
4142 }
4243}
4344
44- function parseInternal ( value : string , context : any ) : componentBuilder . ComponentModule {
45+ function parseInternal ( value : string , context : any , uri ?: string ) : componentBuilder . ComponentModule {
4546 var currentPage : page . Page ;
4647 var rootComponentModule : componentBuilder . ComponentModule ;
4748 // Temporary collection used for parent scope.
@@ -51,134 +52,148 @@ function parseInternal(value: string, context: any): componentBuilder.ComponentM
5152 var templateBuilder : templateBuilderDef . TemplateBuilder ;
5253
5354 var currentPlatformContext : string ;
55+
56+ var wrapSource : ( e : Error , p : xml . Position ) => Error ;
57+ if ( debug . debug && uri ) {
58+ wrapSource = ( e : Error , p : xml . Position ) => {
59+ var source = new debug . Source ( uri , p . line , p . column ) ;
60+ e = new debug . SourceError ( e , source , "Building UI from XML." ) ;
61+ return e ;
62+ }
63+ } else {
64+ wrapSource = e => e ; // no-op identity
65+ }
5466
5567 // Parse the XML.
5668 var xmlParser = new xml . XmlParser ( ( args : xml . ParserEvent ) => {
57-
58- if ( args . eventType === xml . ParserEventType . StartElement ) {
59- if ( isPlatform ( args . elementName ) ) {
60-
61- if ( currentPlatformContext ) {
62- throw new Error ( "Already in '" + currentPlatformContext + "' platform context and cannot switch to '" + args . elementName + "' platform! Platform tags cannot be nested." ) ;
69+ try {
70+ if ( args . eventType === xml . ParserEventType . StartElement ) {
71+ if ( isPlatform ( args . elementName ) ) {
72+
73+ if ( currentPlatformContext ) {
74+ throw new Error ( "Already in '" + currentPlatformContext + "' platform context and cannot switch to '" + args . elementName + "' platform! Platform tags cannot be nested." ) ;
75+ }
76+
77+ currentPlatformContext = args . elementName ;
78+ return ;
6379 }
64-
65- currentPlatformContext = args . elementName ;
66- return ;
67- }
68- }
69-
70- if ( args . eventType === xml . ParserEventType . EndElement ) {
71- if ( isPlatform ( args . elementName ) ) {
72- currentPlatformContext = undefined ;
73- return ;
7480 }
75- }
76-
77- if ( currentPlatformContext && ! isCurentPlatform ( currentPlatformContext ) ) {
78- return ;
79- }
80-
81- if ( templateBuilder ) {
82- var finished = templateBuilder . handleElement ( args ) ;
83- if ( finished ) {
84- // Clean-up and continnue
85- templateBuilder = undefined ;
81+
82+ if ( args . eventType === xml . ParserEventType . EndElement ) {
83+ if ( isPlatform ( args . elementName ) ) {
84+ currentPlatformContext = undefined ;
85+ return ;
86+ }
8687 }
87- else {
88- // Skip processing untill the template builder finishes his job.
88+
89+ if ( currentPlatformContext && ! isCurentPlatform ( currentPlatformContext ) ) {
8990 return ;
9091 }
91- }
92-
93- // Get the current parent.
94- var parent = parents [ parents . length - 1 ] ;
95- var complexProperty = complexProperties [ complexProperties . length - 1 ] ;
96-
97- // Create component instance from every element declaration.
98- if ( args . eventType === xml . ParserEventType . StartElement ) {
99- if ( isComplexProperty ( args . elementName ) ) {
100-
101- var name = getComplexProperty ( args . elementName ) ;
102-
103- complexProperties . push ( {
104- parent : parent ,
105- name : name ,
106- items : [ ] ,
107- } ) ;
108-
109- if ( templateBuilderDef . isKnownTemplate ( name , parent . exports ) ) {
110- templateBuilder = new templateBuilderDef . TemplateBuilder ( {
111- context : parent ? getExports ( parent . component ) : null , // Passing 'context' won't work if you set "codeFile" on the page
92+
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+ }
103+ }
104+
105+ // Get the current parent.
106+ var parent = parents [ parents . length - 1 ] ;
107+ var complexProperty = complexProperties [ complexProperties . length - 1 ] ;
108+
109+ // Create component instance from every element declaration.
110+ if ( args . eventType === xml . ParserEventType . StartElement ) {
111+ if ( isComplexProperty ( args . elementName ) ) {
112+
113+ var name = getComplexProperty ( args . elementName ) ;
114+
115+ complexProperties . push ( {
112116 parent : parent ,
113117 name : name ,
114- elementName : args . elementName ,
115- templateItems : [ ]
118+ items : [ ] ,
116119 } ) ;
117- }
118-
119- } else {
120-
121- var componentModule : componentBuilder . ComponentModule ;
122-
123- if ( args . prefix && args . namespace ) {
124- // Custom components
125- componentModule = loadCustomComponent ( args . namespace , args . elementName , args . attributes , context , currentPage ) ;
120+
121+ if ( templateBuilderDef . isKnownTemplate ( name , parent . exports ) ) {
122+ templateBuilder = new templateBuilderDef . TemplateBuilder ( {
123+ context : parent ? getExports ( parent . component ) : null , // Passing 'context' won't work if you set "codeFile" on the page
124+ parent : parent ,
125+ name : name ,
126+ elementName : args . elementName ,
127+ templateItems : [ ]
128+ } ) ;
129+ }
130+
126131 } else {
127- // Default components
128- componentModule = componentBuilder . getComponentModule ( args . elementName , args . namespace , args . attributes , context ) ;
129- }
130-
131- if ( componentModule ) {
132- if ( parent ) {
133- if ( componentModule . component instanceof view . View ) {
134- if ( complexProperty ) {
135- // Add to complex property to component.
136- addToComplexProperty ( parent , complexProperty , componentModule )
132+
133+ var componentModule : componentBuilder . ComponentModule ;
134+
135+ if ( args . prefix && args . namespace ) {
136+ // Custom components
137+ componentModule = loadCustomComponent ( args . namespace , args . elementName , args . attributes , context , currentPage ) ;
138+ } else {
139+ // Default components
140+ componentModule = componentBuilder . getComponentModule ( args . elementName , args . namespace , args . attributes , context ) ;
141+ }
142+
143+ if ( componentModule ) {
144+ 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 ) {
154+ // Add component to complex property of parent component.
155+ addToComplexProperty ( parent , complexProperty , componentModule ) ;
137156 } else if ( ( < any > parent . component ) . _addChildFromBuilder ) {
138- // Add component to visual tree
139157 ( < any > parent . component ) . _addChildFromBuilder ( args . elementName , componentModule . component ) ;
140158 }
141- } else if ( complexProperty ) {
142- // Add component to complex property of parent component.
143- addToComplexProperty ( parent , complexProperty , componentModule ) ;
144- } else if ( ( < any > parent . component ) . _addChildFromBuilder ) {
145- ( < any > parent . component ) . _addChildFromBuilder ( args . elementName , componentModule . component ) ;
146- }
147- } else if ( parents . length === 0 ) {
148- // Set root component.
149- rootComponentModule = componentModule ;
150-
151- if ( rootComponentModule && rootComponentModule . component instanceof page . Page ) {
152- currentPage = < page . Page > rootComponentModule . component ;
159+ } else if ( parents . length === 0 ) {
160+ // Set root component.
161+ rootComponentModule = componentModule ;
162+
163+ if ( rootComponentModule && rootComponentModule . component instanceof page . Page ) {
164+ currentPage = < page . Page > rootComponentModule . component ;
165+ }
153166 }
167+
168+ // Add the component instance to the parents scope collection.
169+ parents . push ( componentModule ) ;
154170 }
155-
156- // Add the component instance to the parents scope collection.
157- parents . push ( componentModule ) ;
158171 }
159- }
160-
161- } else if ( args . eventType === xml . ParserEventType . EndElement ) {
162- if ( isComplexProperty ( args . elementName ) ) {
163- if ( complexProperty ) {
164- if ( parent && ( < any > parent . component ) . _addArrayFromBuilder ) {
165- // If parent is AddArrayFromBuilder call the interface method to populate the array property.
166- ( < any > parent . component ) . _addArrayFromBuilder ( complexProperty . name , complexProperty . items ) ;
167- complexProperty . items = [ ] ;
172+
173+ } else if ( args . eventType === xml . ParserEventType . EndElement ) {
174+ if ( isComplexProperty ( args . elementName ) ) {
175+ if ( complexProperty ) {
176+ if ( parent && ( < any > parent . component ) . _addArrayFromBuilder ) {
177+ // If parent is AddArrayFromBuilder call the interface method to populate the array property.
178+ ( < any > parent . component ) . _addArrayFromBuilder ( complexProperty . name , complexProperty . items ) ;
179+ complexProperty . items = [ ] ;
180+ }
168181 }
182+ // Remove the last complexProperty from the complexProperties collection (move to the previous complexProperty scope).
183+ complexProperties . pop ( ) ;
184+
185+ } else {
186+ // Remove the last parent from the parents collection (move to the previous parent scope).
187+ parents . pop ( ) ;
169188 }
170- // Remove the last complexProperty from the complexProperties collection (move to the previous complexProperty scope).
171- complexProperties . pop ( ) ;
172-
173- } else {
174- // Remove the last parent from the parents collection (move to the previous parent scope).
175- parents . pop ( ) ;
176189 }
190+
191+ } catch ( e ) {
192+ throw wrapSource ( e , args . position ) ;
177193 }
178-
179- } , ( e ) => {
180- throw new Error ( "XML parse error: " + e . message ) ;
181- } , true ) ;
194+ } , ( e , p ) => {
195+ throw wrapSource ( new Error ( "XML parse error: " + e . message ) , p ) ;
196+ } , true ) ;
182197
183198 if ( types . isString ( value ) ) {
184199 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/ , "" ) ;
@@ -271,7 +286,7 @@ function loadInternal(fileName: string, context?: any): componentBuilder.Compone
271286 throw new Error ( "Error loading file " + fileName + " :" + error . message ) ;
272287 }
273288 var text = file . readTextSync ( onError ) ;
274- componentModule = parseInternal ( text , context ) ;
289+ componentModule = parseInternal ( text , context , fileName ) ;
275290 }
276291
277292 if ( componentModule && componentModule . component ) {
0 commit comments