import { REACT_ELEMENT_TYPE, REACT_LEGACY_ELEMENT_TYPE, REACT_FRAGMENT_TYPE, type ReactNode, type ReactElement, } from '../core' import { REACT_SUSPENSE_TYPE, REACT_PROVIDER_TYPE, REACT_CONSUMER_TYPE, REACT_FORWARD_REF_TYPE, REACT_MEMO_TYPE, REACT_LAZY_TYPE, REACT_STRICT_MODE_TYPE, REACT_PROFILER_TYPE, REACT_PORTAL_TYPE, } from '../react' import { attrToHtml, escapeText, escapeScript, VOID_ELEMENTS, RAW_TEXT_ELEMENTS, } from './escape' import { pushContext, popContext, snapshotContexts, type ContextSnapshot, } from './dispatcher' export interface SuspendedBoundary { id: number fallbackHTML: string children: ReactNode thenable: Promise contextSnapshot: ContextSnapshot } export interface WalkOptions { emit: (chunk: string) => void onSuspend?: ((boundary: SuspendedBoundary) => void) | undefined nextBoundaryId: () => number bootstrapped?: boolean | undefined isBoundaryResolution?: boolean | undefined isSvg?: boolean | undefined /** * Tracks whether the most recent emission within the *current text flow* * ended with a text node. When the next emission is also text, we emit a * `` separator so the browser's HTML parser doesn't merge them * into a single text node — required for hydration to line up text * boundaries with the React tree. Reset to `false` whenever we enter a * new host element (`` opens a fresh text flow). */ textState?: { lastWasText: boolean } } /** * Synchronously walk a React node and emit HTML string pieces to `opts.emit`. * Suspended boundaries are emitted as fallbacks with marker IDs; if `opts.onSuspend` * is provided, the suspension is recorded for later streaming. */ export function walk(node: ReactNode, opts: WalkOptions): void { // Seed a text state if the caller didn't provide one so the separator logic // is active for the whole tree. if (!opts.textState) opts = { ...opts, textState: { lastWasText: false } } walkNode(node, opts) } // ---