import { Callable, type GuardablePredicate, type JsonStructure, type Key, type array, type conform, type listable, type mutable, type requireKeys } from "@ark/util";
import type { BaseConstraint } from "./constraint.ts";
import type { Inner, NormalizedSchema, childKindOf, nodeOfKind, reducibleKindOf } from "./kinds.ts";
import type { BaseParseOptions } from "./parse.ts";
import type { Intersection } from "./roots/intersection.ts";
import type { Morph } from "./roots/morph.ts";
import type { BaseRoot } from "./roots/root.ts";
import type { Unit } from "./roots/unit.ts";
import type { BaseScope } from "./scope.ts";
import type { NodeCompiler } from "./shared/compile.ts";
import type { BaseNodeDeclaration, TypeMeta, attachmentsOf } from "./shared/declare.ts";
import type { ArkErrors } from "./shared/errors.ts";
import { type BasisKind, type NodeKind, type OpenNodeKind, type RefinementKind, type StructuralKind, type UnknownAttachments } from "./shared/implement.ts";
import { Traversal, type TraverseAllows, type TraverseApply } from "./shared/traversal.ts";
import type { UndeclaredKeyHandling } from "./structure/structure.ts";
export declare abstract class BaseNode<
/** @ts-ignore allow instantiation assignment to the base type */
out d extends BaseNodeDeclaration = BaseNodeDeclaration> extends Callable<(data: d["prerequisite"], ctx?: Traversal, onFail?: ArkErrors.Handler | null) => unknown, attachmentsOf<d>> {
    attachments: UnknownAttachments;
    $: BaseScope;
    onFail: ArkErrors.Handler | null;
    includesTransform: boolean;
    includesContextualPredicate: boolean;
    isCyclic: boolean;
    allowsRequiresContext: boolean;
    rootApplyStrategy: "allows" | "contextual" | "optimistic" | "branchedOptimistic";
    contextFreeMorph: ((data: unknown) => unknown) | undefined;
    rootApply: (data: unknown, onFail: ArkErrors.Handler | null) => unknown;
    referencesById: Record<string, BaseNode>;
    shallowReferences: BaseNode[];
    flatRefs: FlatRef[];
    flatMorphs: FlatRef<Morph.Node | Intersection.Node>[];
    allows: (data: d["prerequisite"]) => boolean;
    get shallowMorphs(): array<Morph>;
    constructor(attachments: UnknownAttachments, $: BaseScope);
    protected createRootApply(): this["rootApply"];
    abstract traverseAllows: TraverseAllows<d["prerequisite"]>;
    abstract traverseApply: TraverseApply<d["prerequisite"]>;
    abstract expression: string;
    abstract compile(js: NodeCompiler): void;
    readonly compiledMeta: string;
    protected cacheGetter<name extends keyof this>(name: name, value: this[name]): this[name];
    get description(): string;
    get references(): BaseNode[];
    readonly precedence: number;
    precompilation: string | undefined;
    assert: (data: d["prerequisite"], pipedFromCtx?: Traversal) => unknown;
    traverse(data: d["prerequisite"], pipedFromCtx?: Traversal): ArkErrors | {} | null | undefined;
    /** rawIn should be used internally instead */
    get in(): unknown;
    get rawIn(): BaseNode;
    /** rawOut should be used internally instead */
    get out(): unknown;
    get rawOut(): BaseNode;
    getIo(ioKind: "in" | "out"): BaseNode;
    toJSON(): JsonStructure;
    toString(): string;
    equals(r: unknown): boolean;
    ifEquals(r: unknown): BaseNode | undefined;
    hasKind<kind extends NodeKind>(kind: kind): this is nodeOfKind<kind>;
    assertHasKind<kind extends NodeKind>(kind: kind): nodeOfKind<kind>;
    hasKindIn<kinds extends NodeKind[]>(...kinds: kinds): this is nodeOfKind<kinds[number]>;
    assertHasKindIn<kinds extends NodeKind[]>(...kinds: kinds): nodeOfKind<kinds[number]>;
    isBasis(): this is nodeOfKind<BasisKind>;
    isConstraint(): this is BaseConstraint;
    isStructural(): this is nodeOfKind<StructuralKind>;
    isRefinement(): this is nodeOfKind<RefinementKind>;
    isRoot(): this is BaseRoot;
    isUnknown(): boolean;
    isNever(): boolean;
    hasUnit<value>(value: unknown): this is Unit.Node & {
        unit: value;
    };
    hasOpenIntersection(): this is nodeOfKind<OpenNodeKind>;
    get nestableExpression(): string;
    select<const selector extends NodeSelector.CompositeInput, predicate extends GuardablePredicate<NodeSelector.inferSelectKind<d["kind"], selector>>>(selector: NodeSelector.validateComposite<selector, predicate>): NodeSelector.infer<d["kind"], selector>;
    select<const selector extends NodeSelector.Single>(selector: selector): NodeSelector.infer<d["kind"], selector>;
    private _select;
    transform<mapper extends DeepNodeTransformation>(mapper: mapper, opts?: DeepNodeTransformOptions): nodeOfKind<reducibleKindOf<this["kind"]>> | Extract<ReturnType<mapper>, null>;
    protected _createTransformContext(opts: DeepNodeTransformOptions | undefined): DeepNodeTransformContext;
    protected _transform(mapper: DeepNodeTransformation, ctx: DeepNodeTransformContext): BaseNode | null;
    configureReferences(meta: TypeMeta.MappableInput.Internal, selector?: NodeSelector): this;
}
/** a literal key (named property) or a node (index signatures) representing part of a type structure */
export type KeyOrKeyNode = Key | BaseRoot;
export type GettableKeyOrNode = KeyOrKeyNode | number;
export type FlatRef<root extends BaseRoot = BaseRoot> = {
    path: array<KeyOrKeyNode>;
    node: root;
    propString: string;
};
export type NodeSelector = NodeSelector.Single | NodeSelector.Composite;
export declare namespace NodeSelector {
    type SelectableFn<input, returns, kind extends NodeKind = NodeKind> = {
        <const selector extends NodeSelector.CompositeInput, predicate extends GuardablePredicate<NodeSelector.inferSelectKind<kind, selector>>>(input: input, selector?: NodeSelector.validateComposite<selector, predicate>): returns;
        <const selector extends NodeSelector.Single>(input: input, selector?: selector): returns;
    };
    type Single = NodeSelector.Boundary | NodeSelector.Kind | GuardablePredicate<BaseNode>;
    type Boundary = "self" | "child" | "shallow" | "references";
    type Kind = NodeKind;
    type Method = "filter" | "assertFilter" | "find" | "assertFind";
    interface Composite {
        method?: Method;
        boundary?: Boundary;
        kind?: Kind;
        where?: GuardablePredicate<BaseNode>;
    }
    type Normalized = requireKeys<Composite, "method" | "boundary">;
    type CompositeInput = Omit<Composite, "where">;
    type BaseResult = BaseNode | BaseNode[] | undefined;
    type validateComposite<selector, predicate> = {
        [k in keyof selector]: k extends "where" ? predicate : conform<selector[k], CompositeInput[k & keyof CompositeInput]>;
    };
    type infer<selfKind extends NodeKind, selector> = applyMethod<selector extends NodeSelector.WhereCastInput<any, infer narrowed> ? narrowed : NodeSelector.inferSelectKind<selfKind, selector>, selector>;
    type BoundaryInput<b extends Boundary> = b | {
        boundary: b;
    };
    type KindInput<k extends Kind> = k | {
        kind: k;
    };
    type WhereCastInput<kindNode extends BaseNode, narrowed extends kindNode> = ((In: kindNode) => In is narrowed) | {
        where: (In: kindNode) => In is narrowed;
    };
    type inferSelectKind<selfKind extends NodeKind, selector> = selectKind<selfKind, selector> extends infer kind extends NodeKind ? NodeKind extends kind ? BaseNode : nodeOfKind<kind> : never;
    type selectKind<selfKind extends NodeKind, selector> = selector extends BoundaryInput<"self"> ? selfKind : selector extends KindInput<infer kind> ? kind : selector extends BoundaryInput<"child"> ? selfKind | childKindOf<selfKind> : NodeKind;
    type applyMethod<t, selector> = selector extends {
        method: infer method extends Method;
    } ? method extends "filter" ? t[] : method extends "assertFilter" ? [t, ...t[]] : method extends "find" ? t | undefined : method extends "assertFind" ? t : never : t[];
}
export declare const typePathToPropString: (path: array<KeyOrKeyNode>) => string;
export declare const flatRef: <node extends BaseRoot>(path: array<KeyOrKeyNode>, node: node) => FlatRef<node>;
export declare const flatRefsAreEqual: (l: FlatRef, r: FlatRef) => boolean;
export declare const appendUniqueFlatRefs: <node extends BaseRoot>(existing: FlatRef<node>[] | undefined, refs: listable<FlatRef<node>>) => FlatRef<node>[];
export declare const appendUniqueNodes: <node extends BaseNode>(existing: node[] | undefined, refs: listable<node>) => node[];
export type DeepNodeTransformOptions = {
    shouldTransform?: ShouldTransformFn;
    bindScope?: BaseScope;
    prereduced?: boolean;
    selected?: readonly BaseNode[] | undefined;
};
export type ShouldTransformFn = (node: BaseNode, ctx: DeepNodeTransformContext) => boolean;
export interface DeepNodeTransformContext extends DeepNodeTransformOptions {
    root: BaseNode;
    selected: readonly BaseNode[] | undefined;
    path: mutable<array<KeyOrKeyNode>>;
    seen: {
        [originalId: string]: (() => BaseNode | undefined) | undefined;
    };
    parseOptions: BaseParseOptions;
    undeclaredKeyHandling: UndeclaredKeyHandling | undefined;
}
export type DeepNodeTransformation = <kind extends NodeKind>(kind: kind, innerWithMeta: Inner<kind> & {
    meta: ArkEnv.meta;
}, ctx: DeepNodeTransformContext) => NormalizedSchema<kind> | null;
