import type { GraphQLFieldResolver } from "graphql";
import { GraphQLSchema } from "graphql";
import * as graphql from "graphql";
import type { AbstractTypePlanner, ArgumentApplyPlanResolver, BaseGraphQLArguments, EnumValueApplyResolver, FieldPlanResolver, InputObjectFieldApplyResolver, InputObjectTypeBakedResolver, ScalarPlanResolver } from "./interfaces.js";
import type { Step } from "./step.js";
export interface ObjectFieldConfig<TSource extends Step = Step, TArgs extends BaseGraphQLArguments = any, TResultStep extends Step = Step> {
    plan?: FieldPlanResolver<TSource, TArgs, TResultStep>;
    subscribePlan?: FieldPlanResolver<TSource, TArgs, TResultStep>;
    resolve?: GraphQLFieldResolver<any, any>;
    subscribe?: GraphQLFieldResolver<any, any>;
    args?: {
        [argName: string]: ArgumentApplyPlanResolver | {
            applyPlan?: ArgumentApplyPlanResolver;
            applySubscribePlan?: ArgumentApplyPlanResolver;
            extensions?: graphql.GraphQLArgumentExtensions;
        };
    };
}
/**
 * When defining a field with `typeDefs/objects` you can declare the field plan
 * directly, or you can define a configuration object that accepts the plan and
 * more.
 */
export type FieldPlan<TSource extends Step = Step, TArgs extends BaseGraphQLArguments = BaseGraphQLArguments, TResultStep extends Step = Step> = FieldPlanResolver<TSource, TArgs, TResultStep> | ObjectFieldConfig<TSource, TArgs, TResultStep>;
export type DeprecatedObjectPlan<TSource extends Step = Step> = {
    __assertStep?: ((step: Step) => asserts step is TSource) | {
        new (...args: any[]): TSource;
    };
    __isTypeOf?: graphql.GraphQLIsTypeOfFn<any, any>;
    __planType?($specifier: Step): TSource;
} & {
    [key: string]: FieldPlan<TSource, any, any>;
};
/**
 * The plans/config for each field of a GraphQL object type.
 */
export interface ObjectPlan<TSource extends Step = Step> {
    assertStep?: ((step: Step) => asserts step is TSource) | {
        new (...args: any[]): TSource;
    };
    isTypeOf?: graphql.GraphQLIsTypeOfFn<any, any>;
    planType?($specifier: Step): TSource;
    plans?: {
        [key: string]: FieldPlan<TSource, any, any>;
    };
}
/**
 * The plans for each field of a GraphQL input object type.
 */
export type DeprecatedInputObjectPlan = {
    __baked?: InputObjectTypeBakedResolver;
} & {
    [fieldName: string]: InputObjectFieldApplyResolver<any> | {
        apply?: InputObjectFieldApplyResolver<any>;
        extensions?: graphql.GraphQLInputFieldExtensions;
    };
};
export interface InputObjectFieldConfig<TParent = any, TData = any> {
    apply?: InputObjectFieldApplyResolver<TParent, TData>;
    extensions?: graphql.GraphQLInputFieldExtensions;
}
export type InputFieldPlan<TParent = any, TData = any> = InputObjectFieldApplyResolver<TParent, TData> | InputObjectFieldConfig<TParent, TData>;
export interface InputObjectPlan {
    baked?: InputObjectTypeBakedResolver;
    plans?: {
        [fieldName: string]: InputFieldPlan;
    };
}
/**
 * The plan config for an interface or union type.
 */
export interface AbstractTypePlan<TSource extends Step = any, TSpecifier extends Step = TSource> {
    /**
     * Runtime. If the polymorphic data just needs resolving to a type name, this
     * method can be used to return said type name. If planning of polymorphism
     * is more complex for this polymorphic type (for example, if it includes
     * fetching of data) then the `planType` method should be used instead.
     *
     * Warning: this method is more expensive than planType because it requires
     * the implementation of GraphQL.js emulation.
     */
    resolveType?: graphql.GraphQLTypeResolver<any, Grafast.Context>;
    /**
     * Takes a step representing this polymorphic position, and returns a
     * "specifier" step that will be input to planType. If not specified, the
     * step's own `.toSpecifier()` will be used, if present, otherwise the
     * step's own `.toRecord()`, and failing that the step itself.
     */
    toSpecifier?($step: TSource): TSpecifier;
    /**
     * Plantime. `$specifier` is either a step returned from a field or list
     * position with an abstract type, or a `__ValueStep` that represents the
     * combined values of such steps (to prevent unbounded plan branching).
     * `planType` must then construct a step that represents the `__typename`
     * related to this given specifier (or `null` if no match can be found) and a
     * `planForType` method which, when called, should return the step for the
     * given type.
     */
    planType?: ($specifier: TSpecifier) => AbstractTypePlanner;
}
export interface InterfacePlan<TSource extends Step = any, TSpecifier extends Step = TSource> extends AbstractTypePlan<TSource, TSpecifier> {
}
export interface UnionPlan<TSource extends Step = any, TSpecifier extends Step = TSource> extends AbstractTypePlan<TSource, TSpecifier> {
}
export type DeprecatedUnionOrInterfacePlan = {
    [TKey in keyof AbstractTypePlan as `__${TKey}`]: AbstractTypePlan[TKey];
};
/**
 * The config for a GraphQL scalar type.
 */
export interface ScalarPlan<TInternal = any, TExternal = any> extends Omit<graphql.GraphQLScalarTypeConfig<TInternal, TExternal>, "name" | "description" | "specifiedByURL" | "astNode" | "extensionASTNodes"> {
    plan?: ScalarPlanResolver<any, any>;
}
export interface EnumValueConfig extends Omit<graphql.GraphQLEnumValueConfig, "description" | "deprecationReason" | "astNode"> {
    apply?: EnumValueApplyResolver;
}
export type EnumValueInput = EnumValueApplyResolver | EnumValueConfig | string | number | boolean;
/**
 * The values/configs for the entries in a GraphQL enum type.
 */
export interface EnumPlan {
    values?: {
        [enumValueName: string]: EnumValueInput | undefined;
    };
}
/**
 * A map from GraphQL named type to the config for that type.
 *
 * @deprecated Please use the different plan types instead
 */
export interface GrafastPlans {
    [typeName: string]: DeprecatedObjectPlan | DeprecatedInputObjectPlan | DeprecatedUnionOrInterfacePlan | ScalarPlan | EnumPlan;
}
export interface GrafastSchemaConfig {
    typeDefs: string | graphql.DocumentNode | graphql.DocumentNode[];
    /**
     * All the different types of plans smooshed together to simulate the old
     * typeDefs/resolvers pattern. Avoid.
     *
     * @deprecated Please use objects, unions, interfaces, inputObjects, scalars or enums as appropriate.
     */
    plans?: GrafastPlans;
    scalars?: {
        [typeName: string]: ScalarPlan;
    };
    enums?: {
        [typeName: string]: EnumPlan;
    };
    objects?: {
        [typeName: string]: ObjectPlan<any>;
    };
    unions?: {
        [typeName: string]: UnionPlan<any>;
    };
    interfaces?: {
        [typeName: string]: InterfacePlan<any>;
    };
    inputObjects?: {
        [typeName: string]: InputObjectPlan;
    };
    enableDeferStream?: boolean;
}
/**
 * Takes a GraphQL schema definition in Interface Definition Language (IDL/SDL)
 * syntax and configs for the types in it and returns a GraphQL schema.
 */
export declare function makeGrafastSchema(details: GrafastSchemaConfig): GraphQLSchema;
//# sourceMappingURL=makeGrafastSchema.d.ts.map