UNPKG

@intlayer/core

Version:

Includes core Intlayer functions like translation, dictionary, and utility functions shared across multiple packages.

123 lines (122 loc) 3.77 kB
//#region src/interpreter/getHTML.ts /** * Helper to parse attributes from a tag string. */ const parseAttributes = (attributes) => { const props = {}; const attrRegex = /([a-zA-Z0-9-]+)="([^"]*)"/g; let match = attrRegex.exec(attributes); while (match !== null) { props[match[1]] = match[2]; match = attrRegex.exec(attributes); } return props; }; const astCache = /* @__PURE__ */ new Map(); const parseHTML = (content) => { if (astCache.has(content)) return astCache.get(content); if (typeof content !== "string") return []; const tagRegex = /<(\/)?([a-zA-Z0-9.-]+)([\s\S]*?)(\/?)>/g; const elements = []; const stack = []; let lastIndex = 0; let match = tagRegex.exec(content); const appendChild = (child) => { (stack.length > 0 ? stack[stack.length - 1].children : elements).push(child); }; while (match !== null) { const [fullMatch, isClosingRaw, tagName, attributesRaw, isSelfClosingRaw] = match; const matchIndex = match.index; if (matchIndex > lastIndex) appendChild(content.slice(lastIndex, matchIndex)); const isClosing = isClosingRaw === "/"; const isSelfClosing = isSelfClosingRaw === "/" || attributesRaw.trim().endsWith("/") || fullMatch.endsWith("/>"); const cleanedAttributes = attributesRaw.trim().replace(/\/$/, "").trim(); if (isClosing) { const last = stack[stack.length - 1]; if (last && last.tagName === tagName) { const popped = stack.pop(); if (popped) appendChild({ tagName: popped.tagName, props: popped.props, children: popped.children }); } } else if (isSelfClosing) appendChild({ tagName, props: parseAttributes(cleanedAttributes), children: [] }); else { const tagProps = parseAttributes(cleanedAttributes); stack.push({ tagName, children: [], props: tagProps }); } lastIndex = matchIndex + fullMatch.length; match = tagRegex.exec(content); } if (lastIndex < content.length) appendChild(content.slice(lastIndex)); while (stack.length > 0) { const last = stack.pop(); if (last) appendChild({ tagName: last.tagName, props: last.props, children: last.children }); } astCache.set(content, elements); return elements; }; /** * Interprets a string containing HTML-like tags and replaces them with provided components or strings. */ const getHTML = (content, values) => { const ast = parseHTML(content); let keyCounter = 0; const renderASTNode = (node) => { if (typeof node === "string") return node; const { tagName, props, children } = node; const renderedChildren = children.flatMap(renderASTNode); const index = keyCounter++; let override = values[tagName]; if (!override) { const lowerTagName = tagName.toLowerCase(); const foundKey = Object.keys(values).find((key) => key.toLowerCase() === lowerTagName); if (foundKey) override = values[foundKey]; } const key = `html-tag-${tagName}-${index}`; if (typeof override === "function") return override({ ...props, children: renderedChildren, key }); if (typeof override === "string") { const component = values[override]; if (typeof component === "function") return component({ ...props, children: renderedChildren, key }); return renderedChildren; } if (typeof override === "object" && override !== null && "tag" in override) { const { tag: targetTag, props: extraProps } = override; const component = values[targetTag]; if (typeof component === "function") return component({ ...props, ...extraProps, children: renderedChildren, key }); return renderedChildren; } return renderedChildren; }; const result = ast.flatMap(renderASTNode); return result.length === 1 ? result[0] : result; }; //#endregion export { getHTML }; //# sourceMappingURL=getHTML.mjs.map