UNPKG

html-dom-parser

Version:
1 lines 7.9 kB
{"version":3,"file":"domparser.mjs","names":[],"sources":["../../src/client/domparser.ts"],"sourcesContent":["import type { TrustedTypePolicy } from '../types';\nimport { escapeSpecialCharacters, hasOpenTag } from './utilities';\n\n// constants\nconst HTML = 'html';\nconst HEAD = 'head';\nconst BODY = 'body';\nconst FIRST_TAG_REGEX = /<([a-zA-Z]+[0-9]?)/; // e.g., <h1>\n\nexport function getHTMLForInnerHTML(\n html: string,\n trustedTypePolicy?: TrustedTypePolicy,\n) {\n return trustedTypePolicy ? trustedTypePolicy.createHTML(html) : html;\n}\n\n// falls back to `parseFromString` if `createHTMLDocument` cannot be used\n/* eslint-disable @typescript-eslint/no-unused-vars */\n/* v8 ignore start */\nlet parseFromDocument = (\n html: string,\n tagName?: string,\n trustedTypePolicy?: TrustedTypePolicy,\n): Document => {\n throw new Error(\n 'This browser does not support `document.implementation.createHTMLDocument`',\n );\n};\n\nlet parseFromString = (\n html: string,\n tagName?: string,\n trustedTypePolicy?: TrustedTypePolicy,\n): Document => {\n void trustedTypePolicy;\n throw new Error(\n 'This browser does not support `DOMParser.prototype.parseFromString`',\n );\n};\n\nconst DOMParser = typeof window === 'object' && window.DOMParser;\n\n/**\n * DOMParser (performance: slow).\n *\n * @see https://developer.mozilla.org/docs/Web/API/DOMParser#Parsing_an_SVG_or_HTML_document\n */\nif (typeof DOMParser === 'function') {\n const domParser = new DOMParser();\n const mimeType = 'text/html';\n\n /**\n * Creates an HTML document using `DOMParser.parseFromString`.\n *\n * @param html - The HTML string.\n * @param tagName - The element to render the HTML (with 'body' as fallback).\n * @returns - Document.\n */\n parseFromString = (\n html: string,\n tagName?: string,\n trustedTypePolicy?: TrustedTypePolicy,\n ): Document => {\n void trustedTypePolicy;\n if (tagName) {\n html = `<${tagName}>${html}</${tagName}>`;\n }\n\n return domParser.parseFromString(html, mimeType);\n };\n\n parseFromDocument = parseFromString;\n}\n\n/**\n * DOMImplementation (performance: fair).\n *\n * @see https://developer.mozilla.org/docs/Web/API/DOMImplementation/createHTMLDocument\n */\n// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\nif (typeof document === 'object' && document.implementation) {\n const htmlDocument = document.implementation.createHTMLDocument();\n\n /**\n * Use HTML document created by `document.implementation.createHTMLDocument`.\n *\n * @param html - The HTML string.\n * @param tagName - The element to render the HTML (with 'body' as fallback).\n * @returns - Document\n */\n parseFromDocument = function (\n html: string,\n tagName?: string,\n trustedTypePolicy?: TrustedTypePolicy,\n ): Document {\n if (tagName) {\n const element = htmlDocument.documentElement.querySelector(tagName);\n\n if (element) {\n element.innerHTML = getHTMLForInnerHTML(\n html,\n trustedTypePolicy,\n ) as string;\n }\n\n return htmlDocument;\n }\n\n htmlDocument.documentElement.innerHTML = getHTMLForInnerHTML(\n html,\n trustedTypePolicy,\n ) as string;\n return htmlDocument;\n };\n}\n\n/**\n * Template (performance: fast).\n *\n * @see https://developer.mozilla.org/docs/Web/HTML/Element/template\n */\nconst template =\n typeof document === 'object' && document.createElement('template');\n\nlet parseFromTemplate: (\n html: string,\n trustedTypePolicy?: TrustedTypePolicy,\n) => NodeList;\n\n// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\nif (template && template.content) {\n /**\n * Uses a template element (content fragment) to parse HTML.\n *\n * @param html - HTML string.\n * @returns - Nodes.\n */\n parseFromTemplate = (\n html: string,\n trustedTypePolicy?: TrustedTypePolicy,\n ): NodeList => {\n template.innerHTML = getHTMLForInnerHTML(html, trustedTypePolicy) as string;\n return template.content.childNodes;\n };\n}\n\nconst createNodeList = () => document.createDocumentFragment().childNodes;\n/* v8 ignore stop */\n\n/**\n * Parses HTML string to DOM nodes.\n *\n * @param html - HTML markup.\n * @param trustedTypePolicy - Trusted Types policy.\n * @returns - DOM nodes.\n */\nexport default function domparser(\n html: string,\n trustedTypePolicy?: TrustedTypePolicy,\n): NodeList {\n // Escape special characters before parsing\n html = escapeSpecialCharacters(html);\n\n const match = FIRST_TAG_REGEX.exec(html);\n const firstTagName = match?.[1]?.toLowerCase();\n\n switch (firstTagName) {\n case HTML: {\n const doc = parseFromString(html);\n\n // the created document may come with filler head/body elements,\n // so make sure to remove them if they don't actually exist\n if (!hasOpenTag(html, HEAD)) {\n const element = doc.querySelector(HEAD);\n element?.parentNode?.removeChild(element);\n }\n\n if (!hasOpenTag(html, BODY)) {\n const element = doc.querySelector(BODY);\n element?.parentNode?.removeChild(element);\n }\n\n return doc.querySelectorAll(HTML);\n }\n\n case HEAD:\n case BODY: {\n const elements = parseFromDocument(\n html,\n undefined,\n trustedTypePolicy,\n ).querySelectorAll(firstTagName);\n\n // if there's a sibling element, then return both elements\n /* v8 ignore next */\n if (hasOpenTag(html, BODY) && hasOpenTag(html, HEAD)) {\n return elements[0].parentNode?.childNodes ?? createNodeList();\n }\n\n return elements;\n }\n\n // low-level tag or text\n /* v8 ignore start */\n default: {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (parseFromTemplate) {\n return parseFromTemplate(html, trustedTypePolicy);\n }\n\n const element = parseFromDocument(\n html,\n BODY,\n trustedTypePolicy,\n ).querySelector(BODY);\n\n return element?.childNodes ?? createNodeList();\n }\n /* v8 ignore stop */\n }\n}\n"],"mappings":";;AAIA,MAAM,OAAO;AACb,MAAM,OAAO;AACb,MAAM,OAAO;AACb,MAAM,kBAAkB;AAExB,SAAgB,oBACd,MACA,mBACA;CACA,OAAO,oBAAoB,kBAAkB,WAAW,IAAI,IAAI;AAClE;;AAKA,IAAI,qBACF,MACA,SACA,sBACa;CACb,MAAM,IAAI,MACR,4EACF;AACF;AAEA,IAAI,mBACF,MACA,SACA,sBACa;CAEb,MAAM,IAAI,MACR,qEACF;AACF;AAEA,MAAM,YAAY,OAAO,WAAW,YAAY,OAAO;;;;;;AAOvD,IAAI,OAAO,cAAc,YAAY;CACnC,MAAM,YAAY,IAAI,UAAU;CAChC,MAAM,WAAW;;;;;;;;CASjB,mBACE,MACA,SACA,sBACa;EAEb,IAAI,SACF,OAAO,IAAI,QAAQ,GAAG,KAAK,IAAI,QAAQ;EAGzC,OAAO,UAAU,gBAAgB,MAAM,QAAQ;CACjD;CAEA,oBAAoB;AACtB;;;;;;AAQA,IAAI,OAAO,aAAa,YAAY,SAAS,gBAAgB;CAC3D,MAAM,eAAe,SAAS,eAAe,mBAAmB;;;;;;;;CAShE,oBAAoB,SAClB,MACA,SACA,mBACU;EACV,IAAI,SAAS;GACX,MAAM,UAAU,aAAa,gBAAgB,cAAc,OAAO;GAElE,IAAI,SACF,QAAQ,YAAY,oBAClB,MACA,iBACF;GAGF,OAAO;EACT;EAEA,aAAa,gBAAgB,YAAY,oBACvC,MACA,iBACF;EACA,OAAO;CACT;AACF;;;;;;AAOA,MAAM,WACJ,OAAO,aAAa,YAAY,SAAS,cAAc,UAAU;AAEnE,IAAI;AAMJ,IAAI,YAAY,SAAS;;;;;;;AAOvB,qBACE,MACA,sBACa;CACb,SAAS,YAAY,oBAAoB,MAAM,iBAAiB;CAChE,OAAO,SAAS,QAAQ;AAC1B;AAGF,MAAM,uBAAuB,SAAS,uBAAuB,EAAE;;;;;;;;;AAU/D,SAAwB,UACtB,MACA,mBACU;CAEV,OAAO,wBAAwB,IAAI;CAGnC,MAAM,eADQ,gBAAgB,KAAK,IACV,IAAI,IAAI,YAAY;CAE7C,QAAQ,cAAR;EACE,KAAK,MAAM;GACT,MAAM,MAAM,gBAAgB,IAAI;GAIhC,IAAI,CAAC,WAAW,MAAM,IAAI,GAAG;IAC3B,MAAM,UAAU,IAAI,cAAc,IAAI;IACtC,SAAS,YAAY,YAAY,OAAO;GAC1C;GAEA,IAAI,CAAC,WAAW,MAAM,IAAI,GAAG;IAC3B,MAAM,UAAU,IAAI,cAAc,IAAI;IACtC,SAAS,YAAY,YAAY,OAAO;GAC1C;GAEA,OAAO,IAAI,iBAAiB,IAAI;EAClC;EAEA,KAAK;EACL,KAAK,MAAM;GACT,MAAM,WAAW,kBACf,MACA,KAAA,GACA,iBACF,EAAE,iBAAiB,YAAY;;GAI/B,IAAI,WAAW,MAAM,IAAI,KAAK,WAAW,MAAM,IAAI,GACjD,OAAO,SAAS,GAAG,YAAY,cAAc,eAAe;GAG9D,OAAO;EACT;;EAIA;GAEE,IAAI,mBACF,OAAO,kBAAkB,MAAM,iBAAiB;GASlD,OANgB,kBACd,MACA,MACA,iBACF,EAAE,cAAc,IAEH,GAAG,cAAc,eAAe;CAGjD;AACF"}