"use strict"; var runtimeHtmlHelpers = require("marko/runtime/html/helpers"); var escapeXml = runtimeHtmlHelpers.x; var escapeXmlAttr = runtimeHtmlHelpers.xa; var escapeScript = runtimeHtmlHelpers.xs; var escapeStyle = runtimeHtmlHelpers.xc; var openTagOnly = {}; [ "base", "br", "col", "hr", "embed", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr", ].forEach(function (tagName) { openTagOnly[tagName] = true; }); function getNodeValue(node) { return node.___nodeValue || node.nodeValue; } function getFirstChild(node) { return node.___firstChild || node.firstChild; } function getNextSibling(node) { return node.___nextSibling || node.nextSibling; } function vdomToHTML(node, options) { // NOTE: We don't use XMLSerializer because we need to sort the attributes to correctly compare output HTML strings // BAD: return (new XMLSerializer()).serializeToString(node); var html = ""; function serializeHelper(node) { var nodeType = node.nodeType || node.___nodeType; if (nodeType === 1) { serializeElHelper(node); } else if (nodeType === 3) { serializeTextHelper(node); } else if (nodeType === 8) { serializeCommentHelper(node); } else { html += `INVALID NODE TYPE ${nodeType}\n`; } } function serializeElHelper(el) { var tagName = el.nodeName; html += "<" + tagName; var attributes = el.attributes; var attributesArray = []; var attrName; if (typeof attributes.length === "number") { for (var i = 0; i < attributes.length; i++) { var attr = attributes[i]; attrName = attr.name; if (attrName === "data-marko-const") { continue; } attributesArray.push( " " + attrName + '="' + escapeXmlAttr(attr.value) + '"', ); } } else { for (attrName in attributes) { if (attrName === "data-marko-const") { continue; } var attrValue = attributes[attrName]; if (typeof attrValue !== "string") { if (attrValue === true) { attrValue = ""; } else if (!attrValue) { continue; } } if (attrName === "xlink:href") { attrName = "http://www.w3.org/1999/xlink:href"; } attributesArray.push( " " + attrName + '="' + escapeXmlAttr(attrValue) + '"', ); } } attributesArray.sort(); html += attributesArray.join(""); html += ">"; var hasEndTag = true; if (tagName.toUpperCase() === "TEXTAREA") { html += el.value; } else { var curChild = getFirstChild(el); if (curChild) { while (curChild) { let nodeType = curChild.nodeType || curChild.___nodeType; if (nodeType === 3) { let tag = tagName.toUpperCase(); let escapeText = tag === "SCRIPT" ? escapeScript : tag === "STYLE" ? escapeStyle : escapeXml; serializeTextHelper(curChild, escapeText); } else { serializeHelper(curChild); } curChild = getNextSibling(curChild); } } else if (openTagOnly[tagName.toLowerCase()]) { hasEndTag = false; } } if (hasEndTag) { html += ""; } } function serializeTextHelper(node, escape) { escape = escape || escapeXml; html += escape(getNodeValue(node)); } function serializeCommentHelper(node) { html += ""; } let nodeType = node.nodeType || node.___nodeType; if ( nodeType === 11 /* DocumentFragment */ || (options && options.childrenOnly) ) { var curChild = getFirstChild(node); while (curChild) { serializeHelper(curChild); curChild = getNextSibling(curChild); } } else { serializeHelper(node); } return html; } module.exports = vdomToHTML;