import { ReadonlyPath, type array } from "@ark/util";
import type { ResolvedConfig } from "../config.ts";
import type { Morph } from "../roots/morph.ts";
import { ArkError, ArkErrors, type ArkErrorCode, type ArkErrorInput, type NodeErrorContextInput } from "./errors.ts";
export type MorphsAtPath = {
    path: ReadonlyPath;
    morphs: array<Morph>;
};
export type BranchTraversal = {
    error: ArkError | undefined;
    queuedMorphs: MorphsAtPath[];
};
export type InternalTraversal = Omit<Traversal, "error" | "mustBe" | "reject">;
export declare class Traversal {
    /**
     * #### the path being validated or morphed
     *
     * ✅ array indices represented as numbers
     * ⚠️ mutated during traversal - use `path.slice(0)` to snapshot
     * 🔗 use {@link propString} for a stringified version
     */
    path: PropertyKey[];
    /**
     * #### {@link ArkErrors} that will be part of this traversal's finalized result
     *
     * ✅ will always be an empty array for a valid traversal
     */
    errors: ArkErrors;
    /**
     * #### the original value being traversed
     */
    root: unknown;
    /**
     * #### configuration for this traversal
     *
     * ✅ options can affect traversal results and error messages
     * ✅ defaults < global config < scope config
     * ✅ does not include options configured on individual types
     */
    config: ResolvedConfig;
    queuedMorphs: MorphsAtPath[];
    branches: BranchTraversal[];
    seen: {
        [id in string]?: unknown[];
    };
    constructor(root: unknown, config: ResolvedConfig);
    /**
     * #### the data being validated or morphed
     *
     * ✅ extracted from {@link root} at {@link path}
     */
    get data(): unknown;
    /**
     * #### a string representing {@link path}
     *
     * ✅ uses `.access` {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors#dot_notation | where allowed by JS}, falling back to `[indexAccess]`
     * @example
     * const path = ["key1", Symbol("key2"), "key3", 4, "~key5"]
     * const propString = 'key1[Symbol(key2)].key3[4]["~key5"]'
     */
    get propString(): string;
    /**
     * #### add an {@link ArkError} and return `false`
     *
     * ✅ useful for predicates like `.narrow`
     */
    reject(input: ArkErrorInput): false;
    /**
     * #### add an {@link ArkError} from a description and return `false`
     *
     * ✅ useful for predicates like `.narrow`
     * 🔗 equivalent to {@link reject}({ expected })
     */
    mustBe(expected: string): false;
    /**
     * #### add and return an {@link ArkError}
     *
     * ✅ useful for morphs like `.pipe`
     */
    error<input extends ArkErrorInput>(input: input): ArkError<input extends {
        code: ArkErrorCode;
    } ? input["code"] : "predicate">;
    /**
     * #### whether {@link currentBranch} (or the traversal root, outside a union) has one or more errors
     */
    hasError(): boolean;
    get currentBranch(): BranchTraversal | undefined;
    queueMorphs(morphs: array<Morph>): void;
    finalize(onFail?: ArkErrors.Handler | null): unknown;
    get currentErrorCount(): number;
    get failFast(): boolean;
    pushBranch(): void;
    popBranch(): BranchTraversal | undefined;
    /**
     * @internal
     * Convenience for casting from InternalTraversal to Traversal
     * for cases where the extra methods on the external type are expected, e.g.
     * a morph or predicate.
     */
    get external(): this;
    /**
     * @internal
     */
    errorFromNodeContext<input extends NodeErrorContextInput>(input: input): ArkError<input["code"]>;
    private errorFromContext;
    private applyQueuedMorphs;
    private applyMorphsAtPath;
}
export declare const traverseKey: <result>(key: PropertyKey, fn: () => result, ctx: InternalTraversal | undefined) => result;
export type TraversalMethodsByKind<input = unknown> = {
    Allows: TraverseAllows<input>;
    Apply: TraverseApply<input>;
    Optimistic: TraverseApply<input>;
};
export type TraversalKind = keyof TraversalMethodsByKind & {};
export type TraverseAllows<data = unknown> = (data: data, ctx: InternalTraversal) => boolean;
export type TraverseApply<data = unknown> = (data: data, ctx: InternalTraversal) => void;
