@thednp/domparser
Version:
🍝 Super light HTML parser for isomorphic applications.
1 lines • 29.9 kB
Source Map (JSON)
{"version":3,"file":"prototype-eKhltkqB.cjs","names":["parts: SelectorPart[]","startsWith","toLowerCase","isTag","selfClosingTags","trim","isNode","ALL: ChildElementList","CHILDREN: ChildElementList","CHILDNODES: ChildNodeList","DOM_ERROR","isRoot","node","toUpperCase","isPrimitive","tokenize","childNodes: ChildNodeList","isObj"],"sources":["../src/parts/selectors.ts","../src/parts/prototype.ts"],"sourcesContent":["// selectors.ts\nimport { startsWith, toLowerCase } from \"./util\";\nimport type { DOMNode, MatchFunction, SelectorPart } from \"./types\";\n\n/**\n * Create a selector cache to help improve `match` based queries\n * (matches, querySelector, querySelectorAll).\n */\nclass SelectorCacheMap extends Map<string, MatchFunction> {\n private hits = 0;\n private misses = 0;\n\n constructor() {\n super();\n this.misses = 0;\n this.hits = 0;\n }\n hit() {\n this.hits += 1;\n }\n miss() {\n this.hits += 1;\n }\n getMatchFunction(selector: string, maxSize = 100): MatchFunction {\n let matchFn = this.get(selector);\n\n if (!matchFn) {\n this.miss();\n // If cache is full, remove oldest entry\n if (this.size >= maxSize) {\n const firstKey = this.keys().next().value;\n /* istanbul ignore else @preserve */\n if (firstKey) this.delete(firstKey);\n }\n\n // Parse selector parts once and create a matcher function\n const parts = selector.split(\",\").map((s) => s.trim());\n\n matchFn = (node: DOMNode): boolean =>\n parts.some((part) => matchesSingleSelector(node, part));\n\n this.set(selector, matchFn);\n } else {\n this.hit();\n }\n\n return matchFn;\n }\n clear() {\n super.clear();\n this.misses = 0;\n this.hits = 0;\n }\n getStats() {\n return {\n size: this.size,\n hits: this.hits,\n misses: this.misses,\n // prevent division by ZERO\n hitRate: this.hits / ((this.hits + this.misses) || 1),\n };\n }\n}\n\nexport const selectorCache = new SelectorCacheMap();\n\n// Selector RegExp\nconst SELECTOR_REGEX = /([.#]?[\\w-]+|\\[[\\w-]+(?:=[^\\]]+)?\\])+/g;\n\n/**\n * Parses a CSS selector string into an array of selector parts.\n * Each part represents a segment of the selector (e.g., tag name, class, id, attribute).\n * @param selector The CSS selector string to parse.\n * @returns An array of `SelectorPart` objects representing the parsed selector.\n */\nconst parseSelector = (selector: string): SelectorPart[] => {\n const parts: SelectorPart[] = [];\n const matches =\n selector.match(SELECTOR_REGEX) || /* istanbul ignore next @preserve */ [];\n\n for (const match of matches) {\n if (startsWith(match, \"#\")) {\n parts.push({ type: \"#\", name: \"id\", value: match.slice(1) });\n } else if (startsWith(match, \".\")) {\n parts.push({ type: \".\", name: \"class\", value: match.slice(1) });\n } else if (startsWith(match, \"[\")) {\n const [name, value] = match.slice(1, -1).split(\"=\");\n parts.push({\n type: \"[\",\n name,\n value: value ? value.replace(/['\"]/g, \"\") : undefined,\n });\n } else {\n parts.push({ type: \"\", name: match });\n }\n }\n return parts;\n};\n\n/**\n * Checks if a node matches a single CSS selector.\n * @param node The `DOMNode` object to test against the selector.\n * @param selector The CSS selector string.\n * @returns `true` if the node matches the selector, `false` otherwise.\n */\nconst matchesSingleSelector = (node: DOMNode, selector: string): boolean => {\n const parts = parseSelector(selector);\n\n return parts.every((part) => {\n switch (part.type) {\n case \"#\": {\n return node.attributes.get(\"id\") === part.value;\n }\n case \".\": {\n const classes = node.attributes.get(\"class\")?.split(/\\s+/) || [];\n return classes.includes(part.value as string);\n }\n case \"[\": {\n const attrValue = node.attributes.get(part.name);\n return part.value ? attrValue === part.value : attrValue !== undefined;\n }\n default: {\n return toLowerCase(node.tagName) === toLowerCase(part.name);\n }\n }\n });\n};\n\n/**\n * Checks if a node matches one or mode CSS selectors.\n * @param node The `DOMNode` object to test against the selector.\n * @param selector The CSS selector string.\n * @returns `true` if the node matches the selector, `false` otherwise.\n */\nexport const matchesSelector = (node: DOMNode, selector: string): boolean => {\n const matcher = selectorCache.getMatchFunction(selector);\n return matcher(node);\n};\n","// prototype.ts\nimport { tokenize, trim } from \"./util\";\nimport { matchesSelector } from \"./selectors\";\nimport {\n defineProperties,\n DOM_ERROR,\n isNode,\n isObj,\n isPrimitive,\n isRoot,\n isTag,\n selfClosingTags,\n toUpperCase,\n} from \"./util\";\n\nimport type {\n ChildElementList,\n ChildNode,\n ChildNodeList,\n CommentNode,\n DOMNode,\n MaybeChildNode,\n NodeLikeAttributes,\n RootNode,\n TagNames,\n TextNode,\n TextToken,\n} from \"./types\";\n\n/**\n * Generates text string from node's children textContent.\n * @param node The node whose children to stringify\n * @returns textContent string\n */\nconst textContent = (node: ChildNode): string => {\n if (!isTag(node)) return node.nodeValue;\n const { childNodes, nodeName } = node;\n if (nodeName === \"BR\") return \"\\n\";\n if (!childNodes.length) return \"\";\n const hasTagChild = childNodes.some(isTag);\n\n return childNodes\n .map((n) => (isTag(n) ? textContent(n) : n.nodeValue))\n .join(hasTagChild ? \"\\n\" : \"\");\n};\n\n/**\n * Generates HTML string for node's children\n * @param node The node whose children to stringify\n * @param depth Current indentation depth\n * @returns innerHTML string\n */\nconst innerHTML = (node: DOMNode, depth = 0): string => {\n const { childNodes: childContents } = node;\n // Remove comments\n const childNodes = childContents.filter((c) => c.nodeName !== \"#comment\");\n if (!childNodes.length) return \"\";\n const childIsText = childNodes.length === 1 && !isTag(childNodes[0]);\n const space = depth && !childIsText ? \" \".repeat(depth) : \"\";\n return childNodes\n .map((n) => (isTag(n) ? outerHTML(n, depth) : space + n.nodeValue))\n .join(\"\\n\");\n};\n\n/**\n * Generates HTML string for a node including its opening/closing tags\n * @param node The node to stringify\n * @param depth Current indentation depth\n * @returns outerHTML string\n */\nconst outerHTML = (node: DOMNode, depth = 0): string => {\n const { attributes, tagName, childNodes: childContents } = node;\n const childNodes = childContents.filter((c) => c.nodeName !== \"#comment\");\n const space = depth ? \" \".repeat(depth) : \"\";\n const hasChildren = childNodes.length > 0;\n const childIsText = childNodes.length === 1 && !isTag(childNodes[0]);\n const hasAttributes = attributes.size > 0;\n const isSelfClosing = selfClosingTags.has(tagName);\n\n const attrStr = hasAttributes\n ? \" \" +\n Array.from(attributes)\n .map(([key, val]) => `${key}=\"${trim(val)}\"`)\n .join(\" \")\n : \"\";\n\n let output = `${space}<${tagName}${attrStr}${isSelfClosing ? \" /\" : \"\"}>`;\n output += !childIsText && hasChildren ? \"\\n\" : \"\";\n output += hasChildren ? innerHTML(node, depth + 1) : \"\";\n output += !childIsText && hasChildren ? `\\n${space}` : \"\";\n output += !isSelfClosing ? `</${tagName}>` : \"\";\n\n return output;\n};\n\n/**\n * Creates a basic text or comment node.\n * @param nodeName The node name (\"#text\" or \"#comment\").\n * @param text The text content of the node.\n * @returns A TextNode or CommentNode object.\n */\nexport function createBasicNode<T extends \"#text\" | \"#comment\">(\n nodeName: T,\n text: string,\n): TextNode | CommentNode {\n return {\n nodeName,\n // nodeValue: nodeName !== \"#text\" ? `<${text}>` : text,\n nodeValue: text,\n } as TextNode | CommentNode;\n}\n\nfunction setupChildNode(\n child: ChildNode,\n parent: DOMNode | RootNode,\n ownerDocument?: RootNode,\n) {\n defineProperties(child, {\n textContent: {\n enumerable: false,\n configurable: true,\n get: () => textContent(child),\n set: (newContent: string) => {\n if (isTag(child)) {\n child.replaceChildren();\n child.appendChild(createBasicNode(\"#text\", newContent));\n } else {\n child.nodeValue = newContent;\n }\n },\n },\n parentNode: {\n enumerable: false,\n configurable: true,\n get: () => parent,\n },\n parentElement: {\n enumerable: false,\n configurable: true,\n get: () => parent,\n },\n ownerDocument: {\n enumerable: false,\n configurable: true,\n get: () => ownerDocument,\n },\n });\n\n child.remove = () => parent.removeChild(child);\n\n // Define recursive before and after methods\n child.before = (...nodes: ChildNodeList) => {\n const validNodes = nodes.map(convertToNode).filter(isNode);\n const index = parent.childNodes.indexOf(child);\n // istanbul ignore else @preserve\n if (index > -1) {\n parent.childNodes.splice(index, 0, ...validNodes);\n validNodes.forEach((n, i) => {\n // istanbul ignore else @preserve\n if (isTag(n)) {\n const childIndex = (parent as DOMNode).children.indexOf(\n child as DOMNode,\n );\n (parent as DOMNode).children.splice(childIndex + i, 0, n);\n ownerDocument?.register(n);\n // istanbul ignore else @preserve\n if (isTag(parent as DOMNode)) (parent as DOMNode).registerChild(n);\n }\n setupChildNode(n, parent, ownerDocument); // Setup new nodes\n });\n }\n };\n\n child.after = (...nodes: ChildNodeList) => {\n const validNodes = nodes.map(convertToNode).filter(isNode);\n const index = parent.childNodes.indexOf(child);\n // istanbul ignore else @preserve\n if (index > -1) {\n parent.childNodes.splice(index + 1, 0, ...validNodes);\n validNodes.forEach((n: ChildNode, i: number) => {\n // istanbul ignore else @preserve\n if (isTag(n)) {\n const childIndex = (parent as DOMNode).children.indexOf(\n child as DOMNode,\n );\n (parent as DOMNode).children.splice(childIndex + 1 + i, 0, n);\n ownerDocument?.register(n);\n // istanbul ignore else @preserve\n if (isTag(parent as DOMNode)) (parent as DOMNode).registerChild(n);\n }\n setupChildNode(n, parent, ownerDocument); // Setup new nodes\n });\n }\n };\n}\n\n/**\n * Creates a DOM-like Node (`DOMNode` or `RootNode`) with DOM API properties and methods.\n * This function extends the basic `NodeLike` from **Parser** by adding DOM-specific\n * properties and methods, as well as applying filters based on the provided configuration.\n *\n * @param this - The `RootNode` when creating a `DOMNode`, or `null` otherwise (in non-strict mode)\n * @param nodeName The tag name of the node to create (or '#document' for the root).\n * @param childNodes Optional child nodes to append to the created node.\n * @returns An extended `DOMNode` or `RootNode` object with DOM API.\n */\nexport function createNode(\n this: RootNode | null,\n nodeName: string,\n ...childNodes: ChildNodeList\n): Omit<DOMNode, \"tagName\" | \"attributes\"> | RootNode {\n const ALL: ChildElementList = [];\n const CHILDREN: ChildElementList = [];\n const CHILDNODES: ChildNodeList = [];\n const nodeIsRoot = nodeName === \"#document\";\n const ownerDocument = this ?? undefined;\n\n const node = {\n nodeName,\n appendChild(child: ChildNode) {\n if (!isNode(child)) {\n throw new Error(`${DOM_ERROR} Invalid node.`);\n }\n CHILDNODES.push(child);\n if (isTag(child)) {\n ALL.push(child);\n CHILDREN.push(child);\n ownerDocument?.register(child);\n }\n\n setupChildNode(child, node as unknown as DOMNode, ownerDocument);\n },\n append(...nodes: ChildNodeList) {\n for (const child of nodes) {\n node.appendChild(child);\n }\n },\n cleanup: () => {\n ALL.length = 0;\n CHILDREN.length = 0;\n CHILDNODES.length = 0;\n },\n\n // Root document methods\n ...(isRoot({ nodeName } as RootNode) && {\n createElement(\n tagName:\n & string\n & (keyof HTMLElementTagNameMap | keyof SVGElementTagNameMap),\n first?: NodeLikeAttributes | MaybeChildNode,\n ...rest: MaybeChildNode[]\n ) {\n return createElement.call(node as RootNode, tagName, first, ...rest);\n },\n createElementNS(\n _ns: string,\n tagName:\n & string\n & (keyof SVGElementTagNameMap & keyof HTMLElementTagNameMap),\n first?: NodeLikeAttributes | MaybeChildNode,\n ...rest: MaybeChildNode[]\n ) {\n return createElement.call(node as RootNode, tagName, first, ...rest);\n },\n createComment(content: string) {\n return createBasicNode(\"#comment\", content);\n },\n createTextNode(content: string) {\n return createBasicNode(\"#text\", content);\n },\n getElementById(id: string) {\n return ALL.find((node) => node.attributes.get(\"id\") === id) ?? null;\n },\n }),\n\n // Element methods\n ...(!nodeIsRoot && {\n matches(selector: string) {\n return matchesSelector(node as unknown as DOMNode, selector);\n },\n }),\n // Shared methods\n contains: (childNode: DOMNode) => {\n if (!childNode || !isTag(childNode)) {\n throw new Error(\n \"DomError: the childNode parameter must be a valid DOMNode\",\n );\n }\n if ((node as DOMNode | RootNode).children.includes(childNode)) {\n return true;\n }\n\n let currentParent = childNode.parentNode;\n while (currentParent) {\n if (currentParent === node) {\n return true;\n }\n currentParent = currentParent.parentNode;\n }\n return false;\n },\n removeChild(childNode: ChildNode) {\n if (!childNode || !isNode(childNode)) {\n throw new Error(\n \"DomError: the childNode parameter must be a valid ChildNode\",\n );\n }\n\n const indexOf = (arr: ChildNode[]) => arr.indexOf(childNode);\n /* istanbul ignore else @preserve */\n if (isTag(childNode)) {\n const idx1 = indexOf(ALL);\n const idx2 = indexOf(CHILDREN);\n /* istanbul ignore else @preserve */\n if (idx1 > -1) ALL.splice(idx1, 1);\n /* istanbul ignore else @preserve */\n if (idx2 > -1) CHILDREN.splice(idx2, 1);\n childNode.cleanup();\n\n ownerDocument?.deregister(childNode);\n }\n\n const idx3 = indexOf(CHILDNODES);\n /* istanbul ignore else @preserve */\n if (idx3 > -1) CHILDNODES.splice(idx3, 1);\n },\n replaceChildren: (...newChildren: DOMNode[]) => {\n // clone this array to work\n CHILDNODES.slice(0).forEach((child) => node.removeChild(child));\n node.append(...newChildren);\n },\n querySelector(selector: string) {\n return ALL.find((n) => n.matches(selector)) ?? null;\n },\n querySelectorAll(selector: string) {\n return ALL.filter((n) => n.matches(selector));\n },\n getElementsByTagName(tagName: string) {\n return tagName === \"*\"\n ? ALL\n : ALL.filter((n) => n.tagName.toLowerCase() === tagName.toLowerCase());\n },\n getElementsByClassName(className: string) {\n return ALL.filter((n) => {\n const classAttr = n.attributes.get(\"class\");\n return classAttr?.split(/\\s+/).includes(className) ?? false;\n });\n },\n };\n\n // Define enumerable getters\n defineProperties(node, {\n childNodes: {\n enumerable: true,\n get: () => CHILDNODES,\n },\n children: {\n enumerable: true,\n get: () => CHILDREN,\n },\n // Add tag-specific property\n ...(!nodeIsRoot\n ? {\n registerChild: {\n enumerable: false,\n value: (child: DOMNode) => {\n ALL.push(child);\n },\n },\n }\n : {}),\n });\n\n // Add root-specific properties\n if (nodeIsRoot) {\n defineProperties(node, {\n all: {\n enumerable: true,\n get: () => ALL,\n },\n documentElement: {\n enumerable: true,\n get: () => ALL.find((node) => toUpperCase(node.tagName) === \"HTML\"),\n },\n head: {\n enumerable: true,\n get: () => ALL.find((node) => toUpperCase(node.tagName) === \"HEAD\"),\n },\n body: {\n enumerable: true,\n get: () => ALL.find((node) => toUpperCase(node.tagName) === \"BODY\"),\n },\n register: {\n enumerable: false,\n value: (child: DOMNode) => {\n ALL.push(child);\n },\n },\n deregister: {\n enumerable: false,\n value: (child: DOMNode) => {\n const idx = ALL.indexOf(child);\n /* istanbul ignore else @preserve */\n if (idx > -1) ALL.splice(idx, 1);\n },\n },\n });\n } else {\n // Add HTML generation methods\n defineProperties(node, {\n innerHTML: {\n enumerable: false,\n get: () => innerHTML(node as unknown as DOMNode),\n },\n outerHTML: {\n enumerable: false,\n get: () => outerHTML(node as unknown as DOMNode),\n },\n });\n }\n\n // Add any initial children\n if (childNodes?.length) {\n node.append(...childNodes);\n }\n\n return node as unknown as RootNode | Omit<DOMNode, \"tagName\" | \"attributes\">;\n}\n\nconst convertToNode = (n: string | number | ChildNode) => {\n if (isPrimitive(n)) {\n const { tokenType, value } = tokenize(String(n))[0] as TextToken;\n return createBasicNode(`#${tokenType}`, value);\n }\n return n;\n};\n\n/**\n * Creates a new `Element` like node\n * @param this The RootNode instance\n * @param tagName Tag name for the element\n * @param first Optional attributes or first child\n * @param args Additional child nodes\n * @returns New element node\n */\nexport function createElement(\n this: RootNode,\n tagName: string & TagNames,\n first?: NodeLikeAttributes | MaybeChildNode,\n ...args: MaybeChildNode[]\n): DOMNode {\n const childNodes: ChildNodeList = [];\n let attributes = new Map<string, string>();\n\n // Handle first argument\n /* istanbul ignore else @preserve */\n if (first) {\n if (isObj(first) && !isNode(first)) {\n // Convert attributes object to Map\n attributes = new Map(Object.entries(first));\n } else {\n childNodes.push(convertToNode(first as string | number | ChildNode));\n }\n }\n\n // Add remaining children\n const nodes = args.map(convertToNode).filter(isNode);\n childNodes.push(...nodes);\n\n const node = createNode.call(\n this,\n toUpperCase(tagName),\n ...childNodes,\n ) as DOMNode;\n\n const charset = attributes.get(\"charset\");\n if (tagName === \"meta\" && charset) {\n this.charset = toUpperCase(charset);\n }\n\n defineProperties(node, {\n tagName: {\n enumerable: true,\n get: () => tagName,\n },\n attributes: {\n enumerable: true,\n get: () => attributes,\n },\n id: {\n enumerable: true,\n get: () => attributes.get(\"id\") ?? \"\",\n },\n className: {\n enumerable: true,\n get: () => attributes.get(\"class\") ?? \"\",\n },\n });\n // define Element attributes methods\n node.hasAttribute = (attrName: string) => attributes.has(attrName);\n node.getAttribute = (attrName: string) => attributes.get(attrName) ?? null;\n node.setAttribute = (attrName: string, attrValue: string) => {\n attributes.set(attrName, attrValue);\n };\n node.removeAttribute = (attrName: string) => {\n attributes.delete(attrName);\n };\n node.hasAttributeNS = (_namespace: string, attrName: string) =>\n attributes.has(attrName);\n node.getAttributeNS = (_namespace: string, attrName: string) =>\n attributes.get(attrName) ?? null;\n node.setAttributeNS = (_namespace: string, attrName, attrValue: string) => {\n attributes.set(attrName, attrValue);\n };\n node.removeAttributeNS = (_namespace: string, attrName: string) => {\n attributes.delete(attrName);\n };\n // define Element parent selector\n node.closest = (selector: string) => {\n if (!selector) throw new Error(\"DomError: selector must be a string\");\n if (node.matches(selector)) return node;\n let currentParent = node.parentNode;\n while (!isRoot(currentParent)) {\n if (currentParent.matches(selector)) {\n return currentParent;\n }\n currentParent = currentParent.parentNode;\n }\n return null;\n };\n\n return node;\n}\n\n/**\n * Creates a new `Document` like root node.\n *\n * @returns a new root node\n */\nexport const createDocument = () =>\n createNode.call(null, \"#document\") as RootNode;\n"],"mappings":"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"}