UNPKG

@popeindustries/lit-html-server

Version:

Efficiently render streaming lit-html templates on the server (or in a ServiceWorker!)

1,169 lines (1,151 loc) 37.8 kB
var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default")); // src/lit-html-server.js import "./dom-shim.js"; // src/internal/buffer.js var buffer_exports = {}; __reExport(buffer_exports, node_buffer_star); import * as node_buffer_star from "node:buffer"; // src/internal/consts.js var EMPTY_STRING_BUFFER = buffer_exports.Buffer.from(""); var SPACE_STRING_BUFFER = buffer_exports.Buffer.from(" "); var META_CHILD_CLOSE = buffer_exports.Buffer.from(`<!--/lit-child-->`); var META_CHILD_OPEN = buffer_exports.Buffer.from(`<!--lit-child-->`); var META_CLOSE = buffer_exports.Buffer.from(`<!--/lit-->`); var META_CLOSE_SHADOW = buffer_exports.Buffer.from(`<!--/lit--></template>`); // src/internal/is.js import { isDirectiveResult } from "@popeindustries/lit-html/directive-helpers.js"; function isPrimitive(value) { const type = typeof value; return value === null || !(type === "object" || type === "function"); } function isTemplateResult(result) { const r = ( /** @type { TemplateResult } */ result ); return r != null && "_$litType$" in r; } function isTemplateInstanceOrResult(result) { const r = ( /** @type { TemplateResult | TemplateInstance } */ result ); return r != null && ("_$litType$" in r || "_$litServerTemplateInstance$" in r); } function isPromise(promise) { return promise != null && /** @type { Promise<unknown> } */ promise.then != null; } function isSyncIterator(iterator) { return iterator != null && // Ignore strings (which are also iterable) typeof iterator !== "string" && typeof /** @type { IterableIterator<unknown> } */ iterator[Symbol.iterator] === "function"; } function isAsyncIterator(iterator) { return iterator != null && typeof /** @type { AsyncIterable<unknown> } */ iterator[Symbol.asyncIterator] === "function"; } function isIteratorResult(result) { return result != null && typeof result === "object" && "value" in result && "done" in result; } function isBuffer(value) { return buffer_exports.Buffer.isBuffer(value); } function isArray(value) { return Array.isArray(value); } // src/internal/parts.js import { noChange, nothing } from "@popeindustries/lit-html"; // src/internal/digest.js function digestForTemplateStrings(strings) { const digestSize = 2; const hashes = new Uint32Array(digestSize).fill(5381); for (const s of strings) { for (let i = 0; i < s.length; i++) { hashes[i % digestSize] = hashes[i % digestSize] * 33 ^ s.charCodeAt(i); } } return buffer_exports.Buffer.from(String.fromCharCode(...new Uint8Array(hashes.buffer)), "binary").toString("base64"); } // src/internal/escape.js var HTML_ESCAPES = { '"': "&quot;", "'": "&#x27;", "&": "&amp;", "<": "&lt;", ">": "&gt;" }; var RE_HTML = /["'&<>]/g; var RE_SCRIPT_STYLE_TAG = /<\/(script|style)/gi; function escape(string, context = "text") { switch (context) { case "script": case "style": return string.replace(RE_SCRIPT_STYLE_TAG, "<\\/$1").replace(/<!--/g, "\\x3C!--"); case "attribute": case "text": default: return string.replace(RE_HTML, (match) => HTML_ESCAPES[match]); } } // src/internal/get-element-renderer.js import { ElementRenderer } from "./element-renderer.js"; function getElementRenderer({ elementRenderers = [] }, tagName, ceClass = customElements.get(tagName)) { if (ceClass !== void 0) { for (const renderer of elementRenderers) { if (renderer.matchesClass(ceClass, tagName)) { return new renderer(tagName); } } } return new DefaultElementRenderer(tagName); } var DefaultElementRenderer = class extends ElementRenderer { /** * @param { string } tagName */ constructor(tagName) { super(tagName); const ceClass = customElements.get(tagName) ?? HTMLElement; this.element = /** @type { CustomElement } */ new ceClass(); } }; // src/internal/parts.js var partType = { METADATA: 0, ATTRIBUTE: 1, CHILD: 2, CUSTOMELEMENT_OPEN: 3, CUSTOMELEMENT_CLOSE: 4 }; var EMPTY_STRINGS_ARRAY = ["", ""]; var RE_RAW_TEXT_ELEMENT = /^(?:script|style|textarea|title)$/i; var SPACE_BUFFER = buffer_exports.Buffer.from(" "); var TYPE_TO_LIT_PART_TYPE = { attribute: 1, child: 2, property: 3, boolean: 4, event: 5, element: 6 }; function isAttributePart(part) { return part.type === partType.ATTRIBUTE; } function isChildPart(part) { return part.type === partType.CHILD; } function isCustomElementOpenPart(part) { return part.type === partType.CUSTOMELEMENT_OPEN; } function isCustomElementClosePart(part) { return part.type === partType.CUSTOMELEMENT_CLOSE; } function isMetadataPart(part) { return part.type === partType.METADATA; } function getAttributeTypeFromName(name) { if (name === "") { return "element"; } switch (name[0]) { case "?": return "boolean"; case ".": return "property"; case "@": return "event"; default: return "attribute"; } } var AttributePart = class { /** * Constructor * @param { string } tagName */ constructor(tagName) { this.length = 0; this.tagName = tagName; this.type = partType.ATTRIBUTE; this._parts = []; } /** * Add data for specific attribute * @param { AttributeDataType } type * @param { string } [name] * @param { string } [value] * @param { Array<string> } [strings] */ addAttributeData(type, name = "", value, strings) { const hasValue = value !== void 0; let data; let length = 0; switch (type) { case "boolean": { const unprefixedName = name.startsWith("?") ? name.slice(1) : name; length = hasValue ? 0 : 1; data = { type, length, name, nameBuffer: buffer_exports.Buffer.from(unprefixedName) }; if (hasValue) { data.value = ""; data.resolvedBuffer = data.nameBuffer; } break; } case "attribute": case "property": { length = strings !== void 0 ? strings.length - 1 : 0; data = { type, length, name, strings }; if (hasValue) { data.value = value; data.resolvedBuffer = data.type === "attribute" ? buffer_exports.Buffer.from(`${name}="${value}"`) : EMPTY_STRING_BUFFER; } break; } default: { length = 1; data = { type, length, name, value: "", resolvedBuffer: EMPTY_STRING_BUFFER }; } } this.length += length; this._parts.push(data); } /** * Retrieve resolved string Buffer from passed "values". * Resolves to a single string even when responsible for multiple values. * @param { Array<unknown> } values * @param { InternalRenderOptions } options * @returns { unknown } */ resolveValue(values, options) { const buffer = []; let valuesIndex = 0; for (let data of this._parts) { if (data.resolvedBuffer !== void 0) { if (data.resolvedBuffer !== EMPTY_STRING_BUFFER) { buffer.push(SPACE_BUFFER, data.resolvedBuffer); } } else { if (data.type === "boolean") { const partValue = resolveAttributeValue(values[valuesIndex], this.tagName, data); if (partValue !== nothing) { buffer.push(SPACE_BUFFER, data.nameBuffer); } } else if (data.type === "attribute") { let resolvedValue = ""; const strings = ( /** @type { Array<string> } */ data.strings ); const n = data.length; let bailed = false; for (let i = 0; i < n; i++) { const partValue = resolveAttributeValue(values[valuesIndex + i], this.tagName, data); if (partValue === nothing) { bailed = true; break; } resolvedValue += strings[i] + partValue; } if (!bailed) { resolvedValue += strings[strings.length - 1]; resolvedValue = `${data.name}="${resolvedValue}"`; buffer.push(SPACE_BUFFER, buffer_exports.Buffer.from(resolvedValue)); } } } valuesIndex += data.length; } return buffer_exports.Buffer.concat(buffer); } }; var ChildPart = class { /** * Constructor * @param { string } tagName */ constructor(tagName) { this.tagName = tagName; this.type = partType.CHILD; } /** * Retrieve resolved value given passed "value" * @param { unknown } value * @param { InternalRenderOptions } options * @returns { unknown } */ resolveValue(value, options) { return resolveNodeValue( value, this.tagName, RE_RAW_TEXT_ELEMENT.test(this.tagName) || !options.includeHydrationMetadata ? false : true ); } }; var CustomElementOpenPart = class extends AttributePart { /** * Constructor * @param { string } tagName */ constructor(tagName) { super(tagName); this.ceClass = customElements.get(tagName); this.tagName = tagName; this.type = partType.CUSTOMELEMENT_OPEN; } /** * Retrieve resolved value given passed "values" * @param { Array<unknown> } values * @param { InternalRenderOptions } options * @returns { unknown } */ resolveValue(values, options) { options.customElementStack.push(this.tagName); const renderer = getElementRenderer(options, this.tagName, this.ceClass); renderer.connectedCallback(); let valuesIndex = 0; for (let data of this._parts) { if (data.value !== void 0) { setRendererPropertyOrAttribute(renderer, data.name, data.value); } else { if (data.type === "boolean") { const partValue = resolveAttributeValue(values[valuesIndex], this.tagName, data); if (partValue !== nothing) { setRendererPropertyOrAttribute(renderer, data.name, ""); } } else if (data.type === "property" && data.length === 1) { const partValue = resolvePropertyValue(values[valuesIndex], this.tagName, data); if (partValue !== nothing) { setRendererPropertyOrAttribute(renderer, data.name, partValue); } } else if (data.type === "attribute" || data.type === "property") { let resolvedValue = ""; const strings = ( /** @type { Array<string> } */ data.strings ); const n = data.length; let bailed = false; for (let i = 0; i < n; i++) { const partValue = resolveAttributeValue(values[valuesIndex + i], this.tagName, data); if (partValue === nothing) { bailed = true; break; } resolvedValue += strings[i] + partValue; } if (!bailed) { resolvedValue += strings[strings.length - 1]; setRendererPropertyOrAttribute(renderer, data.name, resolvedValue); } } } valuesIndex += data.length; } const shouldRender = !renderer.element.hasAttribute("render:client"); if (shouldRender) { renderer.setAttribute("hydrate:defer", ""); } const resolvedAttributes = buffer_exports.Buffer.from(`${renderer.renderAttributes()}>`); const result = [resolvedAttributes]; if (options.includeHydrationMetadata) { result.push(buffer_exports.Buffer.from(`<!--lit-attr ${this.length}-->`)); } if (shouldRender) { let renderedContent = renderer.render(); if (renderedContent != null) { if (typeof renderedContent === "string") { renderedContent = /** @type { TemplateResult } */ { _$litType$: 1, strings: EMPTY_STRINGS_ARRAY, values: [buffer_exports.Buffer.from(renderedContent)] }; } const hasShadowDOM = renderer.element.shadowRoot !== null; const instance = getTemplateInstance(renderedContent); if (hasShadowDOM) { instance.setAsRoot("shadow", renderer.renderStyles()); } else { instance.setAsRoot("light"); } result.push(resolveNodeValue(instance, this.tagName, options.includeHydrationMetadata ?? false)); } } return result; } }; var CustomElementClosePart = class { /** * Constructor * @param { string } tagName */ constructor(tagName) { this.tagName = tagName; this.type = partType.CUSTOMELEMENT_CLOSE; } /** * Retrieve resolved value and manage active custom element stack * @param { InternalRenderOptions } options * @returns { unknown } */ resolveValue(options) { if (options.customElementStack[options.customElementStack.length - 1] === this.tagName) { options.customElementStack.pop(); } else { } return EMPTY_STRING_BUFFER; } }; var MetadataPart = class { /** * Constructor * @param { string } tagName * @param { Buffer } value */ constructor(tagName, value) { this.type = partType.METADATA; this.tagName = tagName; this.value = value; } /** * Retrieve resolved value given passed "value" * @param { InternalRenderOptions } options * @returns { unknown } */ resolveValue(options) { return RE_RAW_TEXT_ELEMENT.test(this.tagName) || !options.includeHydrationMetadata ? EMPTY_STRING_BUFFER : this.value; } }; function resolveAttributeValue(value, tagName, data) { if (isDirectiveResult(value)) { const partInfo = { name: data.name, tagName, type: TYPE_TO_LIT_PART_TYPE[data.type] }; if (data.type === "attribute" && data.strings !== void 0 && data.length > 1) { partInfo.strings = data.strings.map((string) => string.toString()); } [, value] = resolveDirectiveValue(value, partInfo); } if (value === nothing) { return value; } if (data.type === "boolean") { return value ? "" : nothing; } else if (isPrimitive(value)) { const string = typeof value !== "string" ? String(value) : value; return escape(string, "attribute"); } else if (isBuffer(value)) { return value.toString(); } else { return String(value); } } function resolvePropertyValue(value, tagName, data) { if (isDirectiveResult(value)) { const partInfo = { name: data.name, tagName, type: TYPE_TO_LIT_PART_TYPE[data.type] }; if (data.strings !== void 0 && data.length > 1) { partInfo.strings = data.strings.map((string) => string.toString()); } [, value] = resolveDirectiveValue(value, partInfo); } return value; } function resolveNodeValue(value, tagName, withMetadata) { let valueIsDirective = false; if (isDirectiveResult(value)) { valueIsDirective = true; const [directiveName, result] = resolveDirectiveValue(value, { type: TYPE_TO_LIT_PART_TYPE["child"], tagName }); if (directiveName === "unsafeHTML" || directiveName === "unsafeSVG") { const strings = ( /** @type { TemplateResult } */ result.strings ); const buffer = buffer_exports.Buffer.from(strings[0]); return withMetadata ? [buffer_exports.Buffer.from(`<!--lit-child ${digestForTemplateStrings(strings)}-->`), buffer, META_CHILD_CLOSE] : buffer; } else { value = result; } } if (value === nothing || value == null) { value = SPACE_STRING_BUFFER; } if (isPrimitive(value)) { let string = typeof value !== "string" ? String(value) : value; string = escape(string, tagName === "script" || tagName === "style" ? tagName : "text"); value = buffer_exports.Buffer.from(string); } if (isBuffer(value)) { return withMetadata ? [META_CHILD_OPEN, value, META_CHILD_CLOSE] : value; } else if (isTemplateInstanceOrResult(value)) { return value; } else if (isPromise(value)) { if (!valueIsDirective && withMetadata) { throw Error( `lit-html does not support interpolation of Promises, and these will not be rendered correctly in the browser. Use the "until" directive instead.` ); } return value.then((value2) => resolveNodeValue(value2, tagName, withMetadata)); } else if (isSyncIterator(value)) { if (!isArray(value)) { value = Array.from(value); } const collection = withMetadata ? [META_CHILD_OPEN] : []; for ( let val of /** @type { Array<unknown> } */ value ) { val = resolveNodeValue(val, tagName, withMetadata); if (isArray(val)) { collection.push(...val); } else { collection.push(val); } } if (withMetadata) { collection.push(META_CHILD_CLOSE); } return collection; } else if (isAsyncIterator(value)) { if (!valueIsDirective && withMetadata) { throw Error( `lit-html does not support interpolation of AsyncIterators, and these will not be rendered correctly in the browser. Use the "async-*" directives instead.` ); } return resolveAsyncIteratorValue(value, tagName, withMetadata); } else { throw Error(`unknown NodePart value: ${value}`); } } async function* resolveAsyncIteratorValue(iterator, tagName, withMetadata) { for await (const value of iterator) { yield resolveNodeValue(value, tagName, withMetadata); } } function resolveDirectiveValue(directiveResult, partInfo) { const Ctor = directiveResult._$litDirective$; const { directiveName } = Ctor; const directive = new Ctor(partInfo); let result = directive.render(...directiveResult.values); if (result === noChange) { result = EMPTY_STRING_BUFFER; } return [directiveName, result]; } function setRendererPropertyOrAttribute(renderer, name, value) { if (name.startsWith(".")) { renderer.setProperty(name.slice(1), value); } else if (name.startsWith("?")) { renderer.setAttribute(name.slice(1), value); } else { renderer.setAttribute(name, value); } } // src/internal/template.js var HTML_TAGS_WITH_HYPHENS = /* @__PURE__ */ new Set([ "annotation-xml", "color-profile", "font-face", "font-face-src", "font-face-uri", "font-face-format", "font-face-name", "missing-glyph" ]); var RE_TAG = /<(?:(?<commentStart>!--|\/[^a-zA-Z])|(?<tagName>\/?[a-zA-Z][^>\s]*)|(?<dynamicTagName>\/?$))/g; var RE_TAG_END = />/g; var RE_ATTR = />|[ \t\n\f\r](?:(?<attributeName>[^\s"'>=/]+)(?:(?<spacesAndEquals>[ \t\n\f\r]*=[ \t\n\f\r]*)(?<quoteChar>["'])?)?|$)/g; var RE_COMMENT_END = /-->/g; var RE_COMMENT_ALT_END = />/g; var RE_CUSTOM_ELEMENT = /^[a-z][a-z0-9._\p{Emoji_Presentation}-]*-[a-z0-9._\p{Emoji_Presentation}-]*$/u; var RE_SINGLE_QUOTED_ATTR_VALUE = /^(?<attributeValue>[^'\n\f\r]*)(?:(?<closingChar>')|$)/; var RE_DOUBLE_QUOTED_ATTR_VALUE = /^(?<attributeValue>[^"\n\f\r]*)(?:(?<closingChar>")|$)/; var RE_UNQUOTED_ATTR_VALUE = /^(?<attributeValue>[^'"=<>` \t\n\f\r]+)/; var TEXT = 1; var ATTRIBUTE = 2; var COMMENT = 3; function getTemplate(strings) { return new Template(strings); } var Template = class { /** * Constructor * @param { TemplateStringsArray } strings */ constructor(strings) { this.digest = digestForTemplateStrings(strings); this.strings = []; this.parts = []; this._parse(strings); } /** * Prepare the template's static strings, * and create Part instances for the dynamic values, * based on lit-html syntax. * @param { TemplateStringsArray } strings */ _parse(strings) { let attributePart; let isOpeningCustomElement = false; let mode = TEXT; let n = strings.length; let nextString = strings[0]; let regex = RE_TAG; let tagName = ""; for (let i = 0; i < n; i++) { const isLastString = i === n - 1; let string = nextString; nextString = strings[i + 1] ?? ""; let lastIndex = 0; let match; while (lastIndex < string.length) { regex.lastIndex = lastIndex; match = regex.exec(string); if (match === null) { break; } lastIndex = regex.lastIndex; if (mode === TEXT) { const groups = ( /** @type { RegexTagGroups } */ match.groups ); if (groups.commentStart === "!--") { mode = COMMENT; regex = RE_COMMENT_END; } else if (groups.commentStart !== void 0) { mode = COMMENT; regex = RE_COMMENT_ALT_END; } else { const isDynamicTagName = groups.dynamicTagName !== void 0; const rawTagName = ( /** @type { string } */ isDynamicTagName ? groups.dynamicTagName : groups.tagName ); const isOpeningTag = rawTagName[0] !== "/"; const isClosingCustomElement = !isOpeningTag && isCustomElementTagName(rawTagName.slice(1)); isOpeningCustomElement = isCustomElementTagName(rawTagName); mode = ATTRIBUTE; regex = RE_ATTR; if (isOpeningTag) { tagName = rawTagName; if (isOpeningCustomElement) { attributePart = new CustomElementOpenPart(tagName); } else { RE_TAG_END.lastIndex = lastIndex; if (RE_TAG_END.exec(string) !== null) { lastIndex = RE_TAG_END.lastIndex - 1; } else { attributePart = new AttributePart(tagName); } } if (attributePart !== void 0) { this.strings.push(buffer_exports.Buffer.from(string.slice(0, lastIndex))); string = string.slice(lastIndex); lastIndex = 0; this.parts.push(attributePart); } } else if (isClosingCustomElement) { this.strings.push(buffer_exports.Buffer.from(string.slice(0, lastIndex))); string = string.slice(lastIndex); lastIndex = 0; this.parts.push(new CustomElementClosePart(tagName)); } if (isDynamicTagName) { } } } else if (mode === ATTRIBUTE) { const groups = ( /** @type { RegexAttrGroups } */ match.groups ); if (match[0] === ">") { if (isOpeningCustomElement) { string = string.slice(lastIndex); lastIndex = 0; } else if (attributePart !== void 0) { this.strings.push(buffer_exports.Buffer.from(">")); this.parts.push(new MetadataPart(tagName, buffer_exports.Buffer.from(`<!--lit-attr ${attributePart.length}-->`))); string = string.slice(lastIndex); lastIndex = 0; } attributePart = void 0; mode = TEXT; regex = RE_TAG; } else if (attributePart !== void 0) { if (groups.attributeName === void 0) { attributePart.addAttributeData("element"); } else { const attributeName = groups.attributeName; if (groups.spacesAndEquals === void 0) { attributePart.addAttributeData("boolean", attributeName, ""); } else { const hasQuotes = groups.quoteChar !== void 0; let valueString = string.slice(lastIndex); if (!hasQuotes) { const valueMatch = RE_UNQUOTED_ATTR_VALUE.exec(valueString); const attributeValue = (valueMatch == null ? void 0 : valueMatch.groups.attributeValue) ?? ""; if (attributeValue !== "") { attributePart.addAttributeData("attribute", attributeName, attributeValue); } else { attributePart.addAttributeData(getAttributeTypeFromName(attributeName), attributeName, void 0, [ "", "" ]); } } else { const attributeStrings = []; const quoteChar = ( /** @type { string } */ groups.quoteChar ); const valueRegex = quoteChar === '"' ? RE_DOUBLE_QUOTED_ATTR_VALUE : RE_SINGLE_QUOTED_ATTR_VALUE; let j = 0; while (valueString !== void 0) { const valueMatch = valueRegex.exec(valueString); if (valueMatch === null) { break; } lastIndex += valueMatch[0].length; const { attributeValue = "", closingChar } = ( /** @type { RegexAttrValueGroups } */ valueMatch.groups ); if (closingChar !== void 0) { if (j === 0) { attributePart.addAttributeData("attribute", attributeName, attributeValue); } else { attributeStrings.push(attributeValue); i += j - 1; nextString = valueString.slice(valueMatch[0].length - 1); } break; } attributeStrings.push(attributeValue); valueString = strings[i + ++j]; } if (attributeStrings.length > 0) { attributePart.addAttributeData( getAttributeTypeFromName(attributeName), attributeName, void 0, attributeStrings ); } } } } } } else if (mode === COMMENT) { mode = TEXT; regex = RE_TAG; } } if (mode !== ATTRIBUTE) { this.strings.push(buffer_exports.Buffer.from(string)); if (mode === TEXT) { if (!isLastString) { this.parts.push(new ChildPart(tagName)); } } else if (mode === COMMENT) { throw Error("parsing expressions inside comment tags is not supported!"); } } } } }; function isCustomElementTagName(tagName) { return !HTML_TAGS_WITH_HYPHENS.has(tagName) && RE_CUSTOM_ELEMENT.test(tagName); } // src/internal/template-instance.js var templateCache = /* @__PURE__ */ new Map(); var id = 0; function getTemplateInstance(result) { const strings = result.strings; let template = templateCache.get(strings); if (template === void 0) { template = getTemplate(strings); templateCache.set(strings, template); } return new TemplateInstance(template, result.values); } var TemplateInstance = class { /** * Constructor * @param { Template } template * @param { Array<unknown> } values * @param { boolean } [hydratable] */ constructor(template, values, hydratable = false) { this._$litServerTemplateInstance$ = true; this.hydratable = hydratable; this.id = id++; this.index = 0; this.maxIndex = template.strings.length + template.parts.length - 1; this.prefix = buffer_exports.Buffer.from(`<!--lit-child ${template.digest}-->`); this.suffix = META_CHILD_CLOSE; this.template = template; this.valueIndex = 0; this.values = values; } /** * Set as root instance. * If a `shadow` root, add optional styles. * @param { 'light' | 'shadow' } [type] * @param { string } [styles] */ setAsRoot(type = "light", styles = "") { const litOpen = `<!--lit ${this.template.digest}-->`; if (type === "light") { this.prefix = buffer_exports.Buffer.from(litOpen); this.suffix = META_CLOSE; } else { const resolvedStyles = styles ? `<style>${styles}</style>`.replace(/[\n\s]/g, "") : ""; this.prefix = buffer_exports.Buffer.from(`<template shadowroot="open">${resolvedStyles}${litOpen}`); this.suffix = META_CLOSE_SHADOW; } } /** * Consume template result content one chunk at a time. * @param { InternalRenderOptions } options * @returns { unknown } */ readChunk(options) { const index = this.index / 2 | 0; const isString = this.index % 2 === 0; const isFirstString = this.index === 0; const isLastString = this.index === this.maxIndex; const withMetadata = options == null ? void 0 : options.includeHydrationMetadata; if (!isString && this.index >= this.maxIndex) { this.index = 0; this.valueIndex = 0; return null; } this.index++; if (isString) { let string = this.template.strings[index]; if (withMetadata) { if (isFirstString) { string = buffer_exports.Buffer.concat([this.prefix, string]); } if (isLastString) { string = buffer_exports.Buffer.concat([string, this.suffix]); } } return string; } const part = this.template.parts[index]; if (isAttributePart(part) || isCustomElementOpenPart(part)) { const length = part.length; const values = this.values.slice(this.valueIndex, this.valueIndex + length); const value = part.resolveValue(values, options); this.valueIndex += length; return value; } else if (isChildPart(part)) { const value = part.resolveValue(this.values[this.valueIndex], options); this.valueIndex++; return value; } else if (isMetadataPart(part) || isCustomElementClosePart(part)) { return part.resolveValue(options); } else { this.valueIndex++; throw Error(`unknown part: ${part}`); } } }; // src/lit-html-server.js import { html } from "@popeindustries/lit-html"; // src/internal/render-processor.js function getProcessor(renderer, stack, highWaterMark = 0, options = { customElementStack: [] }) { const buffer = []; let bufferLength = 0; let processing = false; function flushBuffer() { if (buffer.length > 0) { const keepPushing = renderer.push(buffer_exports.Buffer.concat(buffer, bufferLength)); bufferLength = buffer.length = 0; return keepPushing; } } return function process() { if (processing) { return; } while (true) { processing = true; let chunk = stack[0]; let breakLoop = false; let popStack = true; if (chunk === void 0) { flushBuffer(); return renderer.push(null); } if (isTemplateInstanceOrResult(chunk)) { popStack = false; chunk = getTemplateInstanceChunk(chunk, stack, options); } if (chunk !== null) { if (isBuffer(chunk)) { buffer.push(chunk); bufferLength += chunk.length; if (bufferLength > highWaterMark) { breakLoop = !flushBuffer(); processing = !breakLoop; } } else if (isPromise(chunk)) { flushBuffer(); breakLoop = true; stack.unshift(chunk); chunk.then((chunk2) => { if (isIteratorResult(chunk2)) { if (chunk2.done) { stack.shift(); stack.shift(); } else { stack[0] = chunk2.value; } } else { stack[0] = chunk2; } processing = false; process(); }).catch((err) => { stack.length = 0; renderer.destroy(err); }); } else if (isArray(chunk)) { if (stack[0] === chunk) { popStack = false; stack.shift(); } stack.unshift(...chunk); } else if (isAsyncIterator(chunk)) { popStack = false; if (stack[0] !== chunk) { stack.unshift(chunk); } stack.unshift(chunk[Symbol.asyncIterator]().next()); } else { stack.length = 0; return renderer.destroy(Error(`unknown chunk type: ${chunk}`)); } } if (popStack) { stack.shift(); } if (breakLoop) { break; } } }; } function getTemplateInstanceChunk(instance, stack, options) { if (isTemplateResult(instance)) { instance = getTemplateInstance(instance); stack[0] = instance; } if (instance.hydratable && !options.includeHydrationMetadata) { options.includeHydrationMetadata = true; options.hydrationMetadataRootId = instance.id; } let chunk = instance.readChunk(options); if (chunk === null) { if (options.hydrationMetadataRootId === instance.id) { options.includeHydrationMetadata = false; options.hydrationMetadataRootId = void 0; } stack.shift(); } else if (isTemplateInstanceOrResult(chunk)) { stack.unshift(chunk); chunk = getTemplateInstanceChunk(chunk, stack, options); } return chunk; } // src/internal/node-stream-template-renderer.js import { Readable } from "node:stream"; function nodeStreamTemplateRenderer(result, options) { return new NodeStreamTemplateRenderer(result, options); } var NodeStreamTemplateRenderer = class extends Readable { /** * Constructor * @param { TemplateInstance } result - a template result returned from call to "html`...`" * @param { InternalRenderOptions } [options] */ constructor(result, options) { super({ autoDestroy: true }); this.stack = [result]; this.process = getProcessor(this, this.stack, 16384, options); } /** * Extend Readable.read() */ _read() { if (this.process !== void 0) { this.process(); } } /** * Extend Readalbe.destroy() * @param { Error | null } [err] */ _destroy(err) { if (err) { this.emit("error", err); } this.emit("close"); this.process = void 0; this.stack = void 0; this.removeAllListeners(); } }; // src/internal/promise-template-renderer.js function promiseTemplateRenderer(result, asBuffer = false, options) { return new Promise((resolve, reject) => { let stack = [result]; let buffer = []; let bufferLength = 0; getProcessor( { /** @param { Buffer | null } chunk */ push(chunk) { if (chunk === null) { const concatBuffer = buffer_exports.Buffer.concat(buffer, bufferLength); resolve(asBuffer ? concatBuffer : concatBuffer.toString()); } else { buffer.push(chunk); bufferLength += chunk.length; } return true; }, /** @param { Error } err */ destroy(err) { buffer.length = stack.length = bufferLength = 0; buffer = void 0; stack = void 0; reject(err); } }, stack, 0, options )(); }); } // src/internal/web-stream-template-renderer.js function webStreamTemplateRenderer(result, options) { if (typeof ReadableStream === "undefined") { throw Error("ReadableStream not supported on this platform"); } if (typeof TextEncoder === "undefined") { throw Error("TextEncoder not supported on this platform"); } const underlyingSource = { process: () => { }, start(controller) { const encoder = new TextEncoder(); let stack = [result]; this.process = getProcessor( { /** @param { Buffer | null } chunk */ push(chunk) { if (chunk === null) { controller.close(); return false; } controller.enqueue(encoder.encode(chunk.toString())); return controller.desiredSize != null ? controller.desiredSize > 0 : true; }, /** @param { Error } err */ destroy(err) { controller.error(err); stack = void 0; } }, stack, 16384, options ); }, pull() { this.process(); } }; return new ReadableStream(underlyingSource); } // src/lit-html-server.js import { html as html2, noChange as noChange2, nothing as nothing2, svg } from "@popeindustries/lit-html"; function renderToNodeStream(result, options) { return nodeStreamTemplateRenderer(getRootTemplateInstance(result), { ...options, customElementStack: [] }); } function renderToWebStream(result, options) { return webStreamTemplateRenderer(getRootTemplateInstance(result), { ...options, customElementStack: [] }); } function renderToString(result, options) { return promiseTemplateRenderer(getRootTemplateInstance(result), false, { ...options, customElementStack: [] }); } function renderToBuffer(result, options) { return promiseTemplateRenderer(getRootTemplateInstance(result), true, { ...options, customElementStack: [] }); } function getRootTemplateInstance(result) { if (!isTemplateResult(result)) { result = html`${result}`; } const instance = getTemplateInstance( /** @type { TemplateResult } */ result ); instance.setAsRoot("light"); return instance; } export { getTemplateInstance as __internalGetTemplateInstance__, html2 as html, noChange2 as noChange, nothing2 as nothing, renderToBuffer, renderToNodeStream, renderToString, renderToWebStream, svg };