import { HtmlEscapedCallbackPhase, raw, resolveCallback } from "../utils/html.js";
import { DOM_RENDERER, DOM_STASH } from "./constants.js";
import { captureRenderContext, createContext, useContext } from "./context.js";
import { JSXNode, isUntrustedObject, renderChildren, renderUntrustedObject } from "./base.js";
import { buildDataStack } from "./dom/render.js";
import { Suspense as Suspense$1 } from "./dom/components.js";
import { childrenToString } from "./components.js";
//#region src/jsx/streaming.ts
/**
* @module
* This module enables JSX to supports streaming Response.
*/
/**
* Used to specify nonce for scripts generated by `Suspense` and `ErrorBoundary`.
*
* @example
* ```tsx
*
* Loading...
}>
*
*
*
* ```
*/
const StreamingContext = createContext(null);
let suspenseCounter = 0;
const serializeBoundaryChild = (child) => typeof child === "string" || Array.isArray(child) ? renderChildren([child]) : child == null || typeof child === "boolean" ? "" : isUntrustedObject(child) ? renderUntrustedObject(child) : child.toString();
/**
* @experimental
* `Suspense` is an experimental feature.
* The API might be changed.
*/
const Suspense = async ({ children, fallback }) => {
if (!Array.isArray(children)) children = [children];
const nonce = useContext(StreamingContext)?.scriptNonce;
let resArray = [];
const stackNode = { [DOM_STASH]: [0, []] };
const popNodeStack = () => {
buildDataStack.pop();
};
try {
stackNode[DOM_STASH][0] = 0;
buildDataStack.push([[], stackNode]);
resArray = children.map(serializeBoundaryChild);
} catch (e) {
if (e instanceof Promise) {
const resume = captureRenderContext();
resArray = [e.then(() => resume(() => {
stackNode[DOM_STASH][0] = 0;
buildDataStack.push([[], stackNode]);
return childrenToString(children).finally(popNodeStack);
}))];
} else throw e;
} finally {
popNodeStack();
}
if (resArray.some((res) => res instanceof Promise)) {
const index = suspenseCounter++;
const fallbackStr = await (typeof fallback === "string" || Array.isArray(fallback) ? renderChildren([fallback]) : isUntrustedObject(fallback) ? renderUntrustedObject(fallback) : fallback.toString());
return raw(`${fallbackStr}`, [...fallbackStr.callbacks || [], ({ phase, buffer, context }) => {
if (phase === HtmlEscapedCallbackPhase.BeforeStream) return;
return Promise.all(resArray).then(async (htmlArray) => {
htmlArray = htmlArray.flat();
const content = htmlArray.join("");
if (buffer) buffer[0] = buffer[0].replace(new RegExp(`.*?`, "s"), () => content);
let html = buffer ? "" : `${content}