diff options
Diffstat (limited to 'alarm/node_modules/parse5/lib/serializer/index.js')
-rw-r--r-- | alarm/node_modules/parse5/lib/serializer/index.js | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/alarm/node_modules/parse5/lib/serializer/index.js b/alarm/node_modules/parse5/lib/serializer/index.js new file mode 100644 index 0000000..659ef60 --- /dev/null +++ b/alarm/node_modules/parse5/lib/serializer/index.js @@ -0,0 +1,176 @@ +'use strict'; + +const defaultTreeAdapter = require('../tree-adapters/default'); +const mergeOptions = require('../utils/merge-options'); +const doctype = require('../common/doctype'); +const HTML = require('../common/html'); + +//Aliases +const $ = HTML.TAG_NAMES; +const NS = HTML.NAMESPACES; + +//Default serializer options +const DEFAULT_OPTIONS = { + treeAdapter: defaultTreeAdapter +}; + +//Escaping regexes +const AMP_REGEX = /&/g; +const NBSP_REGEX = /\u00a0/g; +const DOUBLE_QUOTE_REGEX = /"/g; +const LT_REGEX = /</g; +const GT_REGEX = />/g; + +//Serializer +class Serializer { + constructor(node, options) { + this.options = mergeOptions(DEFAULT_OPTIONS, options); + this.treeAdapter = this.options.treeAdapter; + + this.html = ''; + this.startNode = node; + } + + //API + serialize() { + this._serializeChildNodes(this.startNode); + + return this.html; + } + + //Internals + _serializeChildNodes(parentNode) { + const childNodes = this.treeAdapter.getChildNodes(parentNode); + + if (childNodes) { + for (let i = 0, cnLength = childNodes.length; i < cnLength; i++) { + const currentNode = childNodes[i]; + + if (this.treeAdapter.isElementNode(currentNode)) { + this._serializeElement(currentNode); + } else if (this.treeAdapter.isTextNode(currentNode)) { + this._serializeTextNode(currentNode); + } else if (this.treeAdapter.isCommentNode(currentNode)) { + this._serializeCommentNode(currentNode); + } else if (this.treeAdapter.isDocumentTypeNode(currentNode)) { + this._serializeDocumentTypeNode(currentNode); + } + } + } + } + + _serializeElement(node) { + const tn = this.treeAdapter.getTagName(node); + const ns = this.treeAdapter.getNamespaceURI(node); + + this.html += '<' + tn; + this._serializeAttributes(node); + this.html += '>'; + + if ( + tn !== $.AREA && + tn !== $.BASE && + tn !== $.BASEFONT && + tn !== $.BGSOUND && + tn !== $.BR && + tn !== $.COL && + tn !== $.EMBED && + tn !== $.FRAME && + tn !== $.HR && + tn !== $.IMG && + tn !== $.INPUT && + tn !== $.KEYGEN && + tn !== $.LINK && + tn !== $.META && + tn !== $.PARAM && + tn !== $.SOURCE && + tn !== $.TRACK && + tn !== $.WBR + ) { + const childNodesHolder = + tn === $.TEMPLATE && ns === NS.HTML ? this.treeAdapter.getTemplateContent(node) : node; + + this._serializeChildNodes(childNodesHolder); + this.html += '</' + tn + '>'; + } + } + + _serializeAttributes(node) { + const attrs = this.treeAdapter.getAttrList(node); + + for (let i = 0, attrsLength = attrs.length; i < attrsLength; i++) { + const attr = attrs[i]; + const value = Serializer.escapeString(attr.value, true); + + this.html += ' '; + + if (!attr.namespace) { + this.html += attr.name; + } else if (attr.namespace === NS.XML) { + this.html += 'xml:' + attr.name; + } else if (attr.namespace === NS.XMLNS) { + if (attr.name !== 'xmlns') { + this.html += 'xmlns:'; + } + + this.html += attr.name; + } else if (attr.namespace === NS.XLINK) { + this.html += 'xlink:' + attr.name; + } else { + this.html += attr.prefix + ':' + attr.name; + } + + this.html += '="' + value + '"'; + } + } + + _serializeTextNode(node) { + const content = this.treeAdapter.getTextNodeContent(node); + const parent = this.treeAdapter.getParentNode(node); + let parentTn = void 0; + + if (parent && this.treeAdapter.isElementNode(parent)) { + parentTn = this.treeAdapter.getTagName(parent); + } + + if ( + parentTn === $.STYLE || + parentTn === $.SCRIPT || + parentTn === $.XMP || + parentTn === $.IFRAME || + parentTn === $.NOEMBED || + parentTn === $.NOFRAMES || + parentTn === $.PLAINTEXT || + parentTn === $.NOSCRIPT + ) { + this.html += content; + } else { + this.html += Serializer.escapeString(content, false); + } + } + + _serializeCommentNode(node) { + this.html += '<!--' + this.treeAdapter.getCommentNodeContent(node) + '-->'; + } + + _serializeDocumentTypeNode(node) { + const name = this.treeAdapter.getDocumentTypeNodeName(node); + + this.html += '<' + doctype.serializeContent(name, null, null) + '>'; + } +} + +// NOTE: used in tests and by rewriting stream +Serializer.escapeString = function(str, attrMode) { + str = str.replace(AMP_REGEX, '&').replace(NBSP_REGEX, ' '); + + if (attrMode) { + str = str.replace(DOUBLE_QUOTE_REGEX, '"'); + } else { + str = str.replace(LT_REGEX, '<').replace(GT_REGEX, '>'); + } + + return str; +}; + +module.exports = Serializer; |