import { parseHTML } from "linkedom"; export const RUNTIME_BOOTSTRAP_ATTR = "data-hyperframes-preview-runtime"; const RUNTIME_SRC_MARKERS = [ "hyperframe.runtime.iife.js", "hyperframes-runtime.modular.inline.js", "hyperframe-runtime.modular-runtime.inline.js", RUNTIME_BOOTSTRAP_ATTR, ]; const RUNTIME_INLINE_MARKERS = [ "__hyperframeRuntimeBootstrapped", "__hyperframeRuntime", "__hyperframeRuntimeTeardown", "__HF_EXPORT_RENDER_SEEK_CONFIG", "window.__player =", ]; const SIMPLE_RUNTIME_FLAG_ASSIGNMENTS = [ /^window\.__playerReady\s*=\s*(?:true|false)\s*;?$/, /^window\.__renderReady\s*=\s*(?:true|false)\s*;?$/, ]; /** * Parse a full HTML document or wrap a fragment so linkedom consistently puts * fragment content under document.body. */ export function parseHTMLContent(html: string): Document { const trimmed = html.trimStart().toLowerCase(); if (trimmed.startsWith("${html}`).document; } export function stripEmbeddedRuntimeScripts(html: string): string { if (!html) return html; const loweredHtml = html.toLowerCase(); let output = ""; let cursor = 0; while (cursor < html.length) { const scriptStart = findScriptStart(loweredHtml, cursor); if (scriptStart === -1) { output += html.slice(cursor); break; } output += html.slice(cursor, scriptStart); const startTagEnd = findTagEnd(html, scriptStart + 1); if (startTagEnd === -1) { output += html.slice(scriptStart); break; } const closeTagEnd = findScriptCloseTagEnd(loweredHtml, startTagEnd + 1); const scriptEnd = closeTagEnd === -1 ? html.length : closeTagEnd; const block = html.slice(scriptStart, scriptEnd); if (!shouldStripRuntimeScriptBlock(block)) { output += block; } cursor = scriptEnd; } return output; } function findScriptStart(loweredHtml: string, from: number): number { let index = loweredHtml.indexOf("") return index; } return -1; } function findScriptCloseTagEnd(loweredHtml: string, from: number): number { let index = loweredHtml.indexOf("" ? cursor + 1 : -1; } function shouldStripRuntimeScriptBlock(block: string): boolean { const lowered = block.toLowerCase(); for (const marker of RUNTIME_SRC_MARKERS) { if (lowered.includes(marker.toLowerCase())) return true; } for (const marker of RUNTIME_INLINE_MARKERS) { if (block.includes(marker)) return true; } const scriptSource = getScriptSource(block).trim(); for (const pattern of SIMPLE_RUNTIME_FLAG_ASSIGNMENTS) { if (pattern.test(scriptSource)) return true; } return false; } function getScriptSource(block: string): string { const startTagEnd = findTagEnd(block, 1); if (startTagEnd === -1) return ""; const loweredBlock = block.toLowerCase(); const closeTagStart = loweredBlock.lastIndexOf("" || char === "/" || isHtmlWhitespace(char); } function isHtmlWhitespace(char: string): boolean { return char === " " || char === "\n" || char === "\t" || char === "\r" || char === "\f"; } function escapeInlineScriptSource(source: string): string { return escapeCaseInsensitiveToken( escapeCaseInsensitiveToken(source, " ``).join("\n"); } /** * Insert raw tag markup at the very start of ``, ahead of every author * script (inline or external). Falls back to just before ``, then to the * top of the document, for fragments that carry neither. */ export function injectTagsAtHeadStart(html: string, tags: string): string { if (html.includes("]*>/i, (match) => `${match}\n${tags}`); } if (html.includes(" `${tags}\n 0) { const headTags = inlineScriptTags(headScripts); if (html.includes("")) { // Function replacement avoids `$&` interpolation in runtime source. html = html.replace("", () => `${headTags}\n`); } else if (html.includes(" `${headTags}\n 0) { const bodyTags = inlineScriptTags(bodyScripts); if (html.includes("")) { html = html.replace("", () => `${bodyTags}\n`); } else { html = `${html}\n${bodyTags}`; } } return html; }