import { DMMF, GeneratorOptions } from '@prisma/generator-helper';
import AwaitEventEmitter from 'await-event-emitter';
import { Project, SourceFile } from 'ts-morph';
import { ValueOf, WritableDeep } from 'type-fest';

export type ConfigurationCreateArgs = {
	config: {
		[k: string]: GeneratorConfigLine;
	};
	output: string;
	sourceFilePath: string;
};
declare class Configuration {
	#private;
	readonly warnings: Set<string>;
	schemaConfig: Record<string, unknown>;
	externalConfig?: ExternalConfig;
	externalConfigFile?: string;
	constructor(args: Pick<Configuration, "schemaConfig" | "externalConfig" | "externalConfigFile"> & {
		sourceFilePath: string;
		output: string;
		warnings?: string[];
	});
	static create(args: ConfigurationCreateArgs): Promise<Configuration>;
	private initializeOutputFilePattern;
	get output(): string;
	get outputFilePattern(): string;
	get importExtension(): string;
	get emitCompiled(): boolean;
	get tsConfigFilePath(): string | undefined;
	get combineScalarFilters(): boolean;
	get noTypeId(): boolean;
	get noAtomicOperations(): boolean;
	get reExport(): ReExportType;
	get purgeOutput(): boolean;
	get emitSingle(): boolean;
	get requireSingleFieldsInWhereUniqueInput(): boolean;
	get omitModelsCount(): boolean;
	get typeListNullable(): boolean;
	get unsafeCompatibleWhereUniqueInput(): boolean;
	get prismaClientImport(): string;
	get emitBlocksModels(): boolean;
	get emitBlocksPrismaEnums(): boolean;
	get emitBlocksSchemaEnums(): boolean;
	get emitBlocksOutputs(): boolean;
	get emitBlocksInputs(): boolean;
	get emitBlocksArgs(): boolean;
	getGraphqlScalar(type: string): ImportNameSpec | undefined;
	getField(namespace?: string): ConfigFieldRecord | undefined;
	/**
	 * Get graphql for input type
	 */
	getInputType(args: GetInputTypeFunctionArgs): InputTypeRef | undefined;
	get customImports(): CustomImportItem[];
	shouldHideField(args: {
		objectName: string;
		propertyName: string;
		propertyType: string;
		location: FieldLocation;
		typeName: string;
		/**
		 * @deprecated Should not use
		 */
		settings?: ObjectSettings;
		/**
		 * @deprecated Legacy1
		 */
		output?: boolean;
		/**
		 * @deprecated Legacy
		 */
		input?: boolean;
	}): boolean;
	getDecorators(): Generator<DecoratorItem>;
	/**
	 * Get field override arguments for a specific field.
	 * Returns merged fieldArguments from all matching overrides.
	 */
	getFieldOverride(args: {
		objectName: string;
		propertyName: string;
		propertyType: string;
		location: FieldLocation;
		typeName: string;
	}): Record<string, unknown> | undefined;
	/**
	 * @deprecated Should be replaced by decorators
	 */
	get decorate(): LegacyDecorateElement[];
}
declare const ReExport: {
	readonly All: "All";
	readonly Directories: "Directories";
	readonly None: "None";
	readonly Single: "Single";
};
export type ReExportType = ValueOf<typeof ReExport>;
export type ObjectSetting = {
	/**
	 * Act as named import or namespaceImport or defaultImport
	 */
	name: string;
	kind: "Decorator" | "Field" | "FieldType" | "PropertyType" | "ObjectType";
	arguments?: string[] | Record<string, unknown>;
	input: boolean;
	output: boolean;
	model: boolean;
	match?: (test: string) => boolean;
	from: string;
	namespace?: string;
	defaultImport?: string | true;
	namespaceImport?: string;
	namedImport?: boolean;
};
export interface ObjectSettingsFilterArgs {
	name: string;
	input?: boolean;
	output?: boolean;
}
declare class ObjectSettings extends Array<ObjectSetting> {
	shouldHideField({ input, name, output, }: ObjectSettingsFilterArgs): boolean;
	getFieldType({ input, name, output, }: ObjectSettingsFilterArgs): ObjectSetting | undefined;
	getPropertyType({ input, name, output, }: ObjectSettingsFilterArgs): ObjectSetting | undefined;
	getObjectTypeArguments(options: Record<string, any>): string[];
	fieldArguments(): Record<string, unknown> | undefined;
}
export type TAwaitEventEmitter = AwaitEventEmitter.default;
export type FieldLocation = DMMF.FieldLocation;
export type Model = WritableDeep<DMMF.Model>;
export type Schema = WritableDeep<DMMF.Schema>;
export type Field = DMMF.Field;
export type InputTypeRef = DMMF.InputTypeRef;
/**
 * @deprecated
 */
export type LegacyDecorateElement = {
	isMatchField: (s: string) => boolean;
	isMatchType: (s: string) => boolean;
	from: string;
	name: string;
	arguments?: string[];
	namedImport: boolean;
	defaultImport?: string | true;
	namespaceImport?: string;
	type: string;
	field: string;
};
export type FieldInfo = {
	/**
	 * Prisma DMMF field location type
	 * Can be: 'scalar', 'inputObjectTypes', 'outputObjectTypes', 'enumTypes', 'fieldRefTypes'
	 */
	location: FieldLocation;
	/**
	 * Class name
	 */
	objectName: string;
	/**
	 * Property name
	 */
	propertyName: string;
	/**
	 * Property type (may contain TypeScript elements, like parameters for generics, etc.)
	 */
	propertyType: string;
	/**
	 * GraphQL/Prisma type name
	 */
	typeName: string;
};
/**
 * Configuration lines defined in schema
 */
export type GeneratorConfigLine = string | string[] | undefined | null;
export type GetInputTypeFunctionArgs = {
	inputTypeName: string;
	fieldName: string;
	fieldInputTypes: InputTypeRef[];
};
export type EventArguments = {
	schema: Schema;
	models: Map<string, Model>;
	modelNames: string[];
	modelFields: Map<string, Map<string, Field>>;
	fieldSettings: Map<string, Map<string, ObjectSettings>>;
	config: Configuration;
	project: Project;
	output: string;
	getSourceFile(args: {
		type: string;
		name: string;
	}): SourceFile;
	eventEmitter: TAwaitEventEmitter;
	typeNames: Set<string>;
	removeTypes: Set<string>;
	enums: Record<string, DMMF.DatamodelEnum | undefined>;
	getModelName(name: string): string | undefined;
	/**
	 * Input types for this models should be decorated @Type(() => Self)
	 */
	classTransformerTypeModels: Set<string>;
};
export type ImportNameSpec = {
	name: string;
	specifier?: string;
};
export type EmitBlocksOption = "enums" | "models" | "inputs" | "args" | "outputs";
export type ConfigFieldRecord = {
	/** Arguments passed to the decorator.
	 * @default [] */
	arguments?: string[];
	/** Import as default export.
	 * Use `true` to import by the field namespace name. */
	defaultImport?: string | true;
	/** Module to import from (e.g. 'class-validator') */
	from?: string;
	/** Apply decorator on InputType classes.
	 * @default false */
	input?: boolean;
	/** Apply decorator only on model ObjectType classes.
	 * @default false */
	model?: boolean;
	/** Import entire module under this namespace.
	 * @default equals field namespace name */
	namespaceImport?: string;
	/** Apply decorator on ObjectType/output classes.
	 * @default false */
	output?: boolean;
};
/**
 * @example
 * WhereInput: { '*': 'WhereInput' },
 * PostCreateInput: { author: 'UserCreateNestedOneWithoutPostsInput' },
 */
export type ConfigInputTypeMap = Record<string, Record<string, string>>;
export type GetInputTypeRefFunction = (args: GetInputTypeFunctionArgs) => InputTypeRef | undefined;
export type GetInputTypePatternFunction = (args: GetInputTypeFunctionArgs) => string | undefined;
export type GetInputTypeFunction = GetInputTypeRefFunction | GetInputTypePatternFunction;
export type CustomImportItem = {
	/** Import as default export.
	 * Use `true` to import by name. */
	defaultImport?: string | true;
	/** Module specifier to import from (e.g. 'class-validator') */
	from: string;
	/** Name to import */
	name: string;
	/** Import as a named export.
	 * @default false */
	namedImport?: boolean;
	/** Import entire module under this namespace */
	namespaceImport?: string;
};
/**
 * Return `true` to generate `@HideField()` instead of `@Field()` for a field.
 */
export type ShouldHideFieldFunction = (args: FieldInfo) => boolean;
/**
 * Modern decorator rule for `ExternalConfig.decorators`.
 * Prefer this over legacy `decorate_*` schema keys.
 */
export type DecoratorItem = {
	/** Return `true` to apply this decorator to the current field. */
	match: (args: FieldInfo) => boolean;
	/** Arguments passed to the decorator call.
	 * Supports templates like `{propertyType.0}`. */
	arguments?: string[];
	/** Module specifier to import from (e.g. 'class-validator') */
	from: string;
	/** Decorator name. Can include namespace, e.g. `Transform.Type`. */
	name: string;
	/** Import as a named export. */
	namedImport?: boolean;
	/** Import as default export.
	 * Use `true` to import by decorator name. */
	defaultImport?: string | true;
	/** Import entire module under this namespace. */
	namespaceImport?: string;
};
/**
 * Arguments passed to the `@Field()` decorator.
 * Follows NestJS GraphQL's FieldOptions structure to avoid conflicts.
 * These are merged into the generated `@Field()` options object.
 *
 * @see https://docs.nestjs.com/graphql/resolvers-map#field-decorator
 */
export type FieldDecoratorArguments = {
	/**
	 * Custom name for the field in GraphQL schema (different from TypeScript property name).
	 *
	 * **Important:** When you rename a field (e.g., 'take' → 'first'), you must map the GraphQL
	 * argument names back to Prisma field names in your resolver, since Prisma expects the
	 * original field names.
	 *
	 * @example
	 * // Option 1: Manual mapping in resolver
	 * async findMany(args: FindManyArgs): Promise<Item[]> {
	 *   const { first, ...restArgs } = args as any;
	 *   return this.prisma.item.findMany({
	 *     ...restArgs,
	 *     ...(first !== undefined && { take: first }),
	 *   });
	 * }
	 *
	 * @example
	 * // Option 2: Use a helper function
	 * export function mapGraphQLArgsToPrisma(args: any): any {
	 *   const { first, ...restArgs } = args;
	 *   return {
	 *     ...restArgs,
	 *     ...(first !== undefined && { take: first }),
	 *   };
	 * }
	 *
	 * async findMany(args: FindManyArgs): Promise<Item[]> {
	 *   const prismaArgs = mapGraphQLArgsToPrisma(args);
	 *   return this.prisma.item.findMany(prismaArgs);
	 * }
	 * export function mapGraphQLArgsToPrisma(args: any): any {
	 *   const { first, ...restArgs } = args;
	 *   return {
	 *     ...restArgs,
	 *     ...(first !== undefined && { take: first }),
	 *   };
	 * }
	 */
	name?: string;
	/** Description shown in GraphQL schema. */
	description?: string;
	/** Mark field as deprecated with optional reason. */
	deprecationReason?: string;
	/** Complexity for query complexity analysis. */
	complexity?: unknown;
	/**
	 * Middleware function name(s) to apply to the field.
	 * These are emitted as identifier references, not strings.
	 * Make sure to add corresponding customImports for the middleware.
	 *
	 * @example
	 * // Single middleware
	 * middleware: 'loggerMiddleware'
	 *
	 * @example
	 * // Multiple middleware
	 * middleware: ['loggerMiddleware', 'authMiddleware']
	 */
	middleware?: string | string[];
	/** Mark field as nullable in GraphQL schema. */
	nullable?: boolean;
	/** Default value for the field. */
	defaultValue?: unknown;
};
/**
 * Rule for overriding `@Field()` decorator arguments on generated fields.
 * Use this to customize pagination fields (take, skip) or other generated Args fields.
 */
export type FieldDecoratorRule = {
	/** Return `true` to apply this override to the current field. */
	match: (args: FieldInfo) => boolean;
	/**
	 * Arguments to merge into the `@Field()` decorator options.
	 * These are merged with existing arguments (nullable, etc.).
	 */
	decoratorArguments: FieldDecoratorArguments;
};
export type ExternalConfig = Partial<{
	/**
	 * Output folder for generated files.
	 * If path relative and defined in schema it will be relative to schema,
	 * if defined in config file it will be relative to this config file.
	 */
	output: string;
	/**
	 * File path and name pattern for generated files.
	 * @type {string}
	 * Available tokens:
	 * - `{model}` — Model name in dashed-case, or 'prisma' if unknown
	 * - `{name}` — Dashed-case name of model/input/arg without suffix
	 * - `{type}` — Short type name (model, input, args, output)
	 * - `{plural.type}` — Plural short type name (models, inputs, enums)
	 * @default '{model}/{name}.{type}.ts'
	 */
	outputFilePattern: string;
	/**
	 * Append an extension to relative import and export module specifiers.
	 * Useful when your project uses ESM or a custom module resolution.
	 * @example 'js', 'ts', 'mjs'
	 */
	importExtension: string;
	/**
	 * Combine nested/nullable scalar filters into a single filter type.
	 * When enabled, reduces the number of generated filter classes by merging
	 * e.g. `StringNullableFilter` and `StringFilter` into one.
	 * @default true
	 */
	combineScalarFilters: boolean;
	/**
	 * Remove input types for atomic operations.
	 * When enabled, types like `IntFieldUpdateOperationsInput` are not generated.
	 * @default true
	 */
	noAtomicOperations: boolean;
	/**
	 * Emit only selected blocks. Some blocks depend on others
	 * (e.g. models requires schemaEnums, inputs requires prismaEnums).
	 * Valid block names: 'args', 'inputs', 'outputs', 'models', 'enums'
	 * @default All blocks enabled
	 */
	emitBlocks: EmitBlocksOption[];
	/**
	 * Omit the `_count` field from model output types.
	 * @default false
	 */
	omitModelsCount: boolean;
	/**
	 * Emit compiled JavaScript and definition files instead of TypeScript sources.
	 * @default false
	 */
	emitCompiled: boolean;
	/**
	 * Path to tsconfig.json (absolute or relative to CWD).
	 * If not specified, auto-detects `tsconfig.json` if it exists.
	 */
	tsConfigFilePath: string;
	/**
	 * Re-export strategy for generated files.
	 * - None — No re-export index files (default)
	 * - Directories — Index file in each root directory
	 * - Single — Single index file in the output directory
	 * - All — All of the above
	 * @default None
	 */
	reExport: ReExportType;
	/**
	 * Delete all files in the output folder before each generation.
	 * @default false
	 */
	purgeOutput: boolean;
	/**
	 * Mark single-field WhereUniqueInput fields as required (TypeScript)
	 * and non-nullable (GraphQL).
	 * NOTE: This will break compatibility between Prisma types and generated classes.
	 * @default false
	 */
	requireSingleFieldsInWhereUniqueInput: boolean;
	/**
	 * Generate a single merged file with all classes and enums
	 * instead of one file per model/input/arg.
	 * @default false
	 */
	emitSingle: boolean;
	/**
	 * Make all fields in `*WhereUniqueInput` classes non-optional TypeScript properties.
	 * @default false
	 */
	unsafeCompatibleWhereUniqueInput: boolean;
	/**
	 * Add `nullable: true` to relation list properties on output types.
	 * Changes `[Type!]!` → `[Type!]` in the GraphQL schema.
	 * @default false
	 */
	typeListNullable: boolean;
	/**
	 * Import path used for Prisma Client imports in generated files.
	 * @default '@prisma/client'
	 */
	prismaClientImport: string;
	/**
	 * Disable GraphQL ID type usage, using Int/Float for @id fields instead.
	 * @default false
	 */
	noTypeId: boolean;
	/**
	 * Custom GraphQL scalar type mappings for Prisma scalar types.
	 * Keyed by Prisma scalar type name (e.g. 'BigInt', 'DateTime').
	 * @example
	 * // Override BigInt with graphql-scalars' GraphQLBigInt:
	 * { BigInt: { name: 'GraphQLBigInt', specifier: 'graphql-scalars' } }
	 */
	graphqlScalars: Record<string, ImportNameSpec | undefined>;
	/**
	 * Per-field custom decorator configuration, keyed by namespace.
	 * Enables automatic decorator application from external modules
	 * on fields annotated with `@{namespace}.XXX` in the Prisma schema.
	 * Each namespace entry defines:
	 * - `from` — Module specifier to import (e.g. 'class-validator')
	 * - `input` — Apply to InputType classes
	 * - `output` — Apply to ObjectType/output classes
	 * - `model` — Apply only to model ObjectType classes
	 * - `defaultImport` — Import as default export (true = use namespace as name)
	 * - `namespaceImport` — Import entire module under this namespace
	 * - `namedImport` — Import as named export
	 *
	 * @example
	 * // Schema:  /// @Validator.MinLength(3)
	 * // Config:  { from: 'class-validator', input: true }
	 * // Result:  import * as Validator from 'class-validator';  @Validator.MinLength(3)
	 */
	fields: Record<string, ConfigFieldRecord | undefined>;
	/**
	 * Input type mapping.
	 * Select which input type should be exposed when multiple candidates exist.
	 * Since GraphQL does not support input unions, this setting can resolve
	 * ambiguous fields (e.g. `UserRelationFilter` vs `UserWhereInput`).
	 *
	 * Supports two variants:
	 * - object map: `{ [inputTypeName]: { [fieldName|'*']: pattern } }`
	 * - function: return either an `InputTypeRef` or a string pattern
	 *   (same matching behavior as map patterns, including `match:` syntax)
	 * @example
	 * // Force all WhereInput relation properties to use the plain WhereInput type:
	 * { WhereInput: { '*': 'WhereInput' } }
	 * // Or for a specific property in a specific type:
	 * { PostCreateInput: { author: 'UserCreateNestedOneWithoutPostsInput' } }
	 * // Function variant returning a pattern:
	 * ({ inputTypeName, fieldName }) =>
	 *   inputTypeName.includes('CreateOne') && fieldName === 'data'
	 *     ? 'UncheckedCreate'
	 *     : undefined
	 */
	inputType: GetInputTypeFunction | ConfigInputTypeMap;
	/**
	 * Custom import statements injected into generated files.
	 * Each element specifies:
	 * - `from` — Module specifier to import from
	 * - `name` — Name to import
	 * - `namedImport` — Import as named export
	 * - `defaultImport` — Import as default export
	 * - `namespaceImport` — Import entire module under this namespace
	 */
	customImports: CustomImportItem[];
	/**
	 * Hook for deciding whether a generated field should be hidden in GraphQL schema.
	 * Called for each generated input/output/model field.
	 * Returning `true` adds `@HideField()` and skips `@Field()`.
	 * When set, this hook overrides hide settings from field comments and legacy `decorate`.
	 */
	shouldHideField: ShouldHideFieldFunction;
	/**
	 * Modern way to attach decorators to generated fields.
	 * Each rule is evaluated against generated field metadata (`FieldInfo`) and
	 * applied when `match` returns `true`.
	 * Prefer this over legacy `decorate`/`decorate_*` schema configuration.
	 */
	decorators: DecoratorItem[];
	/**
	 * Override `@Field()` decorator arguments for specific fields.
	 * Use this to customize pagination fields (take, skip, cursor) or other
	 * generated Args fields that don't come from your Prisma schema.
	 *
	 * Each rule is evaluated against generated field metadata (`FieldInfo`) and
	 * applied when `match` returns `true`.
	 *
	 * @example
	 * fieldDecoratorArguments: [
	 *   {
	 *     match: ({ objectName, propertyName }) =>
	 *       objectName.endsWith('Args') && propertyName === 'take',
	 *     decoratorArguments: {
	 *       name: 'first',
	 *       defaultValue: 10,
	 *       description: 'Number of records to return',
	 *     },
	 *   },
	 * ]
	 */
	fieldDecoratorArguments: FieldDecoratorRule[];
}>;
export declare function generate(args: GeneratorOptions & {
	skipAddOutputSourceFiles?: boolean;
	connectCallback?: (emitter: TAwaitEventEmitter, eventArguments: EventArguments) => void | Promise<void>;
}): Promise<void>;
export declare const generatorHandlerConfig: {
	onGenerate(options: GeneratorOptions): Promise<void>;
	onManifest(): {
		defaultOutput: string;
		prettyName: string;
	};
};

export {};
