import { parseFrontmatter } from "./frontmatter.js"; import type { ParsedFrontmatter } from "./frontmatter.js"; import type { VNode } from "./jsx-types.js"; export { parseFrontmatter }; export type { ParsedFrontmatter }; /** * One entry in an embedded content snapshot. Mirrors * `crates/zfb-content/src/content_bridge.rs::EntrySnapshot`. Re-exported * by `@takazudo/zfb-runtime/snapshot` for the runtime-side bundle. See * that module for field-by-field documentation. */ export interface SnapshotEntry { readonly slug: string; readonly frontmatter: unknown; readonly body: string; readonly module_specifier: string; readonly rel_path: string; /** * Render-artifact metadata, present only when the build ran with * `emitRenderArtifacts` on and only for markdown entries. Mirrors * `crates/zfb-content/src/render_metadata.rs::RenderRegionMetadata`. */ readonly render_metadata?: SnapshotRenderMetadata; } /** * `{ headings, source_digest }` for one content region. `source_digest` * is `"sha256:" + 64 hex` over the entry's RAW on-disk source bytes * (frontmatter included, no BOM strip, no CRLF normalization) — it * identifies the source, not the rendered output. See * `@takazudo/zfb-runtime/snapshot` for the full field documentation. */ export interface SnapshotRenderMetadata { readonly headings: readonly { readonly depth: number; readonly text: string; readonly slug: string; }[]; readonly source_digest: string; } /** * Point-in-time snapshot of every configured collection. Mirrors * `crates/zfb-content/src/content_bridge.rs::ContentSnapshot`. */ export interface Snapshot { readonly collections: Readonly>; } /** * Register a [`Snapshot`] so [`getCollection`] resolves from memory. * * Pass `undefined` to clear (used by tests that need to restore the v0 * filesystem path between runs). Idempotent: the latest call wins. * * Stored on `globalThis.__zfb.contentSnapshot` rather than a * module-level `let` so a worker bundle that ends up with two * `zfb/content` module instances still sees a single shared snapshot — * see the [`SnapshotBridgeNamespace`] doc above for the full * pnpm-symlink rationale. */ export declare function setContentSnapshot(snapshot: Snapshot | undefined): void; /** * Read the currently-installed [`Snapshot`], or `undefined` if none is * registered. Exposed mostly for tests; production callers should not * need to introspect the bridge state. * * Reads from `globalThis.__zfb.contentSnapshot`; see * [`setContentSnapshot`] for why the slot lives on `globalThis`. */ export declare function getContentSnapshot(): Snapshot | undefined; /** * Flat map of element-name → override component, used by both * [`ContentProps.components`] and the global slot * (`globalThis.__zfb?.mdxComponents`). Keys are lowercase HTML tag names * (`h2`, `p`, `a`, …) or PascalCase custom-component names. */ export type MdxComponents = Record; /** * Props accepted by an entry's [`CollectionEntry.Content`] component. * * `components` mirrors Astro's `` contract: * a flat record of element-name → override component (e.g. `{ h1: MyH1 }`). * The default-components convention ships from `zfb`'s root export * (`defaultComponents`, lands in Sub 6) and users compose with their own * via `{ ...defaultComponents, ...mine }`. */ export interface ContentProps { /** Element-name → override component map. Optional. */ components?: MdxComponents; } /** * Public JSX-element shape returned by [`CollectionEntry.Content`]. * * Matches the structural shape that both Preact's and React's `jsx-runtime` * accept on either side of the boundary, mirroring the Island wrapper's * approach. Consumers should treat this as opaque — its only contract is * "renderable JSX value". * * Aliased as `JSX.Element` in the field signature: the JS runtime is * type-erased and the actual VNode shape is supplied by the framework * adapter at evaluation time. */ export type ContentElement = { readonly type: string | ((...args: unknown[]) => unknown); readonly props: Readonly>; readonly key: unknown; }; /** * Generic shape returned for one entry in a content collection. The `data` * field carries parsed frontmatter, typed by the caller via the generic * parameter. */ export type CollectionEntry> = { /** Filename without `.md` extension. Stable across runs. */ slug: string; /** Parsed frontmatter. */ data: T; /** Raw markdown body (frontmatter stripped). */ body: string; /** * Stable module specifier used as the bridge lookup key. Format: * `mdx:///` (no hash component — the JS stub does * not compile MDX, so it has no body hash to attach; the production * Rust-side `zfb-content::collection::Entry::module_specifier` adds a * `#` suffix and the bridge is responsible for matching either * form against its registered components). * * This field is part of the v0+ JS surface so the bridge has something * deterministic to key on without consulting per-call state. */ module_specifier: string; /** * Renderable component for this entry. * * **Bridge contract.** At call time, `Content` consults * `globalThis.__zfb?.content?.get(entry.module_specifier)`. If the * bridge is present and returns a function, that function is invoked * with `props` and its result returned verbatim. * * **Fallback.** Outside the renderer (unit tests, dev sandboxes, or any * environment where `globalThis.__zfb.content.get` is absent or returns * `undefined`), `Content` returns a JSX-shaped element rendering the * raw markdown body inside a `
` block,
     * with a leading `[zfb fallback render]` marker line so the visual
     * distinction survives unstyled environments. The marker is also a
     * grep target for "did the production renderer not run?" diagnostics.
     *
     * **Typed signature.** Returns `ContentElement` (a structural alias for
     * `JSX.Element`) so consumers can drop ``
     * into both React and Preact JSX without per-framework type setup.
     *
     * @example
     *   const post = (await getCollection("blog"))[0];
     *   return ;
     */
    Content: (props: ContentProps) => ContentElement;
};
/**
 * Load every `*.md` file in the named collection. Files starting with `.`
 * or that lack a `.md` extension are ignored.
 *
 * **ADR-004 contract: this function is synchronous.** TSX page modules
 * call it from anywhere — top-level, inside a render body, inside a
 * `useMemo` — and SSR completes in a single pass without yielding. The
 * snapshot path returns from memory; the filesystem fallback uses sync
 * `node:fs` APIs so the surface stays unified. (The legacy async
 * implementation was an oversight — the ADR predates it; SSG paths
 * always saw a Promise where ADR-004 says they should see an array,
 * which is why migrations from Astro tripped on `getCollection().filter
 * is not a function`.)
 *
 * @example
 *   const posts = getCollection<{ title: string; date: string }>("blog");
 */
export declare function getCollection>(name: string): CollectionEntry[];
/**
 * Look up a single entry in a content collection by slug.
 *
 * Thin wrapper over [`getCollection`]: inherits both resolution paths
 * (snapshot via `globalThis.__zfb.contentSnapshot` and the `node:fs`
 * fallback) for free. Returns `undefined` when either the collection does
 * not exist or no entry matches `slug`.
 *
 * **Runtime vs. generated types divergence.** The generated `types.d.ts`
 * emits a keyed overload (`K extends keyof ZfbCollections`) that ties the
 * return type to the collection's declared schema. That schema is enforced
 * by `zfb check`; this runtime form is intentionally structural — it does
 * not reference `ZfbCollections` and does not attempt to reconcile with the
 * keyed shape. (#857)
 *
 * @example
 *   const post = getEntry<{ title: string }>("blog", "hello-zfb");
 *   if (!post) return null;
 *   return ;
 */
export declare function getEntry>(name: string, slug: string): CollectionEntry | undefined;
/**
 * @internal
 *
 * Convert a `path.relative()` result into a forward-slash-separated
 * slug with the trailing `.md` extension stripped.
 *
 * Slugs are URL-flavored identifiers, not filesystem paths — they
 * MUST use `/` regardless of the host OS so a nested entry like
 * `2024/hello.md` produces the slug `2024/hello` on both POSIX and
 * Windows. Without this normalisation, Windows callers would see
 * `2024\hello`, which then leaks through to `module_specifier` and
 * any URL the consumer derives from the slug.
 *
 * Exported solely so the unit test suite can pin the Windows
 * behaviour without needing an actual Windows host. Do not depend on
 * this from application code — name and signature may change.
 */
export declare function _relPathToSlug(relPath: string): string;
/**
 * Public JSX-element shape returned by every override in [`defaultComponents`].
 *
 * Mirrors [`ContentElement`] and [`IslandElement`]: a structural alias for
 * `JSX.Element` so consumers can drop these overrides into both React and
 * Preact JSX without per-framework type setup.
 */
export type ContentComponentElement = {
    readonly type: string;
    readonly props: Readonly>;
    readonly key: unknown;
};
/**
 * Props accepted by every default override. `children` and any extra
 * attributes (`className`, `id`, `href`, …) are passed through verbatim
 * to the underlying HTML element.
 */
export interface ContentComponentProps {
    children?: VNode;
    [key: string]: unknown;
}
/**
 * `

` passthrough override. Ported from zudo-doc's `HeadingH2`, stripped * of styling — v0 ships pass-through behaviour; visual treatment is layered * on by the consumer (or by a follow-up enhancement pass). */ export declare function ContentH2(props: ContentComponentProps): ContentComponentElement; /** `

` passthrough override. See [`ContentH2`] for the contract. */ export declare function ContentH3(props: ContentComponentProps): ContentComponentElement; /** `

` passthrough override. See [`ContentH2`] for the contract. */ export declare function ContentH4(props: ContentComponentProps): ContentComponentElement; /** `

` passthrough override. Mirrors zudo-doc's `ContentParagraph`. */ export declare function ContentParagraph(props: ContentComponentProps): ContentComponentElement; /** `` passthrough override. Mirrors zudo-doc's `ContentLink`. */ export declare function ContentLink(props: ContentComponentProps): ContentComponentElement; /** `` passthrough override. Mirrors zudo-doc's `ContentStrong`. */ export declare function ContentStrong(props: ContentComponentProps): ContentComponentElement; /** `

` passthrough override. Mirrors zudo-doc's `ContentBlockquote`. */ export declare function ContentBlockquote(props: ContentComponentProps): ContentComponentElement; /** `
    ` passthrough override. Mirrors zudo-doc's `ContentUl`. */ export declare function ContentUl(props: ContentComponentProps): ContentComponentElement; /** `
      ` passthrough override. Mirrors zudo-doc's `ContentOl`. */ export declare function ContentOl(props: ContentComponentProps): ContentComponentElement; /** `` passthrough override. Mirrors zudo-doc's `ContentTable`. */ export declare function ContentTable(props: ContentComponentProps): ContentComponentElement; /** `` passthrough override. Mirrors zudo-doc's `ContentCode`. */ export declare function ContentCode(props: ContentComponentProps): ContentComponentElement; /** * Default per-element override map — eleven entries covering the markdown * tags the zudo-doc convention overrides (`h2`, `h3`, `h4`, `p`, `a`, * `strong`, `blockquote`, `ul`, `ol`, `table`, `code`). * * `h1` is intentionally absent: page titles render from frontmatter, per * the zudo-doc convention. * * Spread into a `components` prop to compose with custom overrides: * * ```tsx * import { defaultComponents } from "zfb"; * * * ``` */ export declare const defaultComponents: { readonly h2: typeof ContentH2; readonly h3: typeof ContentH3; readonly h4: typeof ContentH4; readonly p: typeof ContentParagraph; readonly a: typeof ContentLink; readonly strong: typeof ContentStrong; readonly blockquote: typeof ContentBlockquote; readonly ul: typeof ContentUl; readonly ol: typeof ContentOl; readonly table: typeof ContentTable; readonly code: typeof ContentCode; }; /** * Merge component maps with the documented precedence order: * built-in `defaultComponents` → global slot (`globalThis.__zfb?.mdxComponents`) * → per-call `props.components`. * * Spread in stable key order so the resulting map is deterministic; later * entries in the spread win on collision (lowest → highest priority). Absent * layers (`undefined`) are no-ops via spread-of-undefined. * * **Output-neutral by design:** `defaultComponents` entries are pure * passthroughs (e.g. `ContentH2` → `

      {...props}

      `), so introducing * this merge into `buildContentComponent` does not change the rendered output. */ export declare function mergeMdxComponents(globalSlot: MdxComponents | undefined, perCall: MdxComponents | undefined): MdxComponents;