UNPKG

makestatic-parse-html

Version:

Parses HTML files to an abstract syntax tree

180 lines (161 loc) 4.26 kB
/** * Adapter for css-select so it ccan query the parse5 DOM tree. */ class DomAdapter { static isTag (elem) { return elem.tagName !== undefined } static getParent (elem) { return elem.parentNode } static getName (elem) { return elem.tagName } static getChildren (elem) { /* istanbul ignore next: guard against no child nodes */ return elem.childNodes || [] } static getText (elem, text = '') { const childs = DomAdapter.getChildren(elem) childs.forEach((node) => { if (DomAdapter.isTag(node)) { text += DomAdapter.getText(node, text) } else if (node.nodeName === '#text') { text += node.value } }) return text } static getSiblings (elem) { const parent = DomAdapter.getParent(elem) return parent && DomAdapter.getChildren(parent) } static existsOne (test, nodes) { let node for (let i = 0; i < nodes.length; i++) { node = nodes[i] if (DomAdapter.isTag(node) && (test(node) || DomAdapter.existsOne(test, DomAdapter.getChildren(node)))) { return true } } return false } static getAttributeValue (elem, name) { let attr /* istanbul ignore next: guard against no attributes */ let attrs = elem.attrs || [] for (let i = 0; i < attrs.length; i++) { attr = attrs[i] if (attr.name === name) { return attr.value } } } static hasAttrib (elem, name) { return DomAdapter.getAttributeValue(elem, name) !== undefined } static findOne (test, nodes) { let childs, elem for (let i = 0; i < nodes.length; i++) { if (!DomAdapter.isTag(nodes[i])) { continue } if (test(nodes[i])) { return nodes[i] } childs = DomAdapter.getChildren(nodes[i]) elem = DomAdapter.findAll(test, childs) if (elem.length) { return elem[0] } } } static findAll (test, nodes) { let result = [] let childs for (let i = 0; i < nodes.length; i++) { if (!DomAdapter.isTag(nodes[i])) { continue } if (test(nodes[i])) { result.push(nodes[i]) } childs = DomAdapter.getChildren(nodes[i]) result = result.concat(DomAdapter.findAll(test, childs)) } return result } /** * Utility to get an attribute from a node. * * Iterates the attribute list and gets the first attribute that has * the given name and optionally a specific value. * * Note this is an extension to the interface required by `css-select`. * * @static {function} getAttribute * @param {Object} el the node. * @param {String} name the attribute name. * @param {String} [value] the attribute value. * * @returns the attribute or undefined. */ static getAttribute (el, name, value) { const attrs = el.attrs if (!attrs) { return } let attr for (let i = 0; i < attrs.length; i++) { attr = attrs[i] if (attr.name === name) { if (value && attr.value === value) { return attr } else if (!value) { return attr } } } } static setAttributeValue (elem, name, value) { /* istanbul ignore next: guard against no attributes */ let attrs = elem.attrs || [] let attr = attrs.find((att) => { return att.name === name }) if (attr) { attr.value = value } else { attrs.push({name: name, value: value}) } } static createElement (tagName, attributes) { let attrs = [] for (let k in attributes) { attrs.push({name: k, value: attributes[k]}) } return { nodeName: tagName, tagName: tagName, attrs: attrs, namespaceURI: 'http://www.w3.org/1999/xhtml', childNodes: [] } } static createTextNode (data) { return {nodeName: '#text', value: data} } static prependChild (parent, elem) { // TODO: remove from existing element if parentNode elem.parentNode = parent parent.childNodes.unshift(elem) } static appendChild (parent, elem) { // TODO: remove from existing element if parentNode elem.parentNode = parent parent.childNodes.push(elem) } } module.exports = DomAdapter