import ts from "typescript";
import { MetadataCollection } from "../factories/MetadataCollection";
import { Metadata } from "../schemas/metadata/Metadata";
import { MetadataArray } from "../schemas/metadata/MetadataArray";
import { MetadataObjectType } from "../schemas/metadata/MetadataObjectType";
import { ITypiaContext } from "../transformers/ITypiaContext";
import { CheckerProgrammer } from "./CheckerProgrammer";
import { FunctionProgrammer } from "./helpers/FunctionProgrammer";
import { IExpressionEntry } from "./helpers/IExpressionEntry";
export declare namespace FeatureProgrammer {
    interface IConfig<Output extends ts.ConciseBody = ts.ConciseBody> {
        types: IConfig.ITypes;
        /**
         * Prefix name of internal functions for specific types.
         */
        prefix: string;
        /**
         * Whether to archive access path or not.
         */
        path: boolean;
        /**
         * Whether to trace exception or not.
         */
        trace: boolean;
        addition?: undefined | ((collection: MetadataCollection) => ts.Statement[]);
        /**
         * Initializer of metadata.
         */
        initializer: (props: {
            context: ITypiaContext;
            functor: FunctionProgrammer;
            type: ts.Type;
        }) => {
            collection: MetadataCollection;
            metadata: Metadata;
        };
        /**
         * Decoder, station of every types.
         */
        decoder: (props: {
            metadata: Metadata;
            input: ts.Expression;
            explore: IExplore;
        }) => Output;
        /**
         * Object configurator.
         */
        objector: IConfig.IObjector<Output>;
        /**
         * Generator of functions for object types.
         */
        generator: IConfig.IGenerator;
    }
    namespace IConfig {
        interface ITypes {
            input: (type: ts.Type, name?: undefined | string) => ts.TypeNode;
            output: (type: ts.Type, name?: undefined | string) => ts.TypeNode;
        }
        interface IObjector<Output extends ts.ConciseBody = ts.ConciseBody> {
            /**
             * Type checker when union object type comes.
             */
            checker: (props: {
                metadata: Metadata;
                input: ts.Expression;
                explore: IExplore;
            }) => ts.Expression;
            /**
             * Decoder, function call expression generator of specific typed objects.
             */
            decoder: (props: {
                input: ts.Expression;
                object: MetadataObjectType;
                explore: IExplore;
            }) => ts.Expression;
            /**
             * Joiner of expressions from properties.
             */
            joiner(props: {
                entries: IExpressionEntry<Output>[];
                input?: ts.Expression;
                object?: MetadataObjectType;
            }): ts.ConciseBody;
            /**
             * Union type specificator.
             *
             * Expression of an algorithm specifying object type and calling
             * the `decoder` function of the specified object type.
             */
            unionizer: (props: {
                objects: MetadataObjectType[];
                input: ts.Expression;
                explore: IExplore;
            }) => ts.Expression;
            /**
             * Handler of union type specification failure.
             *
             * @param props Properties of failure
             * @returns Statement of failure
             */
            failure(props: {
                input: ts.Expression;
                expected: string;
                explore?: undefined | IExplore;
            }): ts.Statement;
            /**
             * Transformer of type checking expression by discrimination.
             *
             * When an object type has been specified by a discrimination without full
             * iteration, the `unionizer` will decode the object instance after
             * the last type checking.
             *
             * In such circumtance, you can transform the last type checking function.
             *
             * @param exp Current expression about type checking
             * @returns Transformed expression
             * @deprecated
             */
            is?: undefined | ((exp: ts.Expression) => ts.Expression);
            /**
             * Transformer of non-undefined type checking by discrimination.
             *
             * When specifying an union type of objects, `typia` tries to find
             * descrimination way just by checking only one property type.
             * If succeeded to find the discrimination way, `typia` will check the target
             * property type and in the checking, non-undefined type checking would be
             * done.
             *
             * In such process, you can transform the non-undefined type checking.
             *
             * @param exp
             * @returns Transformed expression
             * @deprecated
             */
            required?: undefined | ((exp: ts.Expression) => ts.Expression);
            /**
             * Conditon wrapper when unable to specify any object type.
             *
             * When failed to specify an object type through discrimination, full
             * iteration type checking would be happend. In such circumstance, you
             * can wrap the condition with additional function.
             *
             * @param props Properties of condition
             * @returns The wrapper expression
             */
            full?: undefined | ((props: {
                condition: ts.Expression;
                input: ts.Expression;
                expected: string;
                explore: IExplore;
            }) => ts.Expression);
            /**
             * Return type.
             */
            type?: undefined | ts.TypeNode;
        }
        interface IGenerator {
            objects?: undefined | ((collection: MetadataCollection) => ts.VariableStatement[]);
            unions?: undefined | ((collection: MetadataCollection) => ts.VariableStatement[]);
            arrays: (collection: MetadataCollection) => ts.VariableStatement[];
            tuples: (collection: MetadataCollection) => ts.VariableStatement[];
        }
    }
    interface IExplore {
        tracable: boolean;
        source: "top" | "function";
        from: "top" | "array" | "object";
        postfix: string;
        start?: undefined | number;
    }
    type Decoder<T, Output extends ts.ConciseBody = ts.ConciseBody> = (props: {
        input: ts.Expression;
        definition: T;
        explore: IExplore;
    }) => Output;
    interface IComposed {
        body: ts.ConciseBody;
        parameters: ts.ParameterDeclaration[];
        functions: Record<string, ts.VariableStatement>;
        statements: ts.Statement[];
        response: ts.TypeNode;
    }
    interface IDecomposed {
        functions: Record<string, ts.VariableStatement>;
        statements: ts.Statement[];
        arrow: ts.ArrowFunction;
    }
    const compose: (props: {
        context: ITypiaContext;
        config: IConfig;
        functor: FunctionProgrammer;
        type: ts.Type;
        name: string | undefined;
    }) => IComposed;
    const writeDecomposed: (props: {
        modulo: ts.LeftHandSideExpression;
        functor: FunctionProgrammer;
        result: IDecomposed;
    }) => ts.CallExpression;
    const write: (props: {
        context: ITypiaContext;
        config: IConfig;
        functor: FunctionProgrammer;
        type: ts.Type;
        name?: string | undefined;
    }) => ts.ArrowFunction;
    const write_object_functions: (props: {
        config: IConfig;
        context: ITypiaContext;
        collection: MetadataCollection;
    }) => ts.VariableStatement[];
    const write_union_functions: (props: {
        config: IConfig;
        collection: MetadataCollection;
    }) => ts.VariableStatement[];
    const decode_array: (props: {
        config: Pick<IConfig, "trace" | "path" | "decoder" | "prefix">;
        functor: FunctionProgrammer;
        combiner: (next: {
            input: ts.Expression;
            arrow: ts.ArrowFunction;
        }) => ts.Expression;
        array: MetadataArray;
        input: ts.Expression;
        explore: IExplore;
    }) => ts.Expression;
    const decode_object: (props: {
        config: Pick<IConfig, "trace" | "path" | "prefix">;
        functor: FunctionProgrammer;
        object: MetadataObjectType;
        input: ts.Expression;
        explore: IExplore;
    }) => ts.CallExpression;
    const index: (props: {
        start: number | null;
        postfix: string;
        rand: string;
    }) => string;
    const argumentsArray: (props: {
        config: Pick<IConfig, "path" | "trace">;
        input: ts.Expression;
        explore: FeatureProgrammer.IExplore;
    }) => ts.Expression[];
    const parameterDeclarations: (props: {
        config: Pick<CheckerProgrammer.IConfig, "path" | "trace">;
        type: ts.TypeNode;
        input: ts.Identifier;
    }) => ts.ParameterDeclaration[];
}
