UNPKG

happy-dom

Version:

Happy DOM is a JavaScript implementation of a web browser without its graphical user interface. It includes many web standards from WHATWG DOM and HTML.

122 lines (108 loc) 3.18 kB
import Document from '../nodes/document/Document.js'; import * as PropertySymbol from '../PropertySymbol.js'; import XMLParser from '../xml-parser/XMLParser.js'; import DOMException from '../exception/DOMException.js'; import DocumentFragment from '../nodes/document-fragment/DocumentFragment.js'; import BrowserWindow from '../window/BrowserWindow.js'; import NodeTypeEnum from '../nodes/node/NodeTypeEnum.js'; /** * DOM parser. * * Reference: * https://developer.mozilla.org/en-US/docs/Web/API/DOMParser. */ export default class DOMParser { readonly #window: BrowserWindow; /** * Constructor. * * @param window Window. */ constructor(window: BrowserWindow) { this.#window = window; } /** * Parses HTML and returns a root element. * * @param string HTML data. * @param mimeType Mime type. * @returns Root element. */ public parseFromString(string: string, mimeType: string): Document { if (!mimeType) { throw new DOMException('Second parameter "mimeType" is mandatory.'); } const newDocument = <Document>this.#createDocument(mimeType); newDocument[PropertySymbol.childNodes].length = 0; newDocument[PropertySymbol.children].length = 0; const root = <DocumentFragment>XMLParser.parse(newDocument, string, { evaluateScripts: true }); let documentElement = null; let documentTypeNode = null; for (const node of root[PropertySymbol.childNodes]) { if (node['tagName'] === 'HTML') { documentElement = node; } else if (node[PropertySymbol.nodeType] === NodeTypeEnum.documentTypeNode) { documentTypeNode = node; } if (documentElement && documentTypeNode) { break; } } if (documentElement) { if (documentTypeNode) { newDocument.appendChild(documentTypeNode); } newDocument.appendChild(documentElement); const body = newDocument.body; if (body) { for (const child of root[PropertySymbol.childNodes].slice()) { body.appendChild(child); } } } else { switch (mimeType) { case 'image/svg+xml': { for (const node of root[PropertySymbol.childNodes].slice()) { newDocument.appendChild(node); } } break; case 'text/html': default: { const documentElement = newDocument.createElement('html'); const bodyElement = newDocument.createElement('body'); const headElement = newDocument.createElement('head'); documentElement.appendChild(headElement); documentElement.appendChild(bodyElement); newDocument.appendChild(documentElement); for (const node of root[PropertySymbol.childNodes].slice()) { bodyElement.appendChild(node); } } break; } } return newDocument; } /** * * @param mimeType Mime type. * @returns Document. */ #createDocument(mimeType: string): Document { switch (mimeType) { case 'text/html': return new this.#window.HTMLDocument(); case 'image/svg+xml': return new this.#window.SVGDocument(); case 'text/xml': case 'application/xml': case 'application/xhtml+xml': return new this.#window.XMLDocument(); default: throw new DOMException(`Unknown mime type "${mimeType}".`); } } }