import { IndexKey } from '@tldraw/utils';
import { JsonValue } from '@tldraw/utils';
import { MakeUndefinedOptional } from '@tldraw/utils';

/**
 * Validator that accepts any value and types it as 'any'. This should generally be avoided
 * as it bypasses type safety, but can be used as an escape hatch for prototyping.
 *
 * @example
 * ```ts
 * const result = T.any.validate(anything) // Returns the value as any
 * // result is typed as any - use with caution!
 * ```
 * @public
 */
declare const any: Validator<any>;

/**
 * Validator that ensures a value is an array. Does not validate the contents of the array.
 * Use T.arrayOf() to validate both the array structure and its contents.
 *
 * @example
 * ```ts
 * const items = T.array.validate([1, "hello", true]) // Returns unknown[]
 * T.array.validate("not array") // Throws ValidationError: "Expected an array, got a string"
 *
 * // For typed arrays, use T.arrayOf:
 * const numbers = T.arrayOf(T.number).validate([1, 2, 3]) // Returns number[]
 * ```
 * @public
 */
declare const array: Validator<unknown[]>;

/**
 * Creates a validator for arrays where each element is validated using the provided validator.
 *
 * @param itemValidator - Validator to use for each array element
 * @returns An ArrayOfValidator that validates both array structure and element types
 * @throws ValidationError When the value is not an array or when any element is invalid
 * @example
 * ```ts
 * const numberArray = T.arrayOf(T.number)
 * numberArray.validate([1, 2, 3]) // Returns number[]
 * numberArray.validate([1, "2", 3]) // Throws ValidationError at index 1
 *
 * const userArray = T.arrayOf(T.object({ name: T.string, age: T.number }))
 * ```
 * @public
 */
declare function arrayOf<T>(itemValidator: Validatable<T>): ArrayOfValidator<T>;

/**
 * Validator for arrays where each element is validated using the provided item validator.
 * Extends the base Validator class with array-specific validation methods.
 *
 * @example
 * ```ts
 * const stringArray = new ArrayOfValidator(T.string)
 * const numbers = stringArray.validate(["a", "b", "c"]) // Returns string[]
 *
 * const userArray = T.arrayOf(T.object({ name: T.string, age: T.number }))
 * ```
 * @public
 */
export declare class ArrayOfValidator<T> extends Validator<T[]> {
    readonly itemValidator: Validatable<T>;
    /**
     * Creates a new ArrayOfValidator.
     *
     * itemValidator - Validator used to validate each array element
     */
    constructor(itemValidator: Validatable<T>);
    /**
     * Returns a new validator that ensures the array is not empty.
     *
     * @returns A new validator that rejects empty arrays
     * @throws ValidationError When the array is empty
     * @example
     * ```ts
     * const nonEmptyStrings = T.arrayOf(T.string).nonEmpty()
     * nonEmptyStrings.validate(["hello"]) // Valid
     * nonEmptyStrings.validate([]) // Throws ValidationError
     * ```
     */
    nonEmpty(): Validator<T[]>;
    /**
     * Returns a new validator that ensures the array has more than one element.
     *
     * @returns A new validator that requires at least 2 elements
     * @throws ValidationError When the array has 1 or fewer elements
     * @example
     * ```ts
     * const multipleItems = T.arrayOf(T.string).lengthGreaterThan1()
     * multipleItems.validate(["a", "b"]) // Valid
     * multipleItems.validate(["a"]) // Throws ValidationError
     * ```
     */
    lengthGreaterThan1(): Validator<T[]>;
}

/**
 * Validator that ensures a value is a bigint.
 *
 * @example
 * ```ts
 * const largeNumber = T.bigint.validate(123n) // Returns 123n
 * T.bigint.validate(123) // Throws ValidationError: "Expected bigint, got a number"
 * ```
 * @public
 */
declare const bigint: Validator<bigint>;

/**
 * Validator that ensures a value is a boolean.
 *
 * @example
 * ```ts
 * const isActive = T.boolean.validate(true) // Returns true
 * const isEnabled = T.boolean.validate(false) // Returns false
 * T.boolean.validate("true") // Throws ValidationError: "Expected boolean, got a string"
 * ```
 * @public
 */
declare const boolean: Validator<boolean>;

/**
 * Creates a validator for dictionary objects where both keys and values are validated.
 * Useful for validating objects used as key-value maps.
 *
 * @param keyValidator - Validator for object keys
 * @param valueValidator - Validator for object values
 * @returns A DictValidator that validates all keys and values
 * @throws ValidationError When any key or value is invalid
 * @example
 * ```ts
 * const scores = T.dict(T.string, T.number)
 * scores.validate({ "alice": 100, "bob": 85 }) // Valid
 *
 * const userPrefs = T.dict(T.string, T.object({
 *   theme: T.literalEnum('light', 'dark'),
 *   notifications: T.boolean
 * }))
 * ```
 * @public
 */
declare function dict<Key extends string, Value>(keyValidator: Validatable<Key>, valueValidator: Validatable<Value>): DictValidator<Key, Value>;

/**
 * Validator for dictionary/map objects where both keys and values are validated.
 * Useful for validating objects used as key-value stores.
 *
 * @example
 * ```ts
 * const scoreDict = new DictValidator(T.string, T.number)
 * const scores = scoreDict.validate({
 *   "alice": 100,
 *   "bob": 85,
 *   "charlie": 92
 * })
 * // scores is typed as Record<string, number>
 * ```
 * @public
 */
export declare class DictValidator<Key extends string, Value> extends Validator<Record<Key, Value>> {
    readonly keyValidator: Validatable<Key>;
    readonly valueValidator: Validatable<Value>;
    /**
     * Creates a new DictValidator.
     *
     * keyValidator - Validator for object keys
     * valueValidator - Validator for object values
     */
    constructor(keyValidator: Validatable<Key>, valueValidator: Validatable<Value>);
}

/**
 * Validator for HTTP and HTTPS URLs only. Rejects all other protocols.
 *
 * @example
 * ```ts
 * const apiUrl = T.httpUrl.validate("https://api.example.com") // Valid
 * const httpUrl = T.httpUrl.validate("http://localhost:3000") // Valid
 * T.httpUrl.validate("") // Valid (empty string allowed)
 * T.httpUrl.validate("ftp://files.example.com") // Throws ValidationError (not http/https)
 * ```
 * @public
 */
declare const httpUrl: Validator<string>;

/**
 * Validator for IndexKey values used in tldraw's indexing system. An IndexKey is a string
 * that meets specific format requirements for use as a database index.
 *
 * @throws ValidationError When the string is not a valid IndexKey format
 * @example
 * ```ts
 * const key = T.indexKey.validate("valid_index_key") // Returns IndexKey
 * T.indexKey.validate("invalid key!") // Throws ValidationError (invalid format)
 * ```
 * @public
 */
declare const indexKey: Validator<IndexKey>;

/**
 * Validator that ensures a value is an integer (whole number).
 *
 * @example
 * ```ts
 * const count = T.integer.validate(42) // Returns 42
 * T.integer.validate(3.14) // Throws ValidationError: "Expected an integer, got 3.14"
 * T.integer.validate(-5) // Returns -5 (negative integers are valid)
 * ```
 * @public
 */
declare const integer: Validator<number>;

/**
 * Creates a validator for JSON dictionaries (objects with string keys and JSON-serializable values).
 *
 * @returns A DictValidator that validates string keys and JSON values
 * @throws ValidationError When keys are not strings or values are not JSON-serializable
 * @example
 * ```ts
 * const config = T.jsonDict().validate({
 *   "setting1": "value",
 *   "setting2": 42,
 *   "setting3": ["a", "b", "c"],
 *   "setting4": { nested: true }
 * })
 * ```
 * @public
 */
declare function jsonDict(): DictValidator<string, JsonValue>;

/**
 * Validator that ensures a value is valid JSON (string, number, boolean, null, array, or plain object).
 * Rejects functions, undefined, symbols, and other non-JSON values.
 *
 * @example
 * ```ts
 * const data = T.jsonValue.validate({ name: "Alice", scores: [1, 2, 3], active: true })
 * T.jsonValue.validate(undefined) // Throws ValidationError
 * T.jsonValue.validate(() => {}) // Throws ValidationError
 * ```
 * @public
 */
declare const jsonValue: Validator<JsonValue>;

/**
 * Validator for URLs that are safe to use as user-facing links. Accepts http, https, and mailto protocols.
 * This validator provides security by rejecting potentially dangerous protocols like javascript:.
 *
 * @example
 * ```ts
 * const link = T.linkUrl.validate("https://example.com") // Valid
 * const email = T.linkUrl.validate("mailto:user@example.com") // Valid
 * T.linkUrl.validate("") // Valid (empty string allowed)
 * T.linkUrl.validate("javascript:alert(1)") // Throws ValidationError (unsafe protocol)
 * ```
 * @public
 */
declare const linkUrl: Validator<string>;

/**
 * Creates a validator that only accepts a specific literal value.
 *
 * @param expectedValue - The exact value that must be matched
 * @returns A validator that only accepts the specified literal value
 * @throws ValidationError When the value doesn't match the expected literal
 * @example
 * ```ts
 * const trueValidator = T.literal(true)
 * trueValidator.validate(true) // Returns true
 * trueValidator.validate(false) // Throws ValidationError
 *
 * const statusValidator = T.literal("active")
 * statusValidator.validate("active") // Returns "active"
 * statusValidator.validate("inactive") // Throws ValidationError
 * ```
 * @public
 */
declare function literal<T extends boolean | number | string>(expectedValue: T): Validator<T>;

/**
 * Creates a validator that only accepts one of the provided literal values.
 * This is a convenience function that creates a setEnum from the provided values.
 *
 * @param values - The allowed literal values
 * @returns A validator that only accepts the provided literal values
 * @throws ValidationError When the value is not one of the allowed literals
 * @example
 * ```ts
 * const themeValidator = T.literalEnum('light', 'dark', 'auto')
 * themeValidator.validate('light') // Returns 'light'
 * themeValidator.validate('blue') // Throws ValidationError: Expected "light" or "dark" or "auto", got blue
 * ```
 * @public
 */
declare function literalEnum<const Values extends readonly unknown[]>(...values: Values): Validator<Values[number]>;

/**
 * Creates a validator for named model objects with enhanced error reporting. The model name
 * will be included in error messages to provide better debugging context.
 *
 * @param name - The name of the model (used in error messages)
 * @param validator - The validator for the model structure
 * @returns A Validator with enhanced error reporting that includes the model name
 * @throws ValidationError With model name context when validation fails
 * @example
 * ```ts
 * const userModel = T.model('User', T.object({
 *   id: T.string,
 *   name: T.string,
 *   email: T.linkUrl
 * }))
 *
 * // Error message will be: "At User.email: Expected a valid url, got 'invalid-email'"
 * ```
 * @public
 */
declare function model<T extends {
    readonly id: string;
}>(name: string, validator: Validatable<T>): Validator<T>;

/**
 * Validator that ensures a value is a finite, non-zero number. Allows negative numbers.
 * Useful for scale factors that can be negative (for flipping) but not zero.
 *
 * @example
 * ```ts
 * const scale = T.nonZeroFiniteNumber.validate(-1.5) // Returns -1.5 (valid, allows negative)
 * T.nonZeroFiniteNumber.validate(0) // Throws ValidationError: "Expected a non-zero number, got 0"
 * T.nonZeroFiniteNumber.validate(Infinity) // Throws ValidationError
 * ```
 * @public
 */
declare const nonZeroFiniteNumber: Validator<number>;

/**
 * Validator that ensures a value is a positive integer (\> 0). Rejects zero and negative integers.
 *
 * @example
 * ```ts
 * const itemCount = T.nonZeroInteger.validate(1) // Returns 1
 * T.nonZeroInteger.validate(0) // Throws ValidationError: "Expected a non-zero positive integer, got 0"
 * T.nonZeroInteger.validate(-5) // Throws ValidationError: "Expected a non-zero positive integer, got -5"
 * ```
 * @public
 */
declare const nonZeroInteger: Validator<number>;

/**
 * Validator that ensures a value is a positive number (\> 0). Rejects zero and negative numbers.
 *
 * @example
 * ```ts
 * const quantity = T.nonZeroNumber.validate(0.01) // Returns 0.01
 * T.nonZeroNumber.validate(0) // Throws ValidationError: "Expected a non-zero positive number, got 0"
 * T.nonZeroNumber.validate(-5) // Throws ValidationError: "Expected a non-zero positive number, got -5"
 * ```
 * @public
 */
declare const nonZeroNumber: Validator<number>;

/**
 * Creates a validator that accepts either the validated type or null.
 *
 * @param validator - The base validator to make nullable
 * @returns A validator that accepts T or null
 * @example
 * ```ts
 * const nullableString = T.nullable(T.string)
 * nullableString.validate("hello") // Returns "hello"
 * nullableString.validate(null) // Returns null
 * nullableString.validate(undefined) // Throws ValidationError
 * ```
 * @public
 */
declare function nullable<T>(validator: Validatable<T>): Validator<null | T>;

/**
 * Validator that ensures a value is a finite, non-NaN number. Rejects Infinity, -Infinity, and NaN.
 *
 * @example
 * ```ts
 * const count = T.number.validate(42) // Returns 42 as number
 * T.number.validate(NaN) // Throws ValidationError: "Expected a number, got NaN"
 * T.number.validate(Infinity) // Throws ValidationError: "Expected a finite number, got Infinity"
 * ```
 * @public
 */
declare const number: Validator<number>;

/* Excluded from this release type: numberUnion */

/**
 * Creates a validator for objects with a defined shape. Each property is validated using
 * its corresponding validator from the config object.
 *
 * @param config - Object mapping property names to their validators
 * @returns An ObjectValidator that validates the object structure and all properties
 * @throws ValidationError When the value is not an object or when any property is invalid
 * @example
 * ```ts
 * const userValidator = T.object({
 *   name: T.string,
 *   age: T.number,
 *   email: T.string.optional(),
 *   isActive: T.boolean
 * })
 *
 * const user = userValidator.validate({
 *   name: "Alice",
 *   age: 25,
 *   email: "alice@example.com",
 *   isActive: true
 * })
 * // user is typed with full type safety
 * ```
 * @public
 */
declare function object<Shape extends object>(config: {
    readonly [K in keyof Shape]: Validatable<Shape[K]>;
}): ObjectValidator<MakeUndefinedOptional<Shape>>;

/**
 * Validator for objects with a defined shape. Each property is validated using its corresponding
 * validator from the config object. Can be configured to allow or reject unknown properties.
 *
 * @example
 * ```ts
 * const userValidator = new ObjectValidator({
 *   name: T.string,
 *   age: T.number,
 *   email: T.string.optional()
 * })
 *
 * const user = userValidator.validate({
 *   name: "Alice",
 *   age: 25,
 *   email: "alice@example.com"
 * })
 * ```
 * @public
 */
export declare class ObjectValidator<Shape extends object> extends Validator<Shape> {
    readonly config: {
        readonly [K in keyof Shape]: Validatable<Shape[K]>;
    };
    private readonly shouldAllowUnknownProperties;
    /**
     * Creates a new ObjectValidator.
     *
     * config - Object mapping property names to their validators
     * shouldAllowUnknownProperties - Whether to allow properties not defined in config
     */
    constructor(config: {
        readonly [K in keyof Shape]: Validatable<Shape[K]>;
    }, shouldAllowUnknownProperties?: boolean);
    /**
     * Returns a new validator that allows unknown properties in the validated object.
     *
     * @returns A new ObjectValidator that accepts extra properties
     * @example
     * ```ts
     * const flexibleUser = T.object({ name: T.string }).allowUnknownProperties()
     * flexibleUser.validate({ name: "Alice", extra: "allowed" }) // Valid
     * ```
     */
    allowUnknownProperties(): ObjectValidator<Shape>;
    /**
     * Creates a new ObjectValidator by extending this validator with additional properties.
     *
     * @param extension - Object mapping new property names to their validators
     * @returns A new ObjectValidator that validates both original and extended properties
     * @example
     * ```ts
     * const baseUser = T.object({ name: T.string, age: T.number })
     * const adminUser = baseUser.extend({
     *   permissions: T.arrayOf(T.string),
     *   isAdmin: T.boolean
     * })
     * // adminUser validates: { name: string; age: number; permissions: string[]; isAdmin: boolean }
     * ```
     */
    extend<Extension extends Record<string, unknown>>(extension: {
        readonly [K in keyof Extension]: Validatable<Extension[K]>;
    }): ObjectValidator<Shape & Extension>;
}

/**
 * Creates a validator that accepts either the validated type or undefined.
 *
 * @param validator - The base validator to make optional
 * @returns A validator that accepts T or undefined
 * @example
 * ```ts
 * const optionalString = T.optional(T.string)
 * optionalString.validate("hello") // Returns "hello"
 * optionalString.validate(undefined) // Returns undefined
 * optionalString.validate(null) // Throws ValidationError
 * ```
 * @public
 */
declare function optional<T>(validator: Validatable<T>): Validator<T | undefined>;

/**
 * Creates a validator that accepts values matching either of two validators.
 * Tries the first validator, and if it fails, tries the second validator.
 *
 * @param v1 - The first validator to try
 * @param v2 - The second validator to try if the first fails
 * @returns A validator that accepts values matching either validator
 * @throws ValidationError When the value matches neither validator (throws error from v2)
 * @example
 * ```ts
 * const stringOrNumber = T.or(T.string, T.number)
 * stringOrNumber.validate("hello") // Returns "hello" as string
 * stringOrNumber.validate(42) // Returns 42 as number
 * stringOrNumber.validate(true) // Throws ValidationError from number validator
 * ```
 * @public
 */
declare function or<T1, T2>(v1: Validatable<T1>, v2: Validatable<T2>): Validator<T1 | T2>;

/**
 * Validator that ensures a value is a non-negative integer (\>= 0).
 * Despite the name "positive", this validator accepts zero.
 *
 * @example
 * ```ts
 * const index = T.positiveInteger.validate(5) // Returns 5
 * const start = T.positiveInteger.validate(0) // Returns 0 (valid)
 * T.positiveInteger.validate(-1) // Throws ValidationError: "Expected a positive integer, got -1"
 * T.positiveInteger.validate(3.14) // Throws ValidationError: "Expected an integer, got 3.14"
 * ```
 * @public
 */
declare const positiveInteger: Validator<number>;

/**
 * Validator that ensures a value is a non-negative number (\>= 0).
 * Despite the name "positive", this validator accepts zero.
 *
 * @example
 * ```ts
 * const price = T.positiveNumber.validate(29.99) // Returns 29.99
 * const free = T.positiveNumber.validate(0) // Returns 0 (valid)
 * T.positiveNumber.validate(-1) // Throws ValidationError: "Expected a positive number, got -1"
 * ```
 * @public
 */
declare const positiveNumber: Validator<number>;

/**
 * Creates a validator that only accepts values from a given Set of allowed values.
 *
 * @param values - Set containing the allowed values
 * @returns A validator that only accepts values from the provided set
 * @throws ValidationError When the value is not in the allowed set
 * @example
 * ```ts
 * const allowedColors = new Set(['red', 'green', 'blue'] as const)
 * const colorValidator = T.setEnum(allowedColors)
 * colorValidator.validate('red') // Returns 'red'
 * colorValidator.validate('yellow') // Throws ValidationError
 * ```
 * @public
 */
declare function setEnum<T>(values: ReadonlySet<T>): Validator<T>;

/**
 * Validator for URLs that are safe to use as asset sources. Accepts http, https, data, and asset protocols.
 * The asset: protocol refers to tldraw's local IndexedDB object store.
 *
 * @example
 * ```ts
 * const imageUrl = T.srcUrl.validate("https://example.com/image.png") // Valid
 * const dataUrl = T.srcUrl.validate("data:image/png;base64,iVBORw0...") // Valid
 * const assetUrl = T.srcUrl.validate("asset:abc123") // Valid (local asset reference)
 * T.srcUrl.validate("") // Valid (empty string allowed)
 * ```
 * @public
 */
declare const srcUrl: Validator<string>;

/**
 * Validator that ensures a value is a string.
 *
 * @example
 * ```ts
 * const name = T.string.validate("hello") // Returns "hello" as string
 * T.string.validate(123) // Throws ValidationError: "Expected string, got a number"
 * ```
 * @public
 */
declare const string: Validator<string>;

declare namespace T {
    export {
        literal,
        arrayOf,
        object,
        jsonDict,
        dict,
        union,
        model,
        setEnum,
        optional,
        nullable,
        literalEnum,
        or,
        ValidatorFn,
        ValidatorUsingKnownGoodVersionFn,
        Validatable,
        ValidationError,
        TypeOf,
        Validator,
        ArrayOfValidator,
        ObjectValidator,
        UnionValidatorConfig,
        UnionValidator,
        DictValidator,
        unknown,
        any,
        string,
        number,
        positiveNumber,
        nonZeroNumber,
        nonZeroFiniteNumber,
        unitInterval,
        integer,
        positiveInteger,
        nonZeroInteger,
        boolean,
        bigint,
        array,
        unknownObject,
        jsonValue,
        linkUrl,
        srcUrl,
        httpUrl,
        indexKey
    }
}
export { T }

/**
 * Utility type that extracts the validated type from a Validatable object.
 * Useful for deriving TypeScript types from validator definitions.
 *
 * @example
 * ```ts
 * const userValidator = T.object({ name: T.string, age: T.number })
 * type User = TypeOf<typeof userValidator> // { name: string; age: number }
 * ```
 * @public
 */
declare type TypeOf<V extends Validatable<any>> = V extends Validatable<infer T> ? T : never;

/**
 * Creates a validator for discriminated union types. Validates objects that can be one of
 * several variants, distinguished by a discriminator property.
 *
 * @param key - The discriminator property name used to determine the variant
 * @param config - Object mapping variant names to their validators
 * @returns A UnionValidator that validates based on the discriminator value
 * @throws ValidationError When the discriminator is invalid or the variant validation fails
 * @example
 * ```ts
 * const shapeValidator = T.union('type', {
 *   circle: T.object({ type: T.literal('circle'), radius: T.number }),
 *   square: T.object({ type: T.literal('square'), size: T.number }),
 *   triangle: T.object({ type: T.literal('triangle'), base: T.number, height: T.number })
 * })
 *
 * const circle = shapeValidator.validate({ type: 'circle', radius: 5 })
 * // circle is typed as { type: 'circle'; radius: number }
 * ```
 * @public
 */
declare function union<Key extends string, Config extends UnionValidatorConfig<Key, Config>>(key: Key, config: Config): UnionValidator<Key, Config>;

/**
 * Validator for discriminated union types. Validates objects that can be one of several variants,
 * distinguished by a discriminator property (key) that indicates which variant the object represents.
 *
 * @example
 * ```ts
 * const shapeValidator = new UnionValidator('type', {
 *   circle: T.object({ type: T.literal('circle'), radius: T.number }),
 *   square: T.object({ type: T.literal('square'), size: T.number })
 * }, () => { throw new Error('Unknown shape') }, false)
 *
 * const circle = shapeValidator.validate({ type: 'circle', radius: 5 })
 * // circle is typed as { type: 'circle'; radius: number }
 * ```
 * @public
 */
export declare class UnionValidator<Key extends string, Config extends UnionValidatorConfig<Key, Config>, UnknownValue = never> extends Validator<TypeOf<Config[keyof Config]> | UnknownValue> {
    private readonly key;
    private readonly config;
    private readonly unknownValueValidation;
    private readonly useNumberKeys;
    /**
     * Creates a new UnionValidator.
     *
     * key - The discriminator property name used to determine the variant
     * config - Object mapping variant names to their validators
     * unknownValueValidation - Function to handle unknown variants
     * useNumberKeys - Whether the discriminator uses number keys instead of strings
     */
    constructor(key: Key, config: Config, unknownValueValidation: (value: object, variant: string) => UnknownValue, useNumberKeys: boolean);
    private expectObject;
    private getMatchingSchemaAndVariant;
    /**
     * Returns a new UnionValidator that can handle unknown variants using the provided function.
     *
     * @param unknownValueValidation - Function to validate/transform unknown variants
     * @returns A new UnionValidator that accepts unknown variants
     * @example
     * ```ts
     * const shapeValidator = T.union('type', { circle: circleValidator })
     *   .validateUnknownVariants((obj, variant) => {
     *     console.warn(`Unknown shape type: ${variant}`)
     *     return obj as UnknownShape
     *   })
     * ```
     */
    validateUnknownVariants<Unknown>(unknownValueValidation: (value: object, variant: string) => Unknown): UnionValidator<Key, Config, Unknown>;
}

/**
 * Configuration type for union validators. Each variant must be a validator that produces
 * an object with the discriminator key set to the variant name.
 *
 * @example
 * ```ts
 * type ShapeConfig = UnionValidatorConfig<'type', {
 *   circle: Validatable<{ type: 'circle'; radius: number }>
 *   square: Validatable<{ type: 'square'; size: number }>
 * }>
 * ```
 * @public
 */
export declare type UnionValidatorConfig<Key extends string, Config> = {
    readonly [Variant in keyof Config]: Validatable<any> & {
        validate(input: any): {
            readonly [K in Key]: Variant;
        };
    };
};

/**
 * Validator that ensures a value is a number in the unit interval [0, 1].
 * Useful for opacity, percentages expressed as decimals, and other normalized values.
 *
 * @example
 * ```ts
 * const opacity = T.unitInterval.validate(0.5) // Returns 0.5
 * T.unitInterval.validate(0) // Returns 0 (valid)
 * T.unitInterval.validate(1) // Returns 1 (valid)
 * T.unitInterval.validate(1.5) // Throws ValidationError
 * T.unitInterval.validate(-0.1) // Throws ValidationError
 * ```
 * @public
 */
declare const unitInterval: Validator<number>;

/**
 * Validator that accepts any value without type checking. Useful as a starting point for
 * building custom validations or when you need to accept truly unknown data.
 *
 * @example
 * ```ts
 * const result = T.unknown.validate(anything) // Returns the value as-is
 * // result is typed as unknown
 * ```
 * @public
 */
declare const unknown: Validator<unknown>;

/**
 * Validator that ensures a value is an object (non-null, non-array). Does not validate
 * the properties of the object.
 *
 * @example
 * ```ts
 * const obj = T.unknownObject.validate({ any: "properties" }) // Returns Record<string, unknown>
 * T.unknownObject.validate(null) // Throws ValidationError: "Expected object, got null"
 * T.unknownObject.validate([1, 2, 3]) // Throws ValidationError: "Expected object, got an array"
 * ```
 * @public
 */
declare const unknownObject: Validator<Record<string, unknown>>;

/**
 * Interface for objects that can validate unknown values and return typed results.
 * This is the core interface implemented by all validators in the validation system.
 *
 * @example
 * ```ts
 * const customValidator: Validatable<number> = {
 *   validate(value) {
 *     if (typeof value !== 'number') {
 *       throw new ValidationError('Expected number')
 *     }
 *     return value
 *   }
 * }
 * ```
 * @public
 */
declare interface Validatable<T> {
    /**
     * Validates an unknown value and returns it with the correct type.
     *
     * @param value - The unknown value to validate
     * @returns The validated value with type T
     * @throws ValidationError When validation fails
     */
    validate(value: unknown): T;
    /**
     * Performance-optimized validation that can use a previously validated value
     * to avoid revalidating unchanged parts of the data structure.
     *
     * If the value has not changed but is not referentially equal, the function
     * should return the previous value.
     *
     * @param knownGoodValue - A previously validated value
     * @param newValue - The new value to validate
     * @returns The validated value, potentially reusing the known good value for performance
     * @throws ValidationError When validation fails
     */
    validateUsingKnownGoodVersion?(knownGoodValue: T, newValue: unknown): T;
}

/**
 * Error thrown when validation fails. Provides detailed information about what went wrong
 * and where in the data structure the error occurred.
 *
 * @example
 * ```ts
 * try {
 *   validator.validate(invalidData)
 * } catch (error) {
 *   if (error instanceof ValidationError) {
 *     console.log(error.message) // "At users.0.email: Expected valid URL"
 *     console.log(error.path) // ['users', 0, 'email']
 *     console.log(error.rawMessage) // "Expected valid URL"
 *   }
 * }
 * ```
 * @public
 */
declare class ValidationError extends Error {
    readonly rawMessage: string;
    readonly path: ReadonlyArray<number | string>;
    name: string;
    /**
     * Creates a new ValidationError with contextual information about where the error occurred.
     *
     * rawMessage - The raw error message without path information
     * path - Array indicating the location in the data structure where validation failed
     */
    constructor(rawMessage: string, path?: ReadonlyArray<number | string>);
}

/**
 * The main validator class that implements the Validatable interface. This is the base class
 * for all validators and provides methods for validation, type checking, and composing validators.
 *
 * @example
 * ```ts
 * const numberValidator = new Validator((value) => {
 *   if (typeof value !== 'number') {
 *     throw new ValidationError('Expected number')
 *   }
 *   return value
 * })
 *
 * const result = numberValidator.validate(42) // Returns 42 as number
 * ```
 * @public
 */
export declare class Validator<T> implements Validatable<T> {
    readonly validationFn: ValidatorFn<T>;
    readonly validateUsingKnownGoodVersionFn?: undefined | ValidatorUsingKnownGoodVersionFn<T, T>;
    /* Excluded from this release type: skipSameValueCheck */
    /**
     * Creates a new Validator instance.
     *
     * validationFn - Function that validates and returns a value of type T
     * validateUsingKnownGoodVersionFn - Optional performance-optimized validation function
     * skipSameValueCheck - Internal flag to skip dev check for validators that transform values
     */
    constructor(validationFn: ValidatorFn<T>, validateUsingKnownGoodVersionFn?: undefined | ValidatorUsingKnownGoodVersionFn<T, T>, 
    /** @internal */
    skipSameValueCheck?: boolean);
    /**
     * Validates an unknown value and returns it with the correct type. The returned value is
     * guaranteed to be referentially equal to the passed value.
     *
     * @param value - The unknown value to validate
     * @returns The validated value with type T
     * @throws ValidationError When validation fails
     * @example
     * ```ts
     * import { T } from '@tldraw/validate'
     *
     * const name = T.string.validate("Alice") // Returns "Alice" as string
     * const title = T.string.validate("") // Returns "" (empty strings are valid)
     *
     * // These will throw ValidationError:
     * T.string.validate(123) // Expected string, got a number
     * T.string.validate(null) // Expected string, got null
     * T.string.validate(undefined) // Expected string, got undefined
     * ```
     */
    validate(value: unknown): T;
    /**
     * Performance-optimized validation using a previously validated value. If the new value
     * is referentially equal to the known good value, returns the known good value immediately.
     *
     * @param knownGoodValue - A previously validated value
     * @param newValue - The new value to validate
     * @returns The validated value, potentially reusing the known good value
     * @throws ValidationError When validation fails
     * @example
     * ```ts
     * import { T } from '@tldraw/validate'
     *
     * const userValidator = T.object({
     *   name: T.string,
     *   settings: T.object({ theme: T.literalEnum('light', 'dark') })
     * })
     *
     * const user = userValidator.validate({ name: "Alice", settings: { theme: "light" } })
     *
     * // Later, with partially changed data:
     * const newData = { name: "Alice", settings: { theme: "dark" } }
     * const updated = userValidator.validateUsingKnownGoodVersion(user, newData)
     * // Only validates the changed 'theme' field for better performance
     * ```
     */
    validateUsingKnownGoodVersion(knownGoodValue: T, newValue: unknown): T;
    /**
     * Type guard that checks if a value is valid without throwing an error.
     *
     * @param value - The value to check
     * @returns True if the value is valid, false otherwise
     * @example
     * ```ts
     * import { T } from '@tldraw/validate'
     *
     * function processUserInput(input: unknown) {
     *   if (T.string.isValid(input)) {
     *     // input is now typed as string within this block
     *     return input.toUpperCase()
     *   }
     *   if (T.number.isValid(input)) {
     *     // input is now typed as number within this block
     *     return input.toFixed(2)
     *   }
     *   throw new Error('Expected string or number')
     * }
     * ```
     */
    isValid(value: unknown): value is T;
    /**
     * Returns a new validator that also accepts null values.
     *
     * @returns A new validator that accepts T or null
     * @example
     * ```ts
     * import { T } from '@tldraw/validate'
     *
     * const assetValidator = T.object({
     *   id: T.string,
     *   name: T.string,
     *   src: T.srcUrl.nullable(), // Can be null if not loaded yet
     *   mimeType: T.string.nullable()
     * })
     *
     * const asset = assetValidator.validate({
     *   id: "image-123",
     *   name: "photo.jpg",
     *   src: null, // Valid - asset not loaded yet
     *   mimeType: "image/jpeg"
     * })
     * ```
     */
    nullable(): Validator<null | T>;
    /**
     * Returns a new validator that also accepts undefined values.
     *
     * @returns A new validator that accepts T or undefined
     * @example
     * ```ts
     * import { T } from '@tldraw/validate'
     *
     * const shapeConfigValidator = T.object({
     *   type: T.literal('rectangle'),
     *   x: T.number,
     *   y: T.number,
     *   label: T.string.optional(), // Optional property
     *   metadata: T.object({ created: T.string }).optional()
     * })
     *
     * // Both of these are valid:
     * const shape1 = shapeConfigValidator.validate({ type: 'rectangle', x: 0, y: 0 })
     * const shape2 = shapeConfigValidator.validate({
     *   type: 'rectangle', x: 0, y: 0, label: "My Shape"
     * })
     * ```
     */
    optional(): Validator<T | undefined>;
    /**
     * Creates a new validator by refining this validator with additional logic that can transform
     * the validated value to a new type.
     *
     * @param otherValidationFn - Function that transforms/validates the value to type U
     * @returns A new validator that validates to type U
     * @throws ValidationError When validation or refinement fails
     * @example
     * ```ts
     * import { T, ValidationError } from '@tldraw/validate'
     *
     * // Transform string to ensure it starts with a prefix
     * const prefixedIdValidator = T.string.refine((id) => {
     *   return id.startsWith('shape:') ? id : `shape:${id}`
     * })
     *
     * const id1 = prefixedIdValidator.validate("rectangle-123") // Returns "shape:rectangle-123"
     * const id2 = prefixedIdValidator.validate("shape:circle-456") // Returns "shape:circle-456"
     *
     * // Parse and validate JSON strings
     * const jsonValidator = T.string.refine((str) => {
     *   try {
     *     return JSON.parse(str)
     *   } catch {
     *     throw new ValidationError('Invalid JSON string')
     *   }
     * })
     * ```
     */
    refine<U>(otherValidationFn: (value: T) => U): Validator<U>;
    /**
     * Adds an additional validation check without changing the resulting value type.
     * Can be called with just a check function, or with a name for better error messages.
     *
     * @param name - Name for the check (used in error messages)
     * @param checkFn - Function that validates the value (should throw on invalid input)
     * @returns A new validator with the additional check
     * @throws ValidationError When the check fails
     * @example
     * ```ts
     * import { T, ValidationError } from '@tldraw/validate'
     *
     * // Basic check without name
     * const evenNumber = T.number.check((value) => {
     *   if (value % 2 !== 0) {
     *     throw new ValidationError('Expected even number')
     *   }
     * })
     *
     * // Named checks for better error messages in complex validators
     * const shapePositionValidator = T.object({
     *   x: T.number.check('finite', (value) => {
     *     if (!Number.isFinite(value)) {
     *       throw new ValidationError('Position must be finite')
     *     }
     *   }),
     *   y: T.number.check('within-bounds', (value) => {
     *     if (value < -10000 || value > 10000) {
     *       throw new ValidationError('Position must be within bounds (-10000 to 10000)')
     *     }
     *   })
     * })
     *
     * // Error will be: "At x (check finite): Position must be finite"
     * ```
     */
    check(name: string, checkFn: (value: T) => void): Validator<T>;
    /**
     * Adds an additional validation check without changing the resulting value type.
     *
     * @param checkFn - Function that validates the value (should throw on invalid input)
     * @returns A new validator with the additional check
     * @throws ValidationError When the check fails
     */
    check(checkFn: (value: T) => void): Validator<T>;
}

/**
 * A function that validates and returns a value of type T from unknown input.
 * The function should throw a ValidationError if the value is invalid.
 *
 * @param value - The unknown value to validate
 * @returns The validated value of type T
 * @throws \{ValidationError\} When the value doesn't match the expected type
 * @example
 * ```ts
 * const stringValidator: ValidatorFn<string> = (value) => {
 *   if (typeof value !== 'string') {
 *     throw new ValidationError('Expected string')
 *   }
 *   return value
 * }
 * ```
 * @public
 */
declare type ValidatorFn<T> = (value: unknown) => T;

/**
 * A performance-optimized validation function that can use a previously validated value
 * to avoid revalidating unchanged parts of the data structure.
 *
 * @param knownGoodValue - A previously validated value of type In
 * @param value - The unknown value to validate
 * @returns The validated value of type Out
 * @throws ValidationError When the value doesn't match the expected type
 * @example
 * ```ts
 * const optimizedValidator: ValidatorUsingKnownGoodVersionFn<User> = (
 *   knownGood,
 *   newValue
 * ) => {
 *   if (Object.is(knownGood, newValue)) return knownGood
 *   return fullValidation(newValue)
 * }
 * ```
 * @public
 */
declare type ValidatorUsingKnownGoodVersionFn<In, Out = In> = (knownGoodValue: In, value: unknown) => Out;

export { }
