| import { html } from 'parse5'; |
| import { Element, Document, ProcessingInstruction, Comment, Text, isDirective, isText, isComment, isTag, } from 'domhandler'; |
| function enquoteDoctypeId(id) { |
| const quote = id.includes('"') ? "'" : '"'; |
| return quote + id + quote; |
| } |
| /** @internal */ |
| export function serializeDoctypeContent(name, publicId, systemId) { |
| let str = '!DOCTYPE '; |
| if (name) { |
| str += name; |
| } |
| if (publicId) { |
| str += ` PUBLIC ${enquoteDoctypeId(publicId)}`; |
| } |
| else if (systemId) { |
| str += ' SYSTEM'; |
| } |
| if (systemId) { |
| str += ` ${enquoteDoctypeId(systemId)}`; |
| } |
| return str; |
| } |
| export const adapter = { |
| // Re-exports from domhandler |
| isCommentNode: isComment, |
| isElementNode: isTag, |
| isTextNode: isText, |
| //Node construction |
| createDocument() { |
| const node = new Document([]); |
| node['x-mode'] = html.DOCUMENT_MODE.NO_QUIRKS; |
| return node; |
| }, |
| createDocumentFragment() { |
| return new Document([]); |
| }, |
| createElement(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; |
| } |
| const node = new Element(tagName, attribs, []); |
| node.namespace = namespaceURI; |
| node['x-attribsNamespace'] = attribsNamespace; |
| node['x-attribsPrefix'] = attribsPrefix; |
| return node; |
| }, |
| createCommentNode(data) { |
| return new Comment(data); |
| }, |
| createTextNode(value) { |
| return new Text(value); |
| }, |
| //Tree mutation |
| appendChild(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; |
| }, |
| insertBefore(parentNode, newNode, referenceNode) { |
| const insertionIdx = parentNode.children.indexOf(referenceNode); |
| const { prev } = referenceNode; |
| if (prev) { |
| prev.next = newNode; |
| newNode.prev = prev; |
| } |
| referenceNode.prev = newNode; |
| newNode.next = referenceNode; |
| parentNode.children.splice(insertionIdx, 0, newNode); |
| newNode.parent = parentNode; |
| }, |
| setTemplateContent(templateElement, contentElement) { |
| adapter.appendChild(templateElement, contentElement); |
| }, |
| getTemplateContent(templateElement) { |
| return templateElement.children[0]; |
| }, |
| setDocumentType(document, name, publicId, systemId) { |
| const data = serializeDoctypeContent(name, publicId, systemId); |
| let doctypeNode = document.children.find((node) => isDirective(node) && node.name === '!doctype'); |
| if (doctypeNode) { |
| doctypeNode.data = data !== null && data !== void 0 ? data : null; |
| } |
| else { |
| doctypeNode = new ProcessingInstruction('!doctype', data); |
| adapter.appendChild(document, doctypeNode); |
| } |
| doctypeNode['x-name'] = name; |
| doctypeNode['x-publicId'] = publicId; |
| doctypeNode['x-systemId'] = systemId; |
| }, |
| setDocumentMode(document, mode) { |
| document['x-mode'] = mode; |
| }, |
| getDocumentMode(document) { |
| return document['x-mode']; |
| }, |
| detachNode(node) { |
| if (node.parent) { |
| const idx = node.parent.children.indexOf(node); |
| const { prev, next } = node; |
| 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; |
| } |
| }, |
| insertText(parentNode, text) { |
| const lastChild = parentNode.children[parentNode.children.length - 1]; |
| if (lastChild && isText(lastChild)) { |
| lastChild.data += text; |
| } |
| else { |
| adapter.appendChild(parentNode, adapter.createTextNode(text)); |
| } |
| }, |
| insertTextBefore(parentNode, text, referenceNode) { |
| const prevNode = parentNode.children[parentNode.children.indexOf(referenceNode) - 1]; |
| if (prevNode && isText(prevNode)) { |
| prevNode.data += text; |
| } |
| else { |
| adapter.insertBefore(parentNode, adapter.createTextNode(text), referenceNode); |
| } |
| }, |
| adoptAttributes(recipient, attrs) { |
| for (let i = 0; i < attrs.length; i++) { |
| const attrName = attrs[i].name; |
| if (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 traversing |
| getFirstChild(node) { |
| return node.children[0]; |
| }, |
| getChildNodes(node) { |
| return node.children; |
| }, |
| getParentNode(node) { |
| return node.parent; |
| }, |
| getAttrList(element) { |
| return element.attributes; |
| }, |
| //Node data |
| getTagName(element) { |
| return element.name; |
| }, |
| getNamespaceURI(element) { |
| return element.namespace; |
| }, |
| getTextNodeContent(textNode) { |
| return textNode.data; |
| }, |
| getCommentNodeContent(commentNode) { |
| return commentNode.data; |
| }, |
| getDocumentTypeNodeName(doctypeNode) { |
| var _a; |
| return (_a = doctypeNode['x-name']) !== null && _a !== void 0 ? _a : ''; |
| }, |
| getDocumentTypeNodePublicId(doctypeNode) { |
| var _a; |
| return (_a = doctypeNode['x-publicId']) !== null && _a !== void 0 ? _a : ''; |
| }, |
| getDocumentTypeNodeSystemId(doctypeNode) { |
| var _a; |
| return (_a = doctypeNode['x-systemId']) !== null && _a !== void 0 ? _a : ''; |
| }, |
| //Node types |
| isDocumentTypeNode(node) { |
| return isDirective(node) && node.name === '!doctype'; |
| }, |
| // Source code location |
| setNodeSourceCodeLocation(node, location) { |
| if (location) { |
| node.startIndex = location.startOffset; |
| node.endIndex = location.endOffset; |
| } |
| node.sourceCodeLocation = location; |
| }, |
| getNodeSourceCodeLocation(node) { |
| return node.sourceCodeLocation; |
| }, |
| updateNodeSourceCodeLocation(node, endLocation) { |
| if (endLocation.endOffset != null) |
| node.endIndex = endLocation.endOffset; |
| node.sourceCodeLocation = { |
| ...node.sourceCodeLocation, |
| ...endLocation, |
| }; |
| }, |
| }; |