import { clsx } from "clsx"; import { HTMLString, markHTMLString } from "../escape.js"; const voidElementNames = /^(area|base|br|col|command|embed|hr|img|input|keygen|link|meta|param|source|track|wbr)$/i; const htmlBooleanAttributes = /^(allowfullscreen|async|autofocus|autoplay|controls|default|defer|disabled|disablepictureinpicture|disableremoteplayback|formnovalidate|hidden|loop|nomodule|novalidate|open|playsinline|readonly|required|reversed|scoped|seamless|itemscope)$/i; const htmlEnumAttributes = /^(contenteditable|draggable|spellcheck|value)$/i; const svgEnumAttributes = /^(autoReverse|externalResourcesRequired|focusable|preserveAlpha)$/i; const STATIC_DIRECTIVES = /* @__PURE__ */ new Set(["set:html", "set:text"]); const toIdent = (k) => k.trim().replace(/(?:(?!^)\b\w|\s+|[^\w]+)/g, (match, index) => { if (/[^\w]|\s/.test(match)) return ""; return index === 0 ? match : match.toUpperCase(); }); const toAttributeString = (value, shouldEscape = true) => shouldEscape ? String(value).replace(/&/g, "&").replace(/"/g, """) : value; const kebab = (k) => k.toLowerCase() === k ? k : k.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`); const toStyleString = (obj) => Object.entries(obj).filter(([_, v]) => typeof v === "string" && v.trim() || typeof v === "number").map(([k, v]) => { if (k[0] !== "-" && k[1] !== "-") return `${kebab(k)}:${v}`; return `${k}:${v}`; }).join(";"); function defineScriptVars(vars) { let output = ""; for (const [key, value] of Object.entries(vars)) { output += `const ${toIdent(key)} = ${JSON.stringify(value)?.replace( /<\/script>/g, "\\x3C/script>" )}; `; } return markHTMLString(output); } function formatList(values) { if (values.length === 1) { return values[0]; } return `${values.slice(0, -1).join(", ")} or ${values[values.length - 1]}`; } function addAttribute(value, key, shouldEscape = true) { if (value == null) { return ""; } if (value === false) { if (htmlEnumAttributes.test(key) || svgEnumAttributes.test(key)) { return markHTMLString(` ${key}="false"`); } return ""; } if (STATIC_DIRECTIVES.has(key)) { console.warn(`[astro] The "${key}" directive cannot be applied dynamically at runtime. It will not be rendered as an attribute. Make sure to use the static attribute syntax (\`${key}={value}\`) instead of the dynamic spread syntax (\`{...{ "${key}": value }}\`).`); return ""; } if (key === "class:list") { const listValue = toAttributeString(clsx(value), shouldEscape); if (listValue === "") { return ""; } return markHTMLString(` ${key.slice(0, -5)}="${listValue}"`); } if (key === "style" && !(value instanceof HTMLString)) { if (Array.isArray(value) && value.length === 2) { return markHTMLString( ` ${key}="${toAttributeString(`${toStyleString(value[0])};${value[1]}`, shouldEscape)}"` ); } if (typeof value === "object") { return markHTMLString(` ${key}="${toAttributeString(toStyleString(value), shouldEscape)}"`); } } if (key === "className") { return markHTMLString(` class="${toAttributeString(value, shouldEscape)}"`); } if (value === true && (key.startsWith("data-") || htmlBooleanAttributes.test(key))) { return markHTMLString(` ${key}`); } else { return markHTMLString(` ${key}="${toAttributeString(value, shouldEscape)}"`); } } function internalSpreadAttributes(values, shouldEscape = true) { let output = ""; for (const [key, value] of Object.entries(values)) { output += addAttribute(value, key, shouldEscape); } return markHTMLString(output); } function renderElement(name, { props: _props, children = "" }, shouldEscape = true) { const { lang: _, "data-astro-id": astroId, "define:vars": defineVars, ...props } = _props; if (defineVars) { if (name === "style") { delete props["is:global"]; delete props["is:scoped"]; } if (name === "script") { delete props.hoist; children = defineScriptVars(defineVars) + "\n" + children; } } if ((children == null || children == "") && voidElementNames.test(name)) { return `<${name}${internalSpreadAttributes(props, shouldEscape)} />`; } return `<${name}${internalSpreadAttributes(props, shouldEscape)}>${children}`; } function renderToBufferDestination(bufferRenderFunction) { const bufferChunks = []; const bufferDestination = { write: (chunk) => bufferChunks.push(chunk) }; const renderPromise = bufferRenderFunction(bufferDestination); return { async renderToFinalDestination(destination) { for (const chunk of bufferChunks) { destination.write(chunk); } bufferDestination.write = (chunk) => destination.write(chunk); await renderPromise; } }; } export { addAttribute, defineScriptVars, formatList, internalSpreadAttributes, renderElement, renderToBufferDestination, toAttributeString, voidElementNames };