@@ -58,21 +58,21 @@ function writeAttributes(attributes, options, depth) {
5858 if ( 'attributesFn' in options ) {
5959 attributes = options . attributesFn ( attributes , currentElementName , currentElement ) ;
6060 }
61- var key , attr , attrName , quote , result = '' ;
61+ var key , attr , attrName , quote , result = [ ] ;
6262 for ( key in attributes ) {
6363 if ( attributes . hasOwnProperty ( key ) ) {
6464 quote = options . noQuotesForNativeAttributes && typeof attributes [ key ] !== 'string' ? '' : '"' ;
6565 attr = '' + attributes [ key ] ; // ensure number and boolean are converted to String
6666 attr = attr . replace ( / " / g, '"' ) ;
6767 attrName = 'attributeNameFn' in options ? options . attributeNameFn ( key , attr , currentElementName , currentElement ) : key ;
68- result += ( options . spaces && options . indentAttributes ? writeIndentation ( options , depth + 1 , false ) : ' ' ) ;
69- result += attrName + '=' + quote + ( 'attributeValueFn' in options ? options . attributeValueFn ( attr , key , currentElementName , currentElement ) : attr ) + quote ;
68+ result . push ( ( options . spaces && options . indentAttributes ? writeIndentation ( options , depth + 1 , false ) : ' ' ) ) ;
69+ result . push ( attrName + '=' + quote + ( 'attributeValueFn' in options ? options . attributeValueFn ( attr , key , currentElementName , currentElement ) : attr ) + quote ) ;
7070 }
7171 }
7272 if ( attributes && Object . keys ( attributes ) . length && options . spaces && options . indentAttributes ) {
73- result += writeIndentation ( options , depth , false ) ;
73+ result . push ( writeIndentation ( options , depth , false ) ) ;
7474 }
75- return result ;
75+ return result . join ( '' ) ;
7676}
7777
7878function writeDeclaration ( declaration , options , depth ) {
@@ -158,10 +158,10 @@ function hasContent(element, options) {
158158function writeElement ( element , options , depth ) {
159159 currentElement = element ;
160160 currentElementName = element . name ;
161- var xml = '' , elementName = 'elementNameFn' in options ? options . elementNameFn ( element . name , element ) : element . name ;
162- xml += '<' + elementName ;
161+ var xml = [ ] , elementName = 'elementNameFn' in options ? options . elementNameFn ( element . name , element ) : element . name ;
162+ xml . push ( '<' + elementName ) ;
163163 if ( element [ options . attributesKey ] ) {
164- xml += writeAttributes ( element [ options . attributesKey ] , options , depth ) ;
164+ xml . push ( writeAttributes ( element [ options . attributesKey ] , options , depth ) ) ;
165165 }
166166 var withClosingTag = element [ options . elementsKey ] && element [ options . elementsKey ] . length || element [ options . attributesKey ] && element [ options . attributesKey ] [ 'xml:space' ] === 'preserve' ;
167167 if ( ! withClosingTag ) {
@@ -172,18 +172,18 @@ function writeElement(element, options, depth) {
172172 }
173173 }
174174 if ( withClosingTag ) {
175- xml += '>' ;
175+ xml . push ( '>' ) ;
176176 if ( element [ options . elementsKey ] && element [ options . elementsKey ] . length ) {
177- xml += writeElements ( element [ options . elementsKey ] , options , depth + 1 ) ;
177+ xml . push ( writeElements ( element [ options . elementsKey ] , options , depth + 1 ) ) ;
178178 currentElement = element ;
179179 currentElementName = element . name ;
180180 }
181- xml += options . spaces && hasContent ( element , options ) ? '\n' + Array ( depth + 1 ) . join ( options . spaces ) : '' ;
182- xml += '</' + elementName + '>' ;
181+ xml . push ( options . spaces && hasContent ( element , options ) ? '\n' + Array ( depth + 1 ) . join ( options . spaces ) : '' ) ;
182+ xml . push ( '</' + elementName + '>' ) ;
183183 } else {
184- xml += '/>' ;
184+ xml . push ( '/>' ) ;
185185 }
186- return xml ;
186+ return xml . join ( '' ) ;
187187}
188188
189189function writeElements ( elements , options , depth , firstLine ) {
@@ -244,15 +244,15 @@ function writeElementCompact(element, name, options, depth, indent) {
244244 if ( typeof element === 'undefined' || element === null ) {
245245 return 'fullTagEmptyElementFn' in options && options . fullTagEmptyElementFn ( name , element ) || options . fullTagEmptyElement ? '<' + elementName + '></' + elementName + '>' : '<' + elementName + '/>' ;
246246 }
247- var xml = '' ;
247+ var xml = [ ] ;
248248 if ( name ) {
249- xml += '<' + elementName ;
249+ xml . push ( '<' + elementName ) ;
250250 if ( typeof element !== 'object' ) {
251- xml += '>' + writeText ( element , options ) + '</' + elementName + '>' ;
252- return xml ;
251+ xml . push ( '>' + writeText ( element , options ) + '</' + elementName + '>' ) ;
252+ return xml . join ( '' ) ;
253253 }
254254 if ( element [ options . attributesKey ] ) {
255- xml += writeAttributes ( element [ options . attributesKey ] , options , depth ) ;
255+ xml . push ( writeAttributes ( element [ options . attributesKey ] , options , depth ) ) ;
256256 }
257257 var withClosingTag = hasContentCompact ( element , options , true ) || element [ options . attributesKey ] && element [ options . attributesKey ] [ 'xml:space' ] === 'preserve' ;
258258 if ( ! withClosingTag ) {
@@ -263,58 +263,58 @@ function writeElementCompact(element, name, options, depth, indent) {
263263 }
264264 }
265265 if ( withClosingTag ) {
266- xml += '>' ;
266+ xml . push ( '>' ) ;
267267 } else {
268- xml += '/>' ;
269- return xml ;
268+ xml . push ( '/>' ) ;
269+ return xml . join ( '' ) ;
270270 }
271271 }
272- xml += writeElementsCompact ( element , options , depth + 1 , false ) ;
272+ xml . push ( writeElementsCompact ( element , options , depth + 1 , false ) ) ;
273273 currentElement = element ;
274274 currentElementName = name ;
275275 if ( name ) {
276- xml += ( indent ? writeIndentation ( options , depth , false ) : '' ) + '</' + elementName + '>' ;
276+ xml . push ( ( indent ? writeIndentation ( options , depth , false ) : '' ) + '</' + elementName + '>' ) ;
277277 }
278- return xml ;
278+ return xml . join ( '' ) ;
279279}
280280
281281function writeElementsCompact ( element , options , depth , firstLine ) {
282- var i , key , nodes , xml = '' ;
282+ var i , key , nodes , xml = [ ] ;
283283 for ( key in element ) {
284284 if ( element . hasOwnProperty ( key ) ) {
285285 nodes = isArray ( element [ key ] ) ? element [ key ] : [ element [ key ] ] ;
286286 for ( i = 0 ; i < nodes . length ; ++ i ) {
287287 switch ( key ) {
288- case options . declarationKey : xml += writeDeclaration ( nodes [ i ] , options , depth ) ; break ;
289- case options . instructionKey : xml += ( options . indentInstruction ? writeIndentation ( options , depth , firstLine ) : '' ) + writeInstruction ( nodes [ i ] , options , depth ) ; break ;
288+ case options . declarationKey : xml . push ( writeDeclaration ( nodes [ i ] , options , depth ) ) ; break ;
289+ case options . instructionKey : xml . push ( ( options . indentInstruction ? writeIndentation ( options , depth , firstLine ) : '' ) + writeInstruction ( nodes [ i ] , options , depth ) ) ; break ;
290290 case options . attributesKey : case options . parentKey : break ; // skip
291- case options . textKey : xml += ( options . indentText ? writeIndentation ( options , depth , firstLine ) : '' ) + writeText ( nodes [ i ] , options ) ; break ;
292- case options . cdataKey : xml += ( options . indentCdata ? writeIndentation ( options , depth , firstLine ) : '' ) + writeCdata ( nodes [ i ] , options ) ; break ;
293- case options . doctypeKey : xml += writeIndentation ( options , depth , firstLine ) + writeDoctype ( nodes [ i ] , options ) ; break ;
294- case options . commentKey : xml += writeIndentation ( options , depth , firstLine ) + writeComment ( nodes [ i ] , options ) ; break ;
295- default : xml += writeIndentation ( options , depth , firstLine ) + writeElementCompact ( nodes [ i ] , key , options , depth , hasContentCompact ( nodes [ i ] , options ) ) ;
291+ case options . textKey : xml . push ( ( options . indentText ? writeIndentation ( options , depth , firstLine ) : '' ) + writeText ( nodes [ i ] , options ) ) ; break ;
292+ case options . cdataKey : xml . push ( ( options . indentCdata ? writeIndentation ( options , depth , firstLine ) : '' ) + writeCdata ( nodes [ i ] , options ) ) ; break ;
293+ case options . doctypeKey : xml . push ( writeIndentation ( options , depth , firstLine ) + writeDoctype ( nodes [ i ] , options ) ) ; break ;
294+ case options . commentKey : xml . push ( writeIndentation ( options , depth , firstLine ) + writeComment ( nodes [ i ] , options ) ) ; break ;
295+ default : xml . push ( writeIndentation ( options , depth , firstLine ) + writeElementCompact ( nodes [ i ] , key , options , depth , hasContentCompact ( nodes [ i ] , options ) ) ) ;
296296 }
297- firstLine = firstLine && ! xml ;
297+ firstLine = firstLine && ! xml . length ;
298298 }
299299 }
300300 }
301- return xml ;
301+ return xml . join ( '' ) ;
302302}
303303
304304module . exports = function ( js , options ) {
305305 options = validateOptions ( options ) ;
306- var xml = '' ;
306+ var xml = [ ] ;
307307 currentElement = js ;
308308 currentElementName = '_root_' ;
309309 if ( options . compact ) {
310- xml = writeElementsCompact ( js , options , 0 , true ) ;
310+ xml . push ( writeElementsCompact ( js , options , 0 , true ) ) ;
311311 } else {
312312 if ( js [ options . declarationKey ] ) {
313- xml += writeDeclaration ( js [ options . declarationKey ] , options , 0 ) ;
313+ xml . push ( writeDeclaration ( js [ options . declarationKey ] , options , 0 ) ) ;
314314 }
315315 if ( js [ options . elementsKey ] && js [ options . elementsKey ] . length ) {
316- xml += writeElements ( js [ options . elementsKey ] , options , 0 , ! xml ) ;
316+ xml . push ( writeElements ( js [ options . elementsKey ] , options , 0 , ! xml . length ) ) ;
317317 }
318318 }
319- return xml ;
319+ return xml . join ( '' ) ;
320320} ;
0 commit comments