import type { Root as HastRoot } from 'hast';
/**
 * Compact serialization format for fallback HAST trees.
 *
 * A `FallbackNode` is either:
 * - a plain string (text node), or
 * - a variable-length tuple whose meaning is determined by length:
 *   - `[tagName, children]`                                – no class, no props
 *   - `[tagName, className, children]`                     – has class, no props
 *   - `[tagName, className, properties, children]`         – has class and props
 *   - `[tagName, className, properties, children, extra]`  – full
 *
 * Where:
 *   - `tagName`    – HTML element name (e.g. `'span'`, `'a'`)
 *   - `className`  – space-joined class string
 *   - `properties` – remaining HTML properties (without `className`)
 *   - `children`   – a single text string **or** an array of child `FallbackNode`s
 *   - `extra`      – optional bag for anything else (data attributes, etc.)
 *
 * This eliminates the repeated `type`, `tagName`, `properties`, `children`,
 * and `value` keys that make raw HAST costly in RSC payloads.
 */
export type FallbackNode = string | FallbackElement;
/**
 * A residual fallback that has been DEFLATE-compressed on its own. Mirrors the
 * `{ hastCompressed }` shape of `VariantSource`.
 *
 * Used for the parts of a variant's fallback that the `ContentLoading`
 * component never renders (extra files when the loading UI shows a single file,
 * extra variants when it shows a single variant). Those residual fallbacks
 * exist only as the DEFLATE dictionary for decompressing `hastCompressed`, so
 * shipping them as plain `FallbackNode[]` text would be dead weight in the
 * initial payload. They are compressed standalone — no preset text dictionary,
 * so the blob is self-contained — and decompressed back to `FallbackNode[]`
 * (via `decompressFallback`) only when the full content swaps in.
 */
export type CompressedFallback = {
  fallbackCompressed: string;
};
export type FallbackElement = [tagName: string, children: string | FallbackNode[]] | [tagName: string, className: string, children: string | FallbackNode[]] | [tagName: string, className: string, properties: Record<string, unknown>, children: string | FallbackNode[]] | [tagName: string, className: string, properties: Record<string, unknown>, children: string | FallbackNode[], extra: Record<string, unknown>];
/**
 * Convert a HAST root into the compact `FallbackNode[]` format.
 */
export declare function hastToFallback(root: HastRoot): FallbackNode[];
/**
 * Convert the compact `FallbackNode[]` format back into a HAST root.
 */
export declare function fallbackToHast(nodes: FallbackNode[]): HastRoot;
/**
 * Extract the text content from compact `FallbackNode[]` without
 * converting back to HAST. Used to build DEFLATE dictionaries.
 */
export declare function fallbackToText(nodes: FallbackNode[]): string;
/**
 * Builds the variant-level root fallback from a final (post-enhancer) HAST
 * root. Each `span.frame` becomes a compact frame element whose single text
 * child is the frame's precomputed plain text (`frame.data.fallback`), so the
 * result is directly renderable as the pre-hydration code block **and** can be
 * redistributed back onto the decoded HAST's frames (see
 * `redistributeRootFallback`).
 *
 * The frame's `data-lined` attribute is dropped (line spans don't exist in the
 * fallback) while other frame attributes (e.g. `data-frame-type`) are kept so
 * the fallback's layout matches the highlighted render. Non-frame top-level
 * nodes (e.g. whitespace text between frames) are preserved in place.
 */
export declare function buildRootFallback(root: HastRoot): FallbackNode[];
/**
 * Whether a compact `fallback` already carries highlighting — i.e. at least one frame
 * keeps nested token spans (array children) instead of flat plain text. True exactly for
 * the promoted {@link promoteCriticalFallback} form; a plain {@link buildRootFallback} has
 * a string child on every frame. `<Pre>` uses this to defer the decompressing decode ONLY
 * when the first paint is already highlighted, so it never flashes plain → highlighted.
 */
export declare function fallbackIsHighlighted(fallback: FallbackNode[]): boolean;
/**
 * The **sparse** highlighted-visible fallback: a map from frame index to the
 * highlighted `FallbackNode` for ONLY the frames visible on the initial collapsed
 * render (`visibleFrames`). Off-screen frames are omitted — they flatten to exactly
 * {@link buildRootFallback}'s plain output, so storing them would just duplicate
 * `fallback` in the precompute. {@link promoteCriticalFallback} splices these back
 * over the plain fallback for `highlightAt: 'init'` (paint highlighted on the first
 * render, zero decompression). Frame indices count `span.frame` children only,
 * matching `getInitialVisibleFrames`.
 *
 * The decoded `root` is shared/read-only; this only reads its frames (the synthetic
 * visible frame reuses the frame's `children` array without mutating it, and
 * `data-lined` is dropped via destructuring, not deletion).
 */
export declare function buildCriticalFallback(root: HastRoot, visibleFrames: {
  [key: number]: boolean;
}): {
  [frameIndex: number]: FallbackNode;
};
/**
 * Splice a sparse {@link buildCriticalFallback} diff back onto a plain `fallback`,
 * replacing each visible frame (matched by index in document order) with its
 * highlighted node. The result is the full highlighted-visible fallback; its text is
 * byte-identical to `fallback` (the highlight spans only wrap the same characters), so
 * it stays a valid DEFLATE dictionary — asserted by tests. Returns a new array; the
 * input is not mutated.
 */
export declare function promoteCriticalFallback(fallback: FallbackNode[], critical: {
  [frameIndex: number]: FallbackNode;
}): FallbackNode[];
/**
 * Redistributes a root fallback (built by `buildRootFallback`) back onto the
 * frames of a decoded HAST root, setting each frame's `data.fallback` to the
 * corresponding fallback frame's text nodes (as HAST, not the compact form).
 *
 * Frames align 1:1 by position because the root fallback and the decoded HAST
 * are both derived from the same final tree. Non-frame fallback entries (e.g.
 * inter-frame whitespace) advance the cursor without being assigned. Mutates
 * `root` in place and returns it.
 */
export declare function redistributeRootFallback(root: HastRoot, fallback: FallbackNode[]): HastRoot;
/**
 * Reduce a root fallback to the frames visible while the code block is
 * collapsed — the contiguous focused window (`padding-top`, `highlighted` /
 * `focus`, `padding-bottom`). Inter-frame nodes inside that window are kept so
 * the slice renders with the same spacing as the full fallback.
 *
 * Matches the runtime rule in `Pre.tsx`: when a block has no emphasis frames
 * (the whole source is the focused window) the first frame stands in. Returns
 * the input unchanged when it has no frames at all.
 *
 * When `collapsesToEmpty` is `true` the source records `focusedLines === 0`
 * (the `oversizedFocus: 'hide'` collapse-to-nothing case): the collapsed window
 * is intentionally empty, so the first-frame fallback is skipped and an empty
 * array is returned. Mirrors the runtime rule in `Pre.tsx` /
 * `getInitialVisibleSourceLines`.
 *
 * Used by `fallbackCollapsed` to paint only the on-screen lines while the
 * file's full fallback rides along compressed (see the prop-compression
 * pattern's "Splitting the Fallback by Visibility").
 */
export declare function collapsedVisibleFallback(fallback: FallbackNode[], collapsesToEmpty?: boolean): FallbackNode[];