import { types as t } from "@marko/compiler";
import { type Binding, BindingType, type Getter, type ReferencedBindings } from "./bindings";
import { type OneMany, type Opt, type SortedOpt } from "./optional";
import { type KnownExprs, type Reason } from "./reasons";
import { type Section } from "./sections";
interface ReferencedFunctionExtra extends t.FunctionExtra, ReferencedExtra {
}
export interface Read {
    binding: Binding;
    extra: t.NodeExtra;
    inOwnBody: boolean;
    getter: Getter | undefined;
    comparedTo: t.Node | undefined;
    deferred: boolean;
    /** The outermost function holding it; none when that escapes into a call. */
    fnRoot: ReferencedFunctionExtra | undefined;
}
export interface ResolvedRead {
    binding: Binding;
    props: Opt<string>;
    inOwnBody: boolean;
    getter: Getter | undefined;
    /** Set for same-section local reads: the function root that owns the read. */
    localFn?: ReferencedFunctionExtra;
}
declare const kReferencedBindings: unique symbol;
declare const kLazyBindings: unique symbol;
declare const kReferencedBindingsInFunction: unique symbol;
declare const kConstantBindingsInFunction: unique symbol;
declare module "@marko/compiler/dist/types" {
    interface ProgramExtra {
        /** An expression reads `$global`, so HTML output declares a const for it. */
        hasGlobalRead?: true;
    }
    interface MarkoTagExtra {
        /** The dom binding the tag is addressed by: its node or marker; an only
         * child control flow tag shares its parent's. */
        nodeBinding?: Binding;
    }
    interface MarkoPlaceholderExtra {
        /** The dom binding the placeholder's text node is held in. */
        nodeBinding?: Binding;
    }
    interface NodeExtra {
        section?: Section;
        [kReferencedBindings]?: ReferencedBindings;
        [kLazyBindings]?: ReferencedBindings;
        /** The bindings it derives, in the order it derives them: call sites
         * derive a child template's, so no one template's order sorts them. */
        derives?: Opt<Binding>;
        /** The initial value of the binding it derives, which keeps it rather than
         * following it, so the binding derives no sources from it. */
        initialValue?: true;
        /** Its value has no side effect to evaluate, so an unread one can go: an
         * expression's from `evaluate`, a tag's from its value attributes. */
        pure?: boolean;
        /** The tag-root `KnownExprs` of the call site that linked this expression
         * to a derives template's binding, for dereferencing its reasons. */
        callSiteExprs?: KnownExprs;
        binding?: Binding;
        assignment?: Binding;
        assignmentTo?: Binding;
        read?: ResolvedRead;
        dropped?: true;
        /** The expression this node sits in: dropped or merged as one. */
        exprRoot?: NodeExtra;
        isEffect?: true;
        /** Retained past render (a change handler, a native spread, a dynamic tag's
         * input), so client code may read a value here as it is, a function too. */
        retained?: true;
        /** Consumed where it is written (a handler its tag attaches, an
         * effect's callback, a key function), so it reaches no client as is. */
        consumed?: true;
        /** Any function it holds is only ever invoked, never read as a value, so
         * the reads inside resolve when it runs. */
        invokeOnly?: true;
        /** The bindings this expression reads only by spreading them as is. */
        spreadFrom?: SortedOpt<Binding>;
        /** A `content` it spreads is rendered (as the element's body, or as a
         * `<meta>`'s attribute), so its effect never reads it. */
        rendersContent?: true;
        merged?: NodeExtra;
    }
    interface FunctionExtra {
        referencesScope?: boolean;
        [kReferencedBindingsInFunction]?: ReferencedBindings;
        referencedLocalBindingsInFunction?: SortedOpt<Binding>;
        [kConstantBindingsInFunction]?: ReferencedBindings;
        name?: string;
        registerId?: string;
        /** When client code reads the function itself, which registers it. */
        reason?: Reason;
        exportRegisterId?: string;
    }
    interface ArrowFunctionExpressionExtra extends FunctionExtra {
    }
    interface FunctionDeclarationExtra extends FunctionExtra {
    }
    interface FunctionExpressionExtra extends FunctionExtra {
    }
}
export declare function isTagVarUsed(tag: t.NodePath<t.MarkoTag>): boolean;
export declare function trackDomVarReferences(tag: t.NodePath<t.MarkoTag>, binding: Binding): Binding | undefined;
export declare function trackVarReferences(tag: t.NodePath<t.MarkoTag>, type: BindingType, aliased?: Binding["aliasOf"]): Binding | undefined;
export declare function trackParamsReferences(body: t.NodePath<t.MarkoTagBody | t.Program>, type: BindingType): Binding | undefined;
export declare function isReferenceHoisted(bindingPath: t.NodePath, reference: t.NodePath): boolean;
export declare function assertReferencedInRender(ref: t.NodePath, name: string, markoRoot?: import("./get-root").MarkoRootPath | null): void;
export declare function setReferencesScope(path: t.NodePath<any>): void;
export declare function trackGlobalReference(path: t.NodePath<t.Identifier>): void;
export declare function mergeReferences<T extends t.Node>(section: Section, target: T, nodes: (t.Node | undefined)[]): NonNullable<T["extra"]> & ReferencedExtra;
export declare function mergeTagReferences(section: Section, tag: t.MarkoTag): t.MarkoTagExtra & t.NodeExtra & ReferencedExtra;
export declare function mergeReferenceGroup(section: Section, nodes: (t.Node | undefined)[]): ReferencedExtra;
export declare function setDerivedFrom(binding: Binding, expr: boolean | Opt<t.NodeExtra>, exprs?: KnownExprs): void;
export declare const getAssignments: () => AssignedBindingExtra[];
export declare const getReadsByExpression: () => Map<ReferencedExtra, Opt<Read>>;
export declare const getFunctionReadsByExpression: () => Map<ReferencedExtra, Map<ReferencedFunctionExtra, OneMany<Read>>>;
export declare const getReferenceFinalizers: () => (() => void)[];
export declare function onFinalizeReferences(finalize: () => void): void;
export declare function addRead(exprExtra: ReferencedExtra, extra: t.NodeExtra, binding: Binding, section: Section, getter: Getter | undefined): Read;
export declare function dropNodes(node: t.Node | t.Node[]): void;
export declare function dropExtra(exprExtra: ReferencedExtra): void;
export declare function dropContent(body: t.MarkoTagBody): void;
export declare function getAllTagReferenceNodes(tag: t.MarkoTag, referenceNodes?: t.Node[], collectAttrTag?: (attrTag: t.MarkoTag) => void): t.Node[];
export declare function createResolvedRead(binding: Binding, props: Opt<string>, inOwnBody?: boolean): ResolvedRead;
export declare function createResolvedGetterRead(binding: Binding, props: Opt<string>, getter: Getter): ResolvedRead;
export interface ReferencedExtra extends t.NodeExtra {
    section: Section;
}
export declare function isReferencedExtra(extra: t.NodeExtra | undefined): extra is ReferencedExtra;
export interface AssignedBindingExtra extends ReferencedExtra {
    assignment: Binding;
    exprRoot: t.NodeExtra;
    /** The outermost function holding it; none when that escapes into a call. */
    fnRoot: ReferencedFunctionExtra | undefined;
}
export declare function hasResumableAssignment(binding: Binding): boolean;
export declare function isAssignedBindingExtra(extra: t.NodeExtra | undefined): extra is AssignedBindingExtra;
export interface RegisteredFnExtra extends ReferencedExtra, t.FunctionExtra {
    exprRoot: t.NodeExtra;
    name: string;
    registerId: string;
    reason: Reason;
}
export declare function isRegisteredFnExtra(extra: t.NodeExtra | undefined): extra is RegisteredFnExtra;
export declare function getReferencedBindings(extra: t.NodeExtra | undefined): ReferencedBindings;
export declare function getBindingsDerivedFrom(binding: Binding): ReferencedBindings;
export declare function getValueReferences(exprs: Opt<t.NodeExtra>): ReferencedBindings;
export declare function getLazyBindings(extra: t.NodeExtra | undefined): ReferencedBindings;
export declare function getReferencedBindingsInFunction(extra: t.FunctionExtra): ReferencedBindings;
export declare function getConstantBindingsInFunction(extra: t.FunctionExtra): ReferencedBindings;
export declare function setResolvedFunctionReads(extra: t.FunctionExtra, referencedBindings: ReferencedBindings, constantBindings: ReferencedBindings): void;
export declare function setResolvedReads(extra: ReferencedExtra, referencedBindings: ReferencedBindings, lazyBindings: ReferencedBindings): void;
export declare function getCanonicalExtra<T extends t.NodeExtra>(extra: T): T;
export {};
