
export type ValidationRuleName =
	| "any"
	| "array"
	| "boolean"
	| "class"
	| "currency"
	| "custom"
	| "date"
	| "email"
	| "enum"
	| "equal"
	| "forbidden"
	| "function"
	| "luhn"
	| "mac"
	| "multi"
	| "number"
	| "object"
	| "objectID"
	| "record"
	| "string"
	| "tuple"
	| "url"
	| "uuid"
	| string;

/**
 * Validation schema definition for "any" built-in validator
 * @see https://github.com/icebob/fastest-validator#any
 */
export interface RuleAny extends RuleCustom {
	/**
	 * Name of built-in validator
	 */
	type: "any";
}

/**
 * Validation schema definition for "array" built-in validator
 * @see https://github.com/icebob/fastest-validator#array
 */
export interface RuleArray<T = any> extends RuleCustom {
    /**
     * Name of built-in validator
     */
    type: "array";
    /**
     * If true, the validator accepts an empty array [].
     * @default true
     */
    empty?: boolean;
    /**
     * Minimum count of elements
     */
    min?: number;
    /**
     * Maximum count of elements
     */
    max?: number;
    /**
     * Fixed count of elements
     */
    length?: number;
    /**
     * The array must contain this element too
     */
    contains?: T | T[];
	/**
	 * The array must be unique (array of objects is always unique).
	 */
	unique?: boolean;
    /**
     * Every element must be an element of the enum array
     */
    enum?: T[];
    /**
     * Validation rules that should be applied to each element of array
     */
    items?: ValidationRule;
	/**
	 * Wrap value into array if different type provided
	 */
	convert?: boolean
}

/**
 * Validation schema definition for "boolean" built-in validator
 * @see https://github.com/icebob/fastest-validator#boolean
 */
export interface RuleBoolean extends RuleCustom {
	/**
	 * Name of built-in validator
	 */
	type: "boolean";
	/**
	 * if true and the type is not Boolean, try to convert. 1, "true", "1", "on" will be true. 0, "false", "0", "off" will be false.
	 * @default false
	 */
	convert?: boolean;
}

/**
 * Validation schema definition for "class" built-in validator
 * @see https://github.com/icebob/fastest-validator#class
 */
export interface RuleClass<T = any> extends RuleCustom {
	/**
	 * Name of built-in validator
	 */
	type: "class";
	/**
	 * Checked Class
	 */
	instanceOf: T;
}

/**
 * Validation schema definition for "currency" built-in validator
 * @see https://github.com/icebob/fastest-validator#currency
 */
export interface RuleCurrency extends RuleCustom {
	/**
	 * Name of built-in validator
	 */
	type: "currency";
	/**
	 * The currency symbol expected in string (as prefix)
	 */
	currencySymbol?: string;
	/**
	 * Toggle to make the currency symbol optional in string
	 * @default false
	 */
	symbolOptional?: boolean;
	/**
	 * Thousand place separator character
	 * @default ','
	 */
	thousandSeparator?: string;
	/**
	 * Decimal place character
	 * @default '.'
	 */
	decimalSeparator?: string;
	/**
	 * Custom regular expression to validate currency strings
	 */
	customRegex?: RegExp | string;
}

/**
 * Validation schema definition for "date" built-in validator
 * @see https://github.com/icebob/fastest-validator#date
 */
export interface RuleDate extends RuleCustom {
	/**
	 * Name of built-in validator
	 */
	type: "date";
	/**
	 * if true and the type is not Date, try to convert with new Date()
	 * @default false
	 */
	convert?: boolean;
}

/**
 * Validation schema definition for "email" built-in validator
 * @see https://github.com/icebob/fastest-validator#email
 */
export interface RuleEmail extends RuleCustom {
	/**
	 * Name of built-in validator
	 */
	type: "email";
	/**
	 * If true, the validator accepts an empty string ""
	 * @default false
	 */
	empty?: boolean;
	/**
	 * Checker method. Can be quick or precise
	 * @default quick
	 */
	mode?: "quick" | "precise";
	/**
	 * Normalize the e-mail address (trim & lower-case). It's a sanitizer, it will change the value in the original object.
	 * @default false
	 */
	normalize?: boolean;
	/**
	 * Minimum value length
	 */
	min?: number;
	/**
	 * Maximum value length
	 */
	max?: number;
}

/**
 * Validation schema definition for "enum" built-in validator
 * @see https://github.com/icebob/fastest-validator#enum
 */
export interface RuleEnum<T = any> extends RuleCustom {
	/**
	 * Name of built-in validator
	 */
	type: "enum";
	/**
	 * The valid values
	 */
	values: T[];
}

/**
 * Validation schema definition for "equal" built-in validator
 * @see https://github.com/icebob/fastest-validator#equal
 */
export interface RuleEqual<T = any> extends RuleCustom {
	/**
	 * Name of built-in validator
	 */
	type: "equal";
	/**
	 * The valid value
	 */
	value?: T;

	/**
	 * Another field name
	 */
	field?: string;

	/**
	 * Strict value checking.
	 *
	 * @default false
	 */
	strict?: boolean;
}

/**
 * Validation schema definition for "forbidden" built-in validator
 * @see https://github.com/icebob/fastest-validator#forbidden
 */
export interface RuleForbidden extends RuleCustom {
	/**
	 * Name of built-in validator
	 */
	type: "forbidden";

	/**
	 * Removes the forbidden value.
	 *
	 * @default false
	 */
	remove?: boolean;
}

/**
 * Validation schema definition for "function" built-in validator
 * @see https://github.com/icebob/fastest-validator#function
 */
export interface RuleFunction extends RuleCustom {
	/**
	 * Name of built-in validator
	 */
	type: "function";
}

/**
 * Validation schema definition for "luhn" built-in validator
 * @see https://github.com/icebob/fastest-validator#luhn
 */
export interface RuleLuhn extends RuleCustom {
	/**
	 * Name of built-in validator
	 */
	type: "luhn";
}

/**
 * Validation schema definition for "mac" built-in validator
 * @see https://github.com/icebob/fastest-validator#mac
 */
export interface RuleMac extends RuleCustom {
	/**
	 * Name of built-in validator
	 */
	type: "mac";
}

/**
 * Validation schema definition for "multi" built-in validator
 * @see https://github.com/icebob/fastest-validator#multi
 */
export interface RuleMulti extends RuleCustom {
	/**
	 * Name of built-in validator
	 */
	type: "multi";

	rules: (RuleCustom | string)[];
}

/**
 * Validation schema definition for "number" built-in validator
 * @see https://github.com/icebob/fastest-validator#number
 */
export interface RuleNumber extends RuleCustom {
	/**
	 * Name of built-in validator
	 */
	type: "number";
	/**
	 * Minimum value
	 */
	min?: number;
	/**
	 * Maximum value
	 */
	max?: number;
	/**
	 * Fixed value
	 */
	equal?: number;
	/**
	 * Can't be equal to this value
	 */
	notEqual?: number;
	/**
	 * The value must be a non-decimal value
	 * @default false
	 */
	integer?: boolean;
	/**
	 * The value must be greater than zero
	 * @default false
	 */
	positive?: boolean;
	/**
	 * The value must be less than zero
	 * @default false
	 */
	negative?: boolean;
	/**
	 * if true and the type is not Number, converts with Number()
	 * @default false
	 */
	convert?: boolean;
}

/**
 * Validation schema definition for "object" built-in validator
 * @see https://github.com/icebob/fastest-validator#object
 */
export interface RuleObject extends RuleCustom {
	/**
	 * Name of built-in validator
	 */
	type: "object";
	/**
	 * If `true` any properties which are not defined on the schema will throw an error.<br>
	 * If `remove` all additional properties will be removed from the original object. It's a sanitizer, it will change the original object.
	 * @default false
	 */
	strict?: boolean | "remove";
	/**
	 * List of properties that should be validated by this rule
	 */
	properties?: ValidationSchema;
	props?: ValidationSchema;
	/**
	 * If set to a number, will throw if the number of props is less than that number.
	 */
	minProps?: number;
	/**
	 * If set to a number, will throw if the number of props is greater than that number.
	 */
	maxProps?: number;
}

export interface RuleRecord extends RuleCustom {
	/**
	 * Name of built-in validator
	 */
	type: "record";
	/**
	 * Key validation rule
	 * @default "string"
	 */
	key?: RuleString;
	/**
	 * Value validation rule
	 */
	value?: ValidationRuleObject;
}

/**
 * Validation schema definition for "string" built-in validator
 * @see https://github.com/icebob/fastest-validator#string
 */
export interface RuleString extends RuleCustom {
	/**
	 * Name of built-in validator
	 */
	type: "string";
	/**
	 * If true, the validator accepts an empty string ""
	 * @default true
	 */
	empty?: boolean;
	/**
	 * Minimum value length
	 */
	min?: number;
	/**
	 * Maximum value length
	 */
	max?: number;
	/**
	 * Fixed value length
	 */
	length?: number;
	/**
	 * Regex pattern
	 */
	pattern?: string | RegExp;
	/**
	 * The value must contain this text
	 */
	contains?: string;
	/**
	 * The value must be an element of the enum array
	 */
	enum?: string[];
	/**
	 * The value must be an alphabetic string
	 */
	alpha?: boolean;
	/**
	 * The value must be a numeric string
	 */
	numeric?: boolean;
	/**
	 * The value must be an alphanumeric string
	 */
	alphanum?: boolean;
	/**
	 * The value must be an alphabetic string that contains dashes
	 */
	alphadash?: boolean;
	/**
	 * The value must be a hex string
	 */
	hex?: boolean;
	/**
	 * The value must be a singleLine string
	 */
	singleLine?: boolean;
	/**
	 * The value must be a base64 string
	 */
	base64?: boolean;
	/**
	 * If true, the value will be trimmed. It's a sanitizer, it will change the value in the original object.
	 */
	trim?: boolean;
	/**
	 * If true, the value will be left trimmed. It's a sanitizer, it will change the value in the original object.
	 */
	trimLeft?: boolean;
	/**
	 * If true, the value will be right trimmed. It's a sanitizer, it will change the value in the original object.
	 */
	trimRight?: boolean;
	/**
	 * If it's a number, the value will be left padded. It's a sanitizer, it will change the value in the original object.
	 */
	padStart?: number;
	/**
	 * If it's a number, the value will be right padded. It's a sanitizer, it will change the value in the original object.
	 */
	padEnd?: number;
	/**
	 * The padding character for the padStart and padEnd.
	 * @default " "
	 */
	padChar?: string;
	/**
	 * If true, the value will be lower-cased. It's a sanitizer, it will change the value in the original object.
	 */
	lowercase?: boolean;
	/**
	 * If true, the value will be upper-cased. It's a sanitizer, it will change the value in the original object.
	 */
	uppercase?: boolean;
	/**
	 * If true, the value will be locale lower-cased. It's a sanitizer, it will change the value in the original object.
	 */
	localeLowercase?: boolean;
	/**
	 * If true, the value will be locale upper-cased. It's a sanitizer, it will change the value in the original object.
	 */
	localeUppercase?: boolean;
	/**
	 * if true and the type is not a String, converts with String()
	 */
	convert?: boolean;
}

/**
 * Validation schema definition for "tuple" built-in validator
 * @see https://github.com/icebob/fastest-validator#array
 */
export interface RuleTuple<T = any> extends RuleCustom {
	/**
	 * Name of built-in validator
	 */
	type: "tuple";
	/**
	 * If true, the validator accepts an empty array [].
	 */
	empty?: boolean
	/**
	 * Validation rules that should be applied to the corresponding element of array
	 */
	items?: [ValidationRule, ValidationRule];
}

/**
 * Validation schema definition for "url" built-in validator
 * @see https://github.com/icebob/fastest-validator#url
 */
export interface RuleURL extends RuleCustom {
	/**
	 * Name of built-in validator
	 */
	type: "url";
	/**
	 * If true, the validator accepts an empty string ""
	 * @default false
	 */
	empty?: boolean;
}

/**
 * Validation schema definition for "uuid" built-in validator
 * @see https://github.com/icebob/fastest-validator#uuid
 */
export interface RuleUUID extends RuleCustom {
	/**
	 * Name of built-in validator
	 */
	type: "uuid";
	/**
	 * UUID version in range 0-6
	 */
	version?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
}

export interface RuleObjectID extends RuleCustom {
	/**
	 * Name of built-in validator
	 */
	type: "objectID";
	/**
	 * To inject ObjectID dependency
	 */
	ObjectID?: any;
	/**
	 * Convert HexStringObjectID to ObjectID
	 */
	convert?: boolean | "hexString";
}

/**
 * Validation schema definition for custom inline validator
 * @see https://github.com/icebob/fastest-validator#custom-validator
 */
export interface RuleCustomInline<T = any> extends RuleCustom {
	/**
	 * Name of built-in validator
	 */
	type: "custom";
	/**
	 * Custom checker function
	 */
	check: CheckerFunction<T>;
}

/**
 * Validation schema definition for custom validator
 * @see https://github.com/icebob/fastest-validator#custom-validator
 */
export interface RuleCustom {
	/**
	 * Name of custom validator that will be used in validation rules
	 */
	type: string;
	/**
	 * Every field in the schema will be required by default. If you'd like to define optional fields, set optional: true.
	 * @default false
	 */
	optional?: boolean;

	/**
	 * If you want disallow `undefined` value but allow `null` value, use `nullable` instead of `optional`.
	 * @default false
	 */
	nullable?: boolean;

	/**
	 * You can set your custom messages in the validator constructor
	 * Sometimes the standard messages are too generic. You can customise messages per validation type per field
	 */
	messages?: MessagesType;

	/**
	 * Default value
	 */
	default?: any;

	/**
	 * Custom checker function
	 */
	custom?: CheckerFunction;

	/**
	 * You can define any additional options for custom validators
	 */
	[key: string]: any;
}

/**
 * List of all possible keys that can be used for error message override
 */
export interface BuiltInMessages {
	/**
	 * The '{field}' field is required.
	 */
	required?: string;
	/**
	 * The '{field}' field must be a string.
	 */
	string?: string;
	/**
	 * The '{field}' field must not be empty.
	 */
	stringEmpty?: string;
	/**
	 * The '{field}' field length must be greater than or equal to {expected} characters long.
	 */
	stringMin?: string;
	/**
	 * The '{field}' field length must be less than or equal to {expected} characters long.
	 */
	stringMax?: string;
	/**
	 * The '{field}' field length must be {expected} characters long.
	 */
	stringLength?: string;
	/**
	 * The '{field}' field fails to match the required pattern.
	 */
	stringPattern?: string;
	/**
	 * The '{field}' field must contain the '{expected}' text.
	 */
	stringContains?: string;
	/**
	 * The '{field}' field does not match any of the allowed values.
	 */
	stringEnum?: string;
	/**
	 * The '{field}' field must be a numeric string.
	 */
	stringNumeric?: string;
	/**
	 * The '{field}' field must be an alphabetic string.
	 */
	stringAlpha?: string;
	/**
	 * The '{field}' field must be an alphanumeric string.
	 */
	stringAlphanum?: string;
	/**
	 * The '{field}' field must be an alphadash string.
	 */
	stringAlphadash?: string;

	/**
	 * The '{field}' field must be a number.
	 */
	number?: string;
	/**
	 * The '{field}' field must be greater than or equal to {expected}.
	 */
	numberMin?: string;
	/**
	 * The '{field}' field must be less than or equal to {expected}.
	 */
	numberMax?: string;
	/**
	 * The '{field}' field must be equal with {expected}.
	 */
	numberEqual?: string;
	/**
	 * The '{field}' field can't be equal with {expected}.
	 */
	numberNotEqual?: string;
	/**
	 * The '{field}' field must be an integer.
	 */
	numberInteger?: string;
	/**
	 * The '{field}' field must be a positive number.
	 */
	numberPositive?: string;
	/**
	 * The '{field}' field must be a negative number.
	 */
	numberNegative?: string;

	/**
	 * The '{field}' field must be an array.
	 */
	array?: string;
	/**
	 * The '{field}' field must not be an empty array.
	 */
	arrayEmpty?: string;
	/**
	 * The '{field}' field must contain at least {expected} items.
	 */
	arrayMin?: string;
	/**
	 * The '{field}' field must contain less than or equal to {expected} items.
	 */
	arrayMax?: string;
	/**
	 * The '{field}' field must contain {expected} items.
	 */
	arrayLength?: string;
	/**
	 * The '{field}' field must contain the '{expected}' item.
	 */
	arrayContains?: string;
	/**
	 * The '{field} field value '{expected}' does not match any of the allowed values.
	 */
	arrayEnum?: string;

	/**
	 * The '{field}' field must be a boolean.
	 */
	boolean?: string;

	/**
	 * The '{field}' field must be a Date.
	 */
	date?: string;
	/**
	 * The '{field}' field must be greater than or equal to {expected}.
	 */
	dateMin?: string;
	/**
	 * The '{field}' field must be less than or equal to {expected}.
	 */
	dateMax?: string;

	/**
	 * The '{field}' field value '{expected}' does not match any of the allowed values.
	 */
	enumValue?: string;

	/**
	 * The '{field}' field value must be equal to '{expected}'.
	 */
	equalValue?: string;
	/**
	 * The '{field}' field value must be equal to '{expected}' field value.
	 */
	equalField?: string;

	/**
	 * The '{field}' field is forbidden.
	 */
	forbidden?: string;

	/**
	 * The '{field}' field must be a function.
	 */
	function?: string;

	/**
	 * The '{field}' field must be a valid e-mail.
	 */
	email?: string;

	/**
	 * The '{field}' field must be a valid checksum luhn.
	 */
	luhn?: string;

	/**
	 * The '{field}' field must be a valid MAC address.
	 */
	mac?: string;

	/**
	 * The '{field}' must be an Object.
	 */
	object?: string;
	/**
	 * The object '{field}' contains forbidden keys: '{actual}'.
	 */
	objectStrict?: string;

	/**
	 * The '{field}' field must be a valid URL.
	 */
	url?: string;

	/**
	 * The '{field}' field must be a valid UUID.
	 */
	uuid?: string;
	/**
	 * The '{field}' field must be a valid UUID version provided.
	 */
	uuidVersion?: string;
}

/**
 * Type with description of custom error messages
 */
export type MessagesType = BuiltInMessages & { [key: string]: string };

/**
 * Union type of all possible built-in validators
 */
export type ValidationRuleObject =
	| RuleAny
	| RuleArray
	| RuleBoolean
	| RuleClass
	| RuleCurrency
	| RuleDate
	| RuleEmail
	| RuleEqual
	| RuleEnum
	| RuleForbidden
	| RuleFunction
	| RuleLuhn
	| RuleMac
	| RuleMulti
	| RuleNumber
	| RuleObject
	| RuleObjectID
	| RuleRecord
	| RuleString
	| RuleTuple
	| RuleURL
	| RuleUUID
	| RuleCustom
	| RuleCustomInline;

/**
 * Description of validation rule definition for a some property
 */
export type ValidationRule =
	| ValidationRuleObject
	| ValidationRuleObject[]
	| ValidationRuleName;

/**
 *
 */
export interface ValidationSchemaMetaKeys {
	/**
	 * Object properties which are not specified on the schema are ignored by default.
	 * If you set the $$strict option to true any additional properties will result in an strictObject error.
	 * @default false
	 */
	$$strict?: boolean | "remove";

	/**
	 * Enable asynchronous functionality. In this case the `validate` and `compile` methods return a `Promise`.
	 * @default false
	 */
	$$async?: boolean;

	/**
	 * Basically the validator expects that you want to validate a Javascript object.
	 * If you want others, you can define the root level schema.
	 * @default false
	 */
	$$root?: boolean;
}

/**
 * Definition for validation schema based on validation rules
 */
export type ValidationSchema<T = any> = ValidationSchemaMetaKeys & {
	/**
	 * List of validation rules for each defined field
	 */
	[key in keyof T]: ValidationRule | undefined | any;
}


/**
 * Structure with description of validation error message
 */
export interface ValidationError {
	/**
	 * Name of validation rule that generates this message
	 */
	type: keyof BuiltInMessages | string;
	/**
	 * Field that catch validation error
	 */
	field: string;
	/**
	 * Description of current validation error
	 */
	message?: string;
	/**
	 * Expected value from validation rule
	 */
	expected?: any;
	/**
	 * Actual value received by validation rule
	 */
	actual?: any;
}

/**
 * List of possible validator constructor options
 */
export interface ValidatorConstructorOptions {
	debug?: boolean;
	/**
	 * List of possible error messages
	 */
	messages?: MessagesType;

	/**
	 * using checker function v2?
	 */
	useNewCustomCheckerFunction?: boolean;

	/**
	 * consider null as a value?
	 */
	considerNullAsAValue?: boolean;

	/**
	 * Immediately halt after the first error
	 */
	haltOnFirstError?: boolean

	/**
	 * Default settings for rules
	 */
	defaults?: {
		[key in ValidationRuleName]: ValidationSchema;
	};

	/**
	 * For set aliases
	 */
	aliases?: {
		[key: string]: ValidationRuleObject;
	};

	/**
	 * For set custom rules.
	 */
	customRules?: {
		[key: string]: CompilationFunction;
	};

	/**
	 * For set plugins.
	 */
	plugins?: PluginFn<any>[];
}

export interface CompilationRule {
	index: number;
	ruleFunction: CompilationFunction;
	schema: ValidationSchema;
	messages: MessagesType;
}

export interface Context<DATA = any> {
	index: number;
	async: boolean;
	rules: ValidationRuleObject[];
	fn: Function[];
	customs: {
		[ruleName: string]: { schema: RuleCustom; messages: MessagesType };
	};
	meta?: object;
	data: DATA;
}

export interface CheckerFunctionError {
	type: string;
	expected?: unknown;
	actual?: unknown;
	field?: string;
}

export type CheckerFunctionV1<T = unknown> = (
	value: T,
	ruleSchema: ValidationRuleObject,
	path: string,
	parent: object | null,
	context: Context
) => true | ValidationError[];
export type CheckerFunctionV2<T = unknown> = (
	value: T,
	errors: CheckerFunctionError[],
	ruleSchema: ValidationRuleObject,
	path: string,
	parent: object | null,
	context: Context
) => T;

export type CheckerFunction<T = unknown> =
	| CheckerFunctionV1<T>
	| CheckerFunctionV2<T>;

export type CompilationFunction = (
	rule: CompilationRule,
	path: string,
	context: Context
) => { sanitized?: boolean; source: string };

export type PluginFn<T = void> = (validator: Validator) => T;

export interface CheckFunctionOptions {
	meta?: object | null;
}

export interface SyncCheckFunction {
	(value: any, opts?: CheckFunctionOptions): true | ValidationError[]
	async: false
}

export interface AsyncCheckFunction {
	(value: any, opts?: CheckFunctionOptions): Promise<true | ValidationError[]>
	async: true
}

export default class Validator {
	/**
	 * List of possible error messages
	 */
	messages: MessagesType;

	/**
	 * List of rules attached to current validator
	 */
	rules: { [key: string]: ValidationRuleObject };

	/**
	 * List of aliases attached to current validator
	 */
	aliases: { [key: string]: ValidationRule };

	/**
	 * Constructor of validation class
	 * @param {ValidatorConstructorOptions} opts List of possible validator constructor options
	 */
	constructor(opts?: ValidatorConstructorOptions);

	/**
	 * Register a custom validation rule in validation object
	 * @param {string} type
	 * @param fn
	 */
	add(type: string, fn: CompilationFunction): void;

	/**
	 * Add a message
	 *
	 * @param {String} name
	 * @param {String} message
	 */
	addMessage(name: string, message: string): void;

	/**
	 * Register an alias in validation object
	 * @param {string} name
	 * @param {ValidationRuleObject} validationRule
	 */
	alias(name: string, validationRule: ValidationRuleObject): void;

	/**
	 * Add a plugin
	 *
	 * @param {Function} fn
	 */
	plugin<T = void>(fn: PluginFn<T>): T;

	/**
	 * Build error message
	 * @return {ValidationError}
	 * @param {Object} opts
	 * @param {String} opts.type
	 * @param {String} opts.field
	 * @param {any=} opts.expected
	 * @param {any=} opts.actual
	 * @param {MessagesType} opts.messages
	 */
	makeError(opts: {
		type: keyof MessagesType;
		field?: string;
		expected?: any;
		actual?: any;
		messages: MessagesType;
	}): string;

	/**
	 * Compile validator functions that working up 100 times faster that native validation process
	 * @param {ValidationSchema | ValidationSchema[]} schema Validation schema definition that should be used for validation
	 * @return {(value: any) => (true | ValidationError[])} function that can be used next for validation of current schema
	 */
	compile<T = any>(
		schema: ValidationSchema<T> | ValidationSchema<T>[]
	): SyncCheckFunction | AsyncCheckFunction;

	/**
	 * Native validation method to validate obj
	 * @param {any} value that should be validated
	 * @param {ValidationSchema} schema Validation schema definition that should be used for validation
	 * @return {{true} | ValidationError[]}
	 */
	validate(
		value: any,
		schema: ValidationSchema
	): true | ValidationError[] | Promise<true | ValidationError[]>;

	/**
	 * Get defined in validator rule
	 * @param {ValidationRuleName | ValidationRuleName[]} name List or name of defined rule
	 * @return {ValidationRule}
	 */
	getRuleFromSchema(
		name: ValidationRuleName | ValidationRuleName[] | ValidationSchema | ValidationSchema[] | { [key: string]: unknown }
	): {
		messages: MessagesType;
		schema: ValidationSchema;
		ruleFunction: Function;
	};

	/**
	 * Normalize a schema, type or short hand definition by expanding it to a full form. The 'normalized'
	 * form is the equivalent schema with any short hands undone. This ensure that each rule; always includes
	 * a 'type' key, arrays always have an 'items' key, 'multi' always have a 'rules' key and objects always
	 * have their properties defined in a 'props' key
	 *
	 * @param { ValidationSchema | string | any } value The value to normalize
	 * @return {ValidationRule | ValidationSchema } The normalized form of the given rule or schema
	 */
	normalize(
		value: ValidationSchema | string | any
	): ValidationRule | ValidationSchema
}
