import * as parse5 from 'parse5'; import type { DefaultTreeAdapterTypes } from 'parse5'; import { sanitizeCustomHeadInput } from './custom-head'; import type { JsMode } from '../types/js-mode'; type ElementNode = DefaultTreeAdapterTypes.Element; type Node = DefaultTreeAdapterTypes.Node; export type FullHtmlExportInput = { html: string; documentHtmlAttributes: string; customHead: string; css: string; cssMode?: 'standard' | 'tailwind-source'; js: string; jsMode: JsMode; canEditJs: boolean; }; const isElement = (node: Node): node is ElementNode => 'tagName' in node; const findElement = (node: Node, tagName: string): ElementNode | null => { if (isElement(node) && node.tagName.toLowerCase() === tagName.toLowerCase()) { return node; } if (!('childNodes' in node)) { return null; } for (const child of node.childNodes) { const match = findElement(child, tagName); if (match) { return match; } } return null; }; const serializeAttrs = (node: ElementNode): string => node.attrs .map((attr) => `${attr.name}="${attr.value.replace(/&/g, '&').replace(/"/g, '"')}"`) .join(' ') .trim(); const escapeStyleText = (css: string): string => css.replace(/<\/style/gi, '<\\/style'); const escapeScriptText = (js: string): string => js.replace(/<\/script/gi, '<\\/script'); function splitEditorHtml(html: string): { bodyAttrs: string; bodyHtml: string } { if (!html.toLowerCase().includes('', '', ]; const customHead = input.canEditJs ? sanitizeCustomHeadInput(input.customHead).html : ''; const css = input.css.trim(); const js = input.canEditJs ? input.js.trim() : ''; if (customHead) { headParts.push(customHead); } if (css) { const styleAttrs = input.cssMode === 'tailwind-source' ? ' type="text/tailwindcss"' : ''; headParts.push(`\n${escapeStyleText(css)}\n`); } const bodyParts = [bodyHtml]; if (js) { const scriptAttrs = input.jsMode === 'module' ? ' type="module"' : ''; bodyParts.push(`\n${escapeScriptText(js)}\n`); } const bodyOpen = bodyAttrs ? `` : ''; const htmlOpen = input.documentHtmlAttributes.trim() ? `` : ''; return [ '', htmlOpen, '', headParts.join('\n'), '', bodyOpen, bodyParts.filter((part) => part !== '').join('\n'), '', '', ].join('\n'); }