| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348 | 'use strict';const doctype = require('parse5/lib/common/doctype');const { DOCUMENT_MODE } = require('parse5/lib/common/html');//Conversion tables for DOM Level1 structure emulationconst nodeTypes = {    element: 1,    text: 3,    cdata: 4,    comment: 8};const nodePropertyShorthands = {    tagName: 'name',    childNodes: 'children',    parentNode: 'parent',    previousSibling: 'prev',    nextSibling: 'next',    nodeValue: 'data'};//Nodeclass Node {    constructor(props) {        for (const key of Object.keys(props)) {            this[key] = props[key];        }    }    get firstChild() {        const children = this.children;        return (children && children[0]) || null;    }    get lastChild() {        const children = this.children;        return (children && children[children.length - 1]) || null;    }    get nodeType() {        return nodeTypes[this.type] || nodeTypes.element;    }}Object.keys(nodePropertyShorthands).forEach(key => {    const shorthand = nodePropertyShorthands[key];    Object.defineProperty(Node.prototype, key, {        get: function() {            return this[shorthand] || null;        },        set: function(val) {            this[shorthand] = val;            return val;        }    });});//Node constructionexports.createDocument = function() {    return new Node({        type: 'root',        name: 'root',        parent: null,        prev: null,        next: null,        children: [],        'x-mode': DOCUMENT_MODE.NO_QUIRKS    });};exports.createDocumentFragment = function() {    return new Node({        type: 'root',        name: 'root',        parent: null,        prev: null,        next: null,        children: []    });};exports.createElement = function(tagName, namespaceURI, attrs) {    const attribs = Object.create(null);    const attribsNamespace = Object.create(null);    const attribsPrefix = Object.create(null);    for (let i = 0; i < attrs.length; i++) {        const attrName = attrs[i].name;        attribs[attrName] = attrs[i].value;        attribsNamespace[attrName] = attrs[i].namespace;        attribsPrefix[attrName] = attrs[i].prefix;    }    return new Node({        type: tagName === 'script' || tagName === 'style' ? tagName : 'tag',        name: tagName,        namespace: namespaceURI,        attribs: attribs,        'x-attribsNamespace': attribsNamespace,        'x-attribsPrefix': attribsPrefix,        children: [],        parent: null,        prev: null,        next: null    });};exports.createCommentNode = function(data) {    return new Node({        type: 'comment',        data: data,        parent: null,        prev: null,        next: null    });};const createTextNode = function(value) {    return new Node({        type: 'text',        data: value,        parent: null,        prev: null,        next: null    });};//Tree mutationconst appendChild = (exports.appendChild = function(parentNode, newNode) {    const prev = parentNode.children[parentNode.children.length - 1];    if (prev) {        prev.next = newNode;        newNode.prev = prev;    }    parentNode.children.push(newNode);    newNode.parent = parentNode;});const insertBefore = (exports.insertBefore = function(parentNode, newNode, referenceNode) {    const insertionIdx = parentNode.children.indexOf(referenceNode);    const prev = referenceNode.prev;    if (prev) {        prev.next = newNode;        newNode.prev = prev;    }    referenceNode.prev = newNode;    newNode.next = referenceNode;    parentNode.children.splice(insertionIdx, 0, newNode);    newNode.parent = parentNode;});exports.setTemplateContent = function(templateElement, contentElement) {    appendChild(templateElement, contentElement);};exports.getTemplateContent = function(templateElement) {    return templateElement.children[0];};exports.setDocumentType = function(document, name, publicId, systemId) {    const data = doctype.serializeContent(name, publicId, systemId);    let doctypeNode = null;    for (let i = 0; i < document.children.length; i++) {        if (document.children[i].type === 'directive' && document.children[i].name === '!doctype') {            doctypeNode = document.children[i];            break;        }    }    if (doctypeNode) {        doctypeNode.data = data;        doctypeNode['x-name'] = name;        doctypeNode['x-publicId'] = publicId;        doctypeNode['x-systemId'] = systemId;    } else {        appendChild(            document,            new Node({                type: 'directive',                name: '!doctype',                data: data,                'x-name': name,                'x-publicId': publicId,                'x-systemId': systemId            })        );    }};exports.setDocumentMode = function(document, mode) {    document['x-mode'] = mode;};exports.getDocumentMode = function(document) {    return document['x-mode'];};exports.detachNode = function(node) {    if (node.parent) {        const idx = node.parent.children.indexOf(node);        const prev = node.prev;        const next = node.next;        node.prev = null;        node.next = null;        if (prev) {            prev.next = next;        }        if (next) {            next.prev = prev;        }        node.parent.children.splice(idx, 1);        node.parent = null;    }};exports.insertText = function(parentNode, text) {    const lastChild = parentNode.children[parentNode.children.length - 1];    if (lastChild && lastChild.type === 'text') {        lastChild.data += text;    } else {        appendChild(parentNode, createTextNode(text));    }};exports.insertTextBefore = function(parentNode, text, referenceNode) {    const prevNode = parentNode.children[parentNode.children.indexOf(referenceNode) - 1];    if (prevNode && prevNode.type === 'text') {        prevNode.data += text;    } else {        insertBefore(parentNode, createTextNode(text), referenceNode);    }};exports.adoptAttributes = function(recipient, attrs) {    for (let i = 0; i < attrs.length; i++) {        const attrName = attrs[i].name;        if (typeof recipient.attribs[attrName] === 'undefined') {            recipient.attribs[attrName] = attrs[i].value;            recipient['x-attribsNamespace'][attrName] = attrs[i].namespace;            recipient['x-attribsPrefix'][attrName] = attrs[i].prefix;        }    }};//Tree traversingexports.getFirstChild = function(node) {    return node.children[0];};exports.getChildNodes = function(node) {    return node.children;};exports.getParentNode = function(node) {    return node.parent;};exports.getAttrList = function(element) {    const attrList = [];    for (const name in element.attribs) {        attrList.push({            name: name,            value: element.attribs[name],            namespace: element['x-attribsNamespace'][name],            prefix: element['x-attribsPrefix'][name]        });    }    return attrList;};//Node dataexports.getTagName = function(element) {    return element.name;};exports.getNamespaceURI = function(element) {    return element.namespace;};exports.getTextNodeContent = function(textNode) {    return textNode.data;};exports.getCommentNodeContent = function(commentNode) {    return commentNode.data;};exports.getDocumentTypeNodeName = function(doctypeNode) {    return doctypeNode['x-name'];};exports.getDocumentTypeNodePublicId = function(doctypeNode) {    return doctypeNode['x-publicId'];};exports.getDocumentTypeNodeSystemId = function(doctypeNode) {    return doctypeNode['x-systemId'];};//Node typesexports.isTextNode = function(node) {    return node.type === 'text';};exports.isCommentNode = function(node) {    return node.type === 'comment';};exports.isDocumentTypeNode = function(node) {    return node.type === 'directive' && node.name === '!doctype';};exports.isElementNode = function(node) {    return !!node.attribs;};// Source code locationexports.setNodeSourceCodeLocation = function(node, location) {    node.sourceCodeLocation = location;};exports.getNodeSourceCodeLocation = function(node) {    return node.sourceCodeLocation;};exports.updateNodeSourceCodeLocation = function(node, endLocation) {    node.sourceCodeLocation = Object.assign(node.sourceCodeLocation, endLocation);};
 |