UNPKG

hono

Version:

Web framework built on Web Standards

124 lines (123 loc) 3 kB
// src/utils/html.ts var HtmlEscapedCallbackPhase = { Stringify: 1, BeforeStream: 2, Stream: 3 }; var raw = (value, callbacks) => { const escapedString = new String(value); escapedString.isEscaped = true; escapedString.callbacks = callbacks; return escapedString; }; var escapeRe = /[&<>'"]/; var stringBufferToString = async (buffer, callbacks) => { let str = ""; callbacks ||= []; const resolvedBuffer = await Promise.all(buffer); for (let i = resolvedBuffer.length - 1; ; i--) { str += resolvedBuffer[i]; i--; if (i < 0) { break; } let r = resolvedBuffer[i]; if (typeof r === "object") { callbacks.push(...r.callbacks || []); } const isEscaped = r.isEscaped; r = await (typeof r === "object" ? r.toString() : r); if (typeof r === "object") { callbacks.push(...r.callbacks || []); } if (r.isEscaped ?? isEscaped) { str += r; } else { const buf = [str]; escapeToBuffer(r, buf); str = buf[0]; } } return raw(str, callbacks); }; var escapeToBuffer = (str, buffer) => { const match = str.search(escapeRe); if (match === -1) { buffer[0] += str; return; } let escape; let index; let lastIndex = 0; for (index = match; index < str.length; index++) { switch (str.charCodeAt(index)) { case 34: escape = "&quot;"; break; case 39: escape = "&#39;"; break; case 38: escape = "&amp;"; break; case 60: escape = "&lt;"; break; case 62: escape = "&gt;"; break; default: continue; } buffer[0] += str.substring(lastIndex, index) + escape; lastIndex = index + 1; } buffer[0] += str.substring(lastIndex, index); }; var resolveCallbackSync = (str) => { const callbacks = str.callbacks; if (!callbacks?.length) { return str; } const buffer = [str]; const context = {}; callbacks.forEach((c) => c({ phase: HtmlEscapedCallbackPhase.Stringify, buffer, context })); return buffer[0]; }; var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) => { if (typeof str === "object" && !(str instanceof String)) { if (!(str instanceof Promise)) { str = str.toString(); } if (str instanceof Promise) { str = await str; } } const callbacks = str.callbacks; if (!callbacks?.length) { return Promise.resolve(str); } if (buffer) { buffer[0] += str; } else { buffer = [str]; } const resStr = Promise.all(callbacks.map((c) => c({ phase, buffer, context }))).then( (res) => Promise.all( res.filter(Boolean).map((str2) => resolveCallback(str2, phase, false, context, buffer)) ).then(() => buffer[0]) ); if (preserveCallbacks) { return raw(await resStr, callbacks); } else { return resStr; } }; export { HtmlEscapedCallbackPhase, escapeToBuffer, raw, resolveCallback, resolveCallbackSync, stringBufferToString };