import { type HastNode } from "./hast-materializer.js"; import type { HastRaw, Data } from "../types.js"; import type { Element, Text, Comment, Doctype, Parents as HastParents, Root as HastRoot } from "hast"; import type { Program } from "estree-jsx"; import type { MdxJsxFlowElementHast, MdxJsxTextElementHast } from "../mdx-types.js"; import type { MdxFlowExpressionHast, MdxTextExpressionHast } from "../mdx-types.js"; import type { MdxjsEsmHast } from "../mdx-types.js"; import type { HastHandle } from "../handles.js"; export type { HastHandle }; /** ESTree-compatible Program node returned by `parseExpression()`. */ export type EstreeProgram = Program; export interface HastDiagnostic { message: string; nodeId?: number | undefined; severity: "error" | "warning" | "info"; } export interface HastVisitorContext { readonly source: string; /** * The URL of the document being processed (the compile `fileURL` option), * or `undefined` when none was given. Use `fileURLToPath(ctx.fileURL)` for a * decoded filesystem path. */ readonly fileURL: URL | undefined; /** * Document-level data bag, shared across every plugin in the compile and * across the mdast→hast phase boundary. Mutate keys directly * (`ctx.data.foo = x`); the bag itself isn't reassignable. Values are kept * on the JS side, so any value is allowed, including functions and class * instances. Returned to the caller as `result.data`. */ readonly data: Data; removeNode(node: Readonly): void; replaceNode(node: Readonly, newNode: HastContent): void; insertBefore(node: Readonly, newNode: HastContent | HastContent[]): void; insertAfter(node: Readonly, newNode: HastContent | HastContent[]): void; /** * Wrap `node` in `parentNode`, making it `parentNode`'s first child. Any * children `parentNode` declares are kept after it, so a `div` with an anchor * child wraps a heading as `div > [heading, anchor]`. */ wrapNode(node: Readonly, parentNode: HastContent): void; prependChild(node: Readonly, childNode: HastContent | HastContent[]): void; appendChild(node: Readonly, childNode: HastContent | HastContent[]): void; /** Insert one node or an array at `index`; clamps (`0` or less prepends, past the end appends). */ insertChildAt(node: Readonly, index: number, childNode: HastContent | HastContent[]): void; /** Remove the `index`-th child of `node`; a no-op when there is no such child. */ removeChildAt(node: Readonly, index: number): void; setProperty(node: Readonly, key: string, value: unknown): void; /** Collect the concatenated text of all descendant text nodes (like DOM textContent). */ textContent(node: Readonly): string; /** * The parent of a node, or `undefined` at the root. Within a pass the same * parent is always the same object, so visitors on sibling nodes can dedupe * by identity. */ parent>(node: Readonly): Readonly; parent(node: Readonly): Readonly | undefined; /** * Index of `node` within its parent's children, or `undefined` at the root. * Use this rather than `parent.children.indexOf(node)`, which won't find it. */ indexOf(node: Readonly): number | undefined; report(opts: { message: string; node?: Readonly; severity?: "error" | "warning" | "info"; }): void; getDiagnostics(): HastDiagnostic[]; } /** New content for a HAST structural mutation. Unlike [`MdastContent`], HAST has * a `raw` node type, so it needs no raw/rawHtml escape hatch. */ export type HastContent = HastNode; /** A filtered visitor: Rust filters by tag/component name, only matched nodes cross the boundary. */ export interface HastFilteredVisitor { filter: string[]; visit(node: Readonly, ctx: HastVisitorContext): HastNode | void | Promise; } type HastVisitorFn = (node: Readonly, ctx: HastVisitorContext) => HastNode | void | Promise; export interface HastVisitorInstance { element?: HastFilteredVisitor | HastFilteredVisitor[]; mdxJsxFlowElement?: HastFilteredVisitor | HastFilteredVisitor[]; mdxJsxTextElement?: HastFilteredVisitor | HastFilteredVisitor[]; text?: HastVisitorFn; comment?: HastVisitorFn; raw?: HastVisitorFn; doctype?: HastVisitorFn; mdxFlowExpression?: HastVisitorFn; mdxTextExpression?: HastVisitorFn; mdxjsEsm?: HastVisitorFn; } interface ResolvedSubscription { nodeType: number; tagFilter: string[]; visitFn: (node: HastNode, ctx: HastVisitorContext) => HastNode | void; } export declare function resolveSubscriptions(plugin: HastVisitorInstance): ResolvedSubscription[]; /** * Walk a handle's arena in Rust, dispatch matched nodes to JS visitor functions, * and apply mutations back to the handle. No arena buffers cross NAPI. * * Returns the number of patches dropped because their target was removed or * replaced earlier in the same pass (the caller warns when non-zero), or a * Promise of that count if any visitor is async. */ export declare function visitHastHandle(handle: HastHandle, plugin: HastVisitorInstance, subs: ResolvedSubscription[], source: string | (() => string), fileURL: URL | undefined, data?: Data): number | Promise;