| /* | 
|   Module dependencies | 
| */ | 
| var ElementType = require('domelementtype'); | 
| var entities = require('entities'); | 
|   | 
| /* mixed-case SVG and MathML tags & attributes | 
|    recognized by the HTML parser, see | 
|    https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inforeign | 
| */ | 
| var foreignNames = require('./foreignNames.json'); | 
| foreignNames.elementNames.__proto__ = null; /* use as a simple dictionary */ | 
| foreignNames.attributeNames.__proto__ = null; | 
|   | 
| var unencodedElements = { | 
|   __proto__: null, | 
|   style: true, | 
|   script: true, | 
|   xmp: true, | 
|   iframe: true, | 
|   noembed: true, | 
|   noframes: true, | 
|   plaintext: true, | 
|   noscript: true | 
| }; | 
|   | 
| /* | 
|   Format attributes | 
| */ | 
| function formatAttrs(attributes, opts) { | 
|   if (!attributes) return; | 
|   | 
|   var output = ''; | 
|   var value; | 
|   | 
|   // Loop through the attributes | 
|   for (var key in attributes) { | 
|     value = attributes[key]; | 
|     if (output) { | 
|       output += ' '; | 
|     } | 
|   | 
|     if (opts.xmlMode === 'foreign') { | 
|       /* fix up mixed-case attribute names */ | 
|       key = foreignNames.attributeNames[key] || key; | 
|     } | 
|     output += key; | 
|     if ((value !== null && value !== '') || opts.xmlMode) { | 
|       output += | 
|         '="' + | 
|         (opts.decodeEntities | 
|           ? entities.encodeXML(value) | 
|           : value.replace(/\"/g, '"')) + | 
|         '"'; | 
|     } | 
|   } | 
|   | 
|   return output; | 
| } | 
|   | 
| /* | 
|   Self-enclosing tags (stolen from node-htmlparser) | 
| */ | 
| var singleTag = { | 
|   __proto__: null, | 
|   area: true, | 
|   base: true, | 
|   basefont: true, | 
|   br: true, | 
|   col: true, | 
|   command: true, | 
|   embed: true, | 
|   frame: true, | 
|   hr: true, | 
|   img: true, | 
|   input: true, | 
|   isindex: true, | 
|   keygen: true, | 
|   link: true, | 
|   meta: true, | 
|   param: true, | 
|   source: true, | 
|   track: true, | 
|   wbr: true | 
| }; | 
|   | 
| var render = (module.exports = function(dom, opts) { | 
|   if (!Array.isArray(dom) && !dom.cheerio) dom = [dom]; | 
|   opts = opts || {}; | 
|   | 
|   var output = ''; | 
|   | 
|   for (var i = 0; i < dom.length; i++) { | 
|     var elem = dom[i]; | 
|   | 
|     if (elem.type === 'root') output += render(elem.children, opts); | 
|     else if (ElementType.isTag(elem)) output += renderTag(elem, opts); | 
|     else if (elem.type === ElementType.Directive) | 
|       output += renderDirective(elem); | 
|     else if (elem.type === ElementType.Comment) output += renderComment(elem); | 
|     else if (elem.type === ElementType.CDATA) output += renderCdata(elem); | 
|     else output += renderText(elem, opts); | 
|   } | 
|   | 
|   return output; | 
| }); | 
|   | 
| var foreignModeIntegrationPoints = [ | 
|   'mi', | 
|   'mo', | 
|   'mn', | 
|   'ms', | 
|   'mtext', | 
|   'annotation-xml', | 
|   'foreignObject', | 
|   'desc', | 
|   'title' | 
| ]; | 
|   | 
| function renderTag(elem, opts) { | 
|   // Handle SVG / MathML in HTML | 
|   if (opts.xmlMode === 'foreign') { | 
|     /* fix up mixed-case element names */ | 
|     elem.name = foreignNames.elementNames[elem.name] || elem.name; | 
|     /* exit foreign mode at integration points */ | 
|     if ( | 
|       elem.parent && | 
|       foreignModeIntegrationPoints.indexOf(elem.parent.name) >= 0 | 
|     ) | 
|       opts = Object.assign({}, opts, { xmlMode: false }); | 
|   } | 
|   if (!opts.xmlMode && ['svg', 'math'].indexOf(elem.name) >= 0) { | 
|     opts = Object.assign({}, opts, { xmlMode: 'foreign' }); | 
|   } | 
|   | 
|   var tag = '<' + elem.name; | 
|   var attribs = formatAttrs(elem.attribs, opts); | 
|   | 
|   if (attribs) { | 
|     tag += ' ' + attribs; | 
|   } | 
|   | 
|   if (opts.xmlMode && (!elem.children || elem.children.length === 0)) { | 
|     tag += '/>'; | 
|   } else { | 
|     tag += '>'; | 
|     if (elem.children) { | 
|       tag += render(elem.children, opts); | 
|     } | 
|   | 
|     if (!singleTag[elem.name] || opts.xmlMode) { | 
|       tag += '</' + elem.name + '>'; | 
|     } | 
|   } | 
|   | 
|   return tag; | 
| } | 
|   | 
| function renderDirective(elem) { | 
|   return '<' + elem.data + '>'; | 
| } | 
|   | 
| function renderText(elem, opts) { | 
|   var data = elem.data || ''; | 
|   | 
|   // if entities weren't decoded, no need to encode them back | 
|   if ( | 
|     opts.decodeEntities && | 
|     !(elem.parent && elem.parent.name in unencodedElements) | 
|   ) { | 
|     data = entities.encodeXML(data); | 
|   } | 
|   | 
|   return data; | 
| } | 
|   | 
| function renderCdata(elem) { | 
|   return '<![CDATA[' + elem.children[0].data + ']]>'; | 
| } | 
|   | 
| function renderComment(elem) { | 
|   return '<!--' + elem.data + '-->'; | 
| } |