@tldraw/validate 4.2.0 → 4.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-cjs/index.d.ts +37 -1
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/lib/validation.js +304 -68
- package/dist-cjs/lib/validation.js.map +3 -3
- package/dist-esm/index.d.mts +37 -1
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/validation.mjs +304 -68
- package/dist-esm/lib/validation.mjs.map +3 -3
- package/package.json +2 -2
- package/src/lib/validation.ts +355 -68
- package/src/test/validation.test.ts +38 -5
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/validation.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n\tIndexKey,\n\tJsonValue,\n\tMakeUndefinedOptional,\n\tSTRUCTURED_CLONE_OBJECT_PROTOTYPE,\n\texhaustiveSwitchError,\n\tgetOwnProperty,\n\thasOwnProperty,\n\tvalidateIndexKey,\n} from '@tldraw/utils'\n\n/**\n * A function that validates and returns a value of type T from unknown input.\n * The function should throw a ValidationError if the value is invalid.\n *\n * @param value - The unknown value to validate\n * @returns The validated value of type T\n * @throws \\{ValidationError\\} When the value doesn't match the expected type\n * @example\n * ```ts\n * const stringValidator: ValidatorFn<string> = (value) => {\n * if (typeof value !== 'string') {\n * throw new ValidationError('Expected string')\n * }\n * return value\n * }\n * ```\n * @public\n */\nexport type ValidatorFn<T> = (value: unknown) => T\n/**\n * A performance-optimized validation function that can use a previously validated value\n * to avoid revalidating unchanged parts of the data structure.\n *\n * @param knownGoodValue - A previously validated value of type In\n * @param value - The unknown value to validate\n * @returns The validated value of type Out\n * @throws ValidationError When the value doesn't match the expected type\n * @example\n * ```ts\n * const optimizedValidator: ValidatorUsingKnownGoodVersionFn<User> = (\n * knownGood,\n * newValue\n * ) => {\n * if (Object.is(knownGood, newValue)) return knownGood\n * return fullValidation(newValue)\n * }\n * ```\n * @public\n */\nexport type ValidatorUsingKnownGoodVersionFn<In, Out = In> = (\n\tknownGoodValue: In,\n\tvalue: unknown\n) => Out\n\n/**\n * Interface for objects that can validate unknown values and return typed results.\n * This is the core interface implemented by all validators in the validation system.\n *\n * @example\n * ```ts\n * const customValidator: Validatable<number> = {\n * validate(value) {\n * if (typeof value !== 'number') {\n * throw new ValidationError('Expected number')\n * }\n * return value\n * }\n * }\n * ```\n * @public\n */\nexport interface Validatable<T> {\n\t/**\n\t * Validates an unknown value and returns it with the correct type.\n\t *\n\t * @param value - The unknown value to validate\n\t * @returns The validated value with type T\n\t * @throws ValidationError When validation fails\n\t */\n\tvalidate(value: unknown): T\n\t/**\n\t * Performance-optimized validation that can use a previously validated value\n\t * to avoid revalidating unchanged parts of the data structure.\n\t *\n\t * If the value has not changed but is not referentially equal, the function\n\t * should return the previous value.\n\t *\n\t * @param knownGoodValue - A previously validated value\n\t * @param newValue - The new value to validate\n\t * @returns The validated value, potentially reusing the known good value for performance\n\t * @throws ValidationError When validation fails\n\t */\n\tvalidateUsingKnownGoodVersion?(knownGoodValue: T, newValue: unknown): T\n}\n\nfunction formatPath(path: ReadonlyArray<number | string>): string | null {\n\tif (!path.length) {\n\t\treturn null\n\t}\n\n\tlet formattedPath = ''\n\tfor (const item of path) {\n\t\tif (typeof item === 'number') {\n\t\t\tformattedPath += `.${item}`\n\t\t} else if (item.startsWith('(')) {\n\t\t\tif (formattedPath.endsWith(')')) {\n\t\t\t\tformattedPath = `${formattedPath.slice(0, -1)}, ${item.slice(1)}`\n\t\t\t} else {\n\t\t\t\tformattedPath += item\n\t\t\t}\n\t\t} else {\n\t\t\tformattedPath += `.${item}`\n\t\t}\n\t}\n\n\t// N.B. We don't want id's in the path because they make grouping in Sentry tough.\n\tformattedPath = formattedPath.replace(/id = [^,]+, /, '').replace(/id = [^)]+/, '')\n\n\tif (formattedPath.startsWith('.')) {\n\t\treturn formattedPath.slice(1)\n\t}\n\treturn formattedPath\n}\n\n/**\n * Error thrown when validation fails. Provides detailed information about what went wrong\n * and where in the data structure the error occurred.\n *\n * @example\n * ```ts\n * try {\n * validator.validate(invalidData)\n * } catch (error) {\n * if (error instanceof ValidationError) {\n * console.log(error.message) // \"At users.0.email: Expected valid URL\"\n * console.log(error.path) // ['users', 0, 'email']\n * console.log(error.rawMessage) // \"Expected valid URL\"\n * }\n * }\n * ```\n * @public\n */\nexport class ValidationError extends Error {\n\toverride name = 'ValidationError'\n\n\t/**\n\t * Creates a new ValidationError with contextual information about where the error occurred.\n\t *\n\t * rawMessage - The raw error message without path information\n\t * path - Array indicating the location in the data structure where validation failed\n\t */\n\tconstructor(\n\t\tpublic readonly rawMessage: string,\n\t\tpublic readonly path: ReadonlyArray<number | string> = []\n\t) {\n\t\tconst formattedPath = formatPath(path)\n\t\tconst indentedMessage = rawMessage\n\t\t\t.split('\\n')\n\t\t\t.map((line, i) => (i === 0 ? line : ` ${line}`))\n\t\t\t.join('\\n')\n\t\tsuper(path ? `At ${formattedPath}: ${indentedMessage}` : indentedMessage)\n\t}\n}\n\nfunction prefixError<T>(path: string | number, fn: () => T): T {\n\ttry {\n\t\treturn fn()\n\t} catch (err) {\n\t\tif (err instanceof ValidationError) {\n\t\t\tthrow new ValidationError(err.rawMessage, [path, ...err.path])\n\t\t}\n\t\tthrow new ValidationError((err as Error).toString(), [path])\n\t}\n}\n\nfunction typeToString(value: unknown): string {\n\tif (value === null) return 'null'\n\tif (Array.isArray(value)) return 'an array'\n\tconst type = typeof value\n\tswitch (type) {\n\t\tcase 'bigint':\n\t\tcase 'boolean':\n\t\tcase 'function':\n\t\tcase 'number':\n\t\tcase 'string':\n\t\tcase 'symbol':\n\t\t\treturn `a ${type}`\n\t\tcase 'object':\n\t\t\treturn `an ${type}`\n\t\tcase 'undefined':\n\t\t\treturn 'undefined'\n\t\tdefault:\n\t\t\texhaustiveSwitchError(type)\n\t}\n}\n\n/**\n * Utility type that extracts the validated type from a Validatable object.\n * Useful for deriving TypeScript types from validator definitions.\n *\n * @example\n * ```ts\n * const userValidator = T.object({ name: T.string, age: T.number })\n * type User = TypeOf<typeof userValidator> // { name: string; age: number }\n * ```\n * @public\n */\nexport type TypeOf<V extends Validatable<any>> = V extends Validatable<infer T> ? T : never\n\n/**\n * The main validator class that implements the Validatable interface. This is the base class\n * for all validators and provides methods for validation, type checking, and composing validators.\n *\n * @example\n * ```ts\n * const numberValidator = new Validator((value) => {\n * if (typeof value !== 'number') {\n * throw new ValidationError('Expected number')\n * }\n * return value\n * })\n *\n * const result = numberValidator.validate(42) // Returns 42 as number\n * ```\n * @public\n */\nexport class Validator<T> implements Validatable<T> {\n\t/**\n\t * Creates a new Validator instance.\n\t *\n\t * validationFn - Function that validates and returns a value of type T\n\t * validateUsingKnownGoodVersionFn - Optional performance-optimized validation function\n\t */\n\tconstructor(\n\t\treadonly validationFn: ValidatorFn<T>,\n\t\treadonly validateUsingKnownGoodVersionFn?: ValidatorUsingKnownGoodVersionFn<T>\n\t) {}\n\n\t/**\n\t * Validates an unknown value and returns it with the correct type. The returned value is\n\t * guaranteed to be referentially equal to the passed value.\n\t *\n\t * @param value - The unknown value to validate\n\t * @returns The validated value with type T\n\t * @throws ValidationError When validation fails\n\t * @example\n\t * ```ts\n\t * import { T } from '@tldraw/validate'\n\t *\n\t * const name = T.string.validate(\"Alice\") // Returns \"Alice\" as string\n\t * const title = T.string.validate(\"\") // Returns \"\" (empty strings are valid)\n\t *\n\t * // These will throw ValidationError:\n\t * T.string.validate(123) // Expected string, got a number\n\t * T.string.validate(null) // Expected string, got null\n\t * T.string.validate(undefined) // Expected string, got undefined\n\t * ```\n\t */\n\tvalidate(value: unknown): T {\n\t\tconst validated = this.validationFn(value)\n\t\tif (process.env.NODE_ENV !== 'production' && !Object.is(value, validated)) {\n\t\t\tthrow new ValidationError('Validator functions must return the same value they were passed')\n\t\t}\n\t\treturn validated\n\t}\n\n\t/**\n\t * Performance-optimized validation using a previously validated value. If the new value\n\t * is referentially equal to the known good value, returns the known good value immediately.\n\t *\n\t * @param knownGoodValue - A previously validated value\n\t * @param newValue - The new value to validate\n\t * @returns The validated value, potentially reusing the known good value\n\t * @throws ValidationError When validation fails\n\t * @example\n\t * ```ts\n\t * import { T } from '@tldraw/validate'\n\t *\n\t * const userValidator = T.object({\n\t * name: T.string,\n\t * settings: T.object({ theme: T.literalEnum('light', 'dark') })\n\t * })\n\t *\n\t * const user = userValidator.validate({ name: \"Alice\", settings: { theme: \"light\" } })\n\t *\n\t * // Later, with partially changed data:\n\t * const newData = { name: \"Alice\", settings: { theme: \"dark\" } }\n\t * const updated = userValidator.validateUsingKnownGoodVersion(user, newData)\n\t * // Only validates the changed 'theme' field for better performance\n\t * ```\n\t */\n\tvalidateUsingKnownGoodVersion(knownGoodValue: T, newValue: unknown): T {\n\t\tif (Object.is(knownGoodValue, newValue)) {\n\t\t\treturn knownGoodValue as T\n\t\t}\n\n\t\tif (this.validateUsingKnownGoodVersionFn) {\n\t\t\treturn this.validateUsingKnownGoodVersionFn(knownGoodValue, newValue)\n\t\t}\n\n\t\treturn this.validate(newValue)\n\t}\n\n\t/**\n\t * Type guard that checks if a value is valid without throwing an error.\n\t *\n\t * @param value - The value to check\n\t * @returns True if the value is valid, false otherwise\n\t * @example\n\t * ```ts\n\t * import { T } from '@tldraw/validate'\n\t *\n\t * function processUserInput(input: unknown) {\n\t * if (T.string.isValid(input)) {\n\t * // input is now typed as string within this block\n\t * return input.toUpperCase()\n\t * }\n\t * if (T.number.isValid(input)) {\n\t * // input is now typed as number within this block\n\t * return input.toFixed(2)\n\t * }\n\t * throw new Error('Expected string or number')\n\t * }\n\t * ```\n\t */\n\tisValid(value: unknown): value is T {\n\t\ttry {\n\t\t\tthis.validate(value)\n\t\t\treturn true\n\t\t} catch {\n\t\t\treturn false\n\t\t}\n\t}\n\n\t/**\n\t * Returns a new validator that also accepts null values.\n\t *\n\t * @returns A new validator that accepts T or null\n\t * @example\n\t * ```ts\n\t * import { T } from '@tldraw/validate'\n\t *\n\t * const assetValidator = T.object({\n\t * id: T.string,\n\t * name: T.string,\n\t * src: T.srcUrl.nullable(), // Can be null if not loaded yet\n\t * mimeType: T.string.nullable()\n\t * })\n\t *\n\t * const asset = assetValidator.validate({\n\t * id: \"image-123\",\n\t * name: \"photo.jpg\",\n\t * src: null, // Valid - asset not loaded yet\n\t * mimeType: \"image/jpeg\"\n\t * })\n\t * ```\n\t */\n\tnullable(): Validator<T | null> {\n\t\treturn nullable(this)\n\t}\n\n\t/**\n\t * Returns a new validator that also accepts undefined values.\n\t *\n\t * @returns A new validator that accepts T or undefined\n\t * @example\n\t * ```ts\n\t * import { T } from '@tldraw/validate'\n\t *\n\t * const shapeConfigValidator = T.object({\n\t * type: T.literal('rectangle'),\n\t * x: T.number,\n\t * y: T.number,\n\t * label: T.string.optional(), // Optional property\n\t * metadata: T.object({ created: T.string }).optional()\n\t * })\n\t *\n\t * // Both of these are valid:\n\t * const shape1 = shapeConfigValidator.validate({ type: 'rectangle', x: 0, y: 0 })\n\t * const shape2 = shapeConfigValidator.validate({\n\t * type: 'rectangle', x: 0, y: 0, label: \"My Shape\"\n\t * })\n\t * ```\n\t */\n\toptional(): Validator<T | undefined> {\n\t\treturn optional(this)\n\t}\n\n\t/**\n\t * Creates a new validator by refining this validator with additional logic that can transform\n\t * the validated value to a new type.\n\t *\n\t * @param otherValidationFn - Function that transforms/validates the value to type U\n\t * @returns A new validator that validates to type U\n\t * @throws ValidationError When validation or refinement fails\n\t * @example\n\t * ```ts\n\t * import { T, ValidationError } from '@tldraw/validate'\n\t *\n\t * // Transform string to ensure it starts with a prefix\n\t * const prefixedIdValidator = T.string.refine((id) => {\n\t * return id.startsWith('shape:') ? id : `shape:${id}`\n\t * })\n\t *\n\t * const id1 = prefixedIdValidator.validate(\"rectangle-123\") // Returns \"shape:rectangle-123\"\n\t * const id2 = prefixedIdValidator.validate(\"shape:circle-456\") // Returns \"shape:circle-456\"\n\t *\n\t * // Parse and validate JSON strings\n\t * const jsonValidator = T.string.refine((str) => {\n\t * try {\n\t * return JSON.parse(str)\n\t * } catch {\n\t * throw new ValidationError('Invalid JSON string')\n\t * }\n\t * })\n\t * ```\n\t */\n\trefine<U>(otherValidationFn: (value: T) => U): Validator<U> {\n\t\treturn new Validator(\n\t\t\t(value) => {\n\t\t\t\treturn otherValidationFn(this.validate(value))\n\t\t\t},\n\n\t\t\t(knownGoodValue, newValue) => {\n\t\t\t\tconst validated = this.validateUsingKnownGoodVersion(knownGoodValue as any, newValue)\n\t\t\t\tif (Object.is(knownGoodValue, validated)) {\n\t\t\t\t\treturn knownGoodValue\n\t\t\t\t}\n\t\t\t\treturn otherValidationFn(validated)\n\t\t\t}\n\t\t)\n\t}\n\n\t/**\n\t * Adds an additional validation check without changing the resulting value type.\n\t * Can be called with just a check function, or with a name for better error messages.\n\t *\n\t * @param name - Name for the check (used in error messages)\n\t * @param checkFn - Function that validates the value (should throw on invalid input)\n\t * @returns A new validator with the additional check\n\t * @throws ValidationError When the check fails\n\t * @example\n\t * ```ts\n\t * import { T, ValidationError } from '@tldraw/validate'\n\t *\n\t * // Basic check without name\n\t * const evenNumber = T.number.check((value) => {\n\t * if (value % 2 !== 0) {\n\t * throw new ValidationError('Expected even number')\n\t * }\n\t * })\n\t *\n\t * // Named checks for better error messages in complex validators\n\t * const shapePositionValidator = T.object({\n\t * x: T.number.check('finite', (value) => {\n\t * if (!Number.isFinite(value)) {\n\t * throw new ValidationError('Position must be finite')\n\t * }\n\t * }),\n\t * y: T.number.check('within-bounds', (value) => {\n\t * if (value < -10000 || value > 10000) {\n\t * throw new ValidationError('Position must be within bounds (-10000 to 10000)')\n\t * }\n\t * })\n\t * })\n\t *\n\t * // Error will be: \"At x (check finite): Position must be finite\"\n\t * ```\n\t */\n\tcheck(name: string, checkFn: (value: T) => void): Validator<T>\n\t/**\n\t * Adds an additional validation check without changing the resulting value type.\n\t *\n\t * @param checkFn - Function that validates the value (should throw on invalid input)\n\t * @returns A new validator with the additional check\n\t * @throws ValidationError When the check fails\n\t */\n\tcheck(checkFn: (value: T) => void): Validator<T>\n\tcheck(nameOrCheckFn: string | ((value: T) => void), checkFn?: (value: T) => void): Validator<T> {\n\t\tif (typeof nameOrCheckFn === 'string') {\n\t\t\treturn this.refine((value) => {\n\t\t\t\tprefixError(`(check ${nameOrCheckFn})`, () => checkFn!(value))\n\t\t\t\treturn value\n\t\t\t})\n\t\t} else {\n\t\t\treturn this.refine((value) => {\n\t\t\t\tnameOrCheckFn(value)\n\t\t\t\treturn value\n\t\t\t})\n\t\t}\n\t}\n}\n\n/**\n * Validator for arrays where each element is validated using the provided item validator.\n * Extends the base Validator class with array-specific validation methods.\n *\n * @example\n * ```ts\n * const stringArray = new ArrayOfValidator(T.string)\n * const numbers = stringArray.validate([\"a\", \"b\", \"c\"]) // Returns string[]\n *\n * const userArray = T.arrayOf(T.object({ name: T.string, age: T.number }))\n * ```\n * @public\n */\nexport class ArrayOfValidator<T> extends Validator<T[]> {\n\t/**\n\t * Creates a new ArrayOfValidator.\n\t *\n\t * itemValidator - Validator used to validate each array element\n\t */\n\tconstructor(readonly itemValidator: Validatable<T>) {\n\t\tsuper(\n\t\t\t(value) => {\n\t\t\t\tconst arr = array.validate(value)\n\t\t\t\tfor (let i = 0; i < arr.length; i++) {\n\t\t\t\t\tprefixError(i, () => itemValidator.validate(arr[i]))\n\t\t\t\t}\n\t\t\t\treturn arr as T[]\n\t\t\t},\n\t\t\t(knownGoodValue, newValue) => {\n\t\t\t\tif (!itemValidator.validateUsingKnownGoodVersion) return this.validate(newValue)\n\t\t\t\tconst arr = array.validate(newValue)\n\t\t\t\tlet isDifferent = knownGoodValue.length !== arr.length\n\t\t\t\tfor (let i = 0; i < arr.length; i++) {\n\t\t\t\t\tconst item = arr[i]\n\t\t\t\t\tif (i >= knownGoodValue.length) {\n\t\t\t\t\t\tisDifferent = true\n\t\t\t\t\t\tprefixError(i, () => itemValidator.validate(item))\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\t// sneaky quick check here to avoid the prefix + validator overhead\n\t\t\t\t\tif (Object.is(knownGoodValue[i], item)) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tconst checkedItem = prefixError(i, () =>\n\t\t\t\t\t\titemValidator.validateUsingKnownGoodVersion!(knownGoodValue[i], item)\n\t\t\t\t\t)\n\t\t\t\t\tif (!Object.is(checkedItem, knownGoodValue[i])) {\n\t\t\t\t\t\tisDifferent = true\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn isDifferent ? (newValue as T[]) : knownGoodValue\n\t\t\t}\n\t\t)\n\t}\n\n\t/**\n\t * Returns a new validator that ensures the array is not empty.\n\t *\n\t * @returns A new validator that rejects empty arrays\n\t * @throws ValidationError When the array is empty\n\t * @example\n\t * ```ts\n\t * const nonEmptyStrings = T.arrayOf(T.string).nonEmpty()\n\t * nonEmptyStrings.validate([\"hello\"]) // Valid\n\t * nonEmptyStrings.validate([]) // Throws ValidationError\n\t * ```\n\t */\n\tnonEmpty() {\n\t\treturn this.check((value) => {\n\t\t\tif (value.length === 0) {\n\t\t\t\tthrow new ValidationError('Expected a non-empty array')\n\t\t\t}\n\t\t})\n\t}\n\n\t/**\n\t * Returns a new validator that ensures the array has more than one element.\n\t *\n\t * @returns A new validator that requires at least 2 elements\n\t * @throws ValidationError When the array has 1 or fewer elements\n\t * @example\n\t * ```ts\n\t * const multipleItems = T.arrayOf(T.string).lengthGreaterThan1()\n\t * multipleItems.validate([\"a\", \"b\"]) // Valid\n\t * multipleItems.validate([\"a\"]) // Throws ValidationError\n\t * ```\n\t */\n\tlengthGreaterThan1() {\n\t\treturn this.check((value) => {\n\t\t\tif (value.length <= 1) {\n\t\t\t\tthrow new ValidationError('Expected an array with length greater than 1')\n\t\t\t}\n\t\t})\n\t}\n}\n\n/**\n * Validator for objects with a defined shape. Each property is validated using its corresponding\n * validator from the config object. Can be configured to allow or reject unknown properties.\n *\n * @example\n * ```ts\n * const userValidator = new ObjectValidator({\n * name: T.string,\n * age: T.number,\n * email: T.string.optional()\n * })\n *\n * const user = userValidator.validate({\n * name: \"Alice\",\n * age: 25,\n * email: \"alice@example.com\"\n * })\n * ```\n * @public\n */\nexport class ObjectValidator<Shape extends object> extends Validator<Shape> {\n\t/**\n\t * Creates a new ObjectValidator.\n\t *\n\t * config - Object mapping property names to their validators\n\t * shouldAllowUnknownProperties - Whether to allow properties not defined in config\n\t */\n\tconstructor(\n\t\tpublic readonly config: {\n\t\t\treadonly [K in keyof Shape]: Validatable<Shape[K]>\n\t\t},\n\t\tprivate readonly shouldAllowUnknownProperties = false\n\t) {\n\t\tsuper(\n\t\t\t(object) => {\n\t\t\t\tif (typeof object !== 'object' || object === null) {\n\t\t\t\t\tthrow new ValidationError(`Expected object, got ${typeToString(object)}`)\n\t\t\t\t}\n\n\t\t\t\tfor (const [key, validator] of Object.entries(config)) {\n\t\t\t\t\tprefixError(key, () => {\n\t\t\t\t\t\t;(validator as Validatable<unknown>).validate(getOwnProperty(object, key))\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tif (!shouldAllowUnknownProperties) {\n\t\t\t\t\tfor (const key of Object.keys(object)) {\n\t\t\t\t\t\tif (!hasOwnProperty(config, key)) {\n\t\t\t\t\t\t\tthrow new ValidationError(`Unexpected property`, [key])\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn object as Shape\n\t\t\t},\n\t\t\t(knownGoodValue, newValue) => {\n\t\t\t\tif (typeof newValue !== 'object' || newValue === null) {\n\t\t\t\t\tthrow new ValidationError(`Expected object, got ${typeToString(newValue)}`)\n\t\t\t\t}\n\n\t\t\t\tlet isDifferent = false\n\n\t\t\t\tfor (const [key, validator] of Object.entries(config)) {\n\t\t\t\t\tconst prev = getOwnProperty(knownGoodValue, key)\n\t\t\t\t\tconst next = getOwnProperty(newValue, key)\n\t\t\t\t\t// sneaky quick check here to avoid the prefix + validator overhead\n\t\t\t\t\tif (Object.is(prev, next)) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tconst checked = prefixError(key, () => {\n\t\t\t\t\t\tconst validatable = validator as Validatable<unknown>\n\t\t\t\t\t\tif (validatable.validateUsingKnownGoodVersion) {\n\t\t\t\t\t\t\treturn validatable.validateUsingKnownGoodVersion(prev, next)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn validatable.validate(next)\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\tif (!Object.is(checked, prev)) {\n\t\t\t\t\t\tisDifferent = true\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!shouldAllowUnknownProperties) {\n\t\t\t\t\tfor (const key of Object.keys(newValue)) {\n\t\t\t\t\t\tif (!hasOwnProperty(config, key)) {\n\t\t\t\t\t\t\tthrow new ValidationError(`Unexpected property`, [key])\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (const key of Object.keys(knownGoodValue)) {\n\t\t\t\t\tif (!hasOwnProperty(newValue, key)) {\n\t\t\t\t\t\tisDifferent = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn isDifferent ? (newValue as Shape) : knownGoodValue\n\t\t\t}\n\t\t)\n\t}\n\n\t/**\n\t * Returns a new validator that allows unknown properties in the validated object.\n\t *\n\t * @returns A new ObjectValidator that accepts extra properties\n\t * @example\n\t * ```ts\n\t * const flexibleUser = T.object({ name: T.string }).allowUnknownProperties()\n\t * flexibleUser.validate({ name: \"Alice\", extra: \"allowed\" }) // Valid\n\t * ```\n\t */\n\tallowUnknownProperties() {\n\t\treturn new ObjectValidator(this.config, true)\n\t}\n\n\t/**\n\t * Creates a new ObjectValidator by extending this validator with additional properties.\n\t *\n\t * @param extension - Object mapping new property names to their validators\n\t * @returns A new ObjectValidator that validates both original and extended properties\n\t * @example\n\t * ```ts\n\t * const baseUser = T.object({ name: T.string, age: T.number })\n\t * const adminUser = baseUser.extend({\n\t * permissions: T.arrayOf(T.string),\n\t * isAdmin: T.boolean\n\t * })\n\t * // adminUser validates: { name: string; age: number; permissions: string[]; isAdmin: boolean }\n\t * ```\n\t */\n\textend<Extension extends Record<string, unknown>>(extension: {\n\t\treadonly [K in keyof Extension]: Validatable<Extension[K]>\n\t}): ObjectValidator<Shape & Extension> {\n\t\treturn new ObjectValidator({ ...this.config, ...extension }) as any as ObjectValidator<\n\t\t\tShape & Extension\n\t\t>\n\t}\n}\n\n/**\n * Configuration type for union validators. Each variant must be a validator that produces\n * an object with the discriminator key set to the variant name.\n *\n * @example\n * ```ts\n * type ShapeConfig = UnionValidatorConfig<'type', {\n * circle: Validatable<{ type: 'circle'; radius: number }>\n * square: Validatable<{ type: 'square'; size: number }>\n * }>\n * ```\n * @public\n */\nexport type UnionValidatorConfig<Key extends string, Config> = {\n\treadonly [Variant in keyof Config]: Validatable<any> & {\n\t\tvalidate(input: any): { readonly [K in Key]: Variant }\n\t}\n}\n/**\n * Validator for discriminated union types. Validates objects that can be one of several variants,\n * distinguished by a discriminator property (key) that indicates which variant the object represents.\n *\n * @example\n * ```ts\n * const shapeValidator = new UnionValidator('type', {\n * circle: T.object({ type: T.literal('circle'), radius: T.number }),\n * square: T.object({ type: T.literal('square'), size: T.number })\n * }, () => { throw new Error('Unknown shape') }, false)\n *\n * const circle = shapeValidator.validate({ type: 'circle', radius: 5 })\n * // circle is typed as { type: 'circle'; radius: number }\n * ```\n * @public\n */\nexport class UnionValidator<\n\tKey extends string,\n\tConfig extends UnionValidatorConfig<Key, Config>,\n\tUnknownValue = never,\n> extends Validator<TypeOf<Config[keyof Config]> | UnknownValue> {\n\t/**\n\t * Creates a new UnionValidator.\n\t *\n\t * key - The discriminator property name used to determine the variant\n\t * config - Object mapping variant names to their validators\n\t * unknownValueValidation - Function to handle unknown variants\n\t * useNumberKeys - Whether the discriminator uses number keys instead of strings\n\t */\n\tconstructor(\n\t\tprivate readonly key: Key,\n\t\tprivate readonly config: Config,\n\t\tprivate readonly unknownValueValidation: (value: object, variant: string) => UnknownValue,\n\t\tprivate readonly useNumberKeys: boolean\n\t) {\n\t\tsuper(\n\t\t\t(input) => {\n\t\t\t\tthis.expectObject(input)\n\n\t\t\t\tconst { matchingSchema, variant } = this.getMatchingSchemaAndVariant(input)\n\t\t\t\tif (matchingSchema === undefined) {\n\t\t\t\t\treturn this.unknownValueValidation(input, variant)\n\t\t\t\t}\n\n\t\t\t\treturn prefixError(`(${key} = ${variant})`, () => matchingSchema.validate(input))\n\t\t\t},\n\t\t\t(prevValue, newValue) => {\n\t\t\t\tthis.expectObject(newValue)\n\t\t\t\tthis.expectObject(prevValue)\n\n\t\t\t\tconst { matchingSchema, variant } = this.getMatchingSchemaAndVariant(newValue)\n\t\t\t\tif (matchingSchema === undefined) {\n\t\t\t\t\treturn this.unknownValueValidation(newValue, variant)\n\t\t\t\t}\n\n\t\t\t\tif (getOwnProperty(prevValue, key) !== getOwnProperty(newValue, key)) {\n\t\t\t\t\t// the type has changed so bail out and do a regular validation\n\t\t\t\t\treturn prefixError(`(${key} = ${variant})`, () => matchingSchema.validate(newValue))\n\t\t\t\t}\n\n\t\t\t\treturn prefixError(`(${key} = ${variant})`, () => {\n\t\t\t\t\tif (matchingSchema.validateUsingKnownGoodVersion) {\n\t\t\t\t\t\treturn matchingSchema.validateUsingKnownGoodVersion(prevValue, newValue)\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn matchingSchema.validate(newValue)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\t\t)\n\t}\n\n\tprivate expectObject(value: unknown): asserts value is object {\n\t\tif (typeof value !== 'object' || value === null) {\n\t\t\tthrow new ValidationError(`Expected an object, got ${typeToString(value)}`, [])\n\t\t}\n\t}\n\n\tprivate getMatchingSchemaAndVariant(object: object): {\n\t\tmatchingSchema: Validatable<any> | undefined\n\t\tvariant: string\n\t} {\n\t\tconst variant = getOwnProperty(object, this.key)! as string & keyof Config\n\t\tif (!this.useNumberKeys && typeof variant !== 'string') {\n\t\t\tthrow new ValidationError(\n\t\t\t\t`Expected a string for key \"${this.key}\", got ${typeToString(variant)}`\n\t\t\t)\n\t\t} else if (this.useNumberKeys && !Number.isFinite(Number(variant))) {\n\t\t\tthrow new ValidationError(`Expected a number for key \"${this.key}\", got \"${variant as any}\"`)\n\t\t}\n\n\t\tconst matchingSchema = hasOwnProperty(this.config, variant) ? this.config[variant] : undefined\n\t\treturn { matchingSchema, variant }\n\t}\n\n\t/**\n\t * Returns a new UnionValidator that can handle unknown variants using the provided function.\n\t *\n\t * @param unknownValueValidation - Function to validate/transform unknown variants\n\t * @returns A new UnionValidator that accepts unknown variants\n\t * @example\n\t * ```ts\n\t * const shapeValidator = T.union('type', { circle: circleValidator })\n\t * .validateUnknownVariants((obj, variant) => {\n\t * console.warn(`Unknown shape type: ${variant}`)\n\t * return obj as UnknownShape\n\t * })\n\t * ```\n\t */\n\tvalidateUnknownVariants<Unknown>(\n\t\tunknownValueValidation: (value: object, variant: string) => Unknown\n\t): UnionValidator<Key, Config, Unknown> {\n\t\treturn new UnionValidator(this.key, this.config, unknownValueValidation, this.useNumberKeys)\n\t}\n}\n\n/**\n * Validator for dictionary/map objects where both keys and values are validated.\n * Useful for validating objects used as key-value stores.\n *\n * @example\n * ```ts\n * const scoreDict = new DictValidator(T.string, T.number)\n * const scores = scoreDict.validate({\n * \"alice\": 100,\n * \"bob\": 85,\n * \"charlie\": 92\n * })\n * // scores is typed as Record<string, number>\n * ```\n * @public\n */\nexport class DictValidator<Key extends string, Value> extends Validator<Record<Key, Value>> {\n\t/**\n\t * Creates a new DictValidator.\n\t *\n\t * keyValidator - Validator for object keys\n\t * valueValidator - Validator for object values\n\t */\n\tconstructor(\n\t\tpublic readonly keyValidator: Validatable<Key>,\n\t\tpublic readonly valueValidator: Validatable<Value>\n\t) {\n\t\tsuper(\n\t\t\t(object) => {\n\t\t\t\tif (typeof object !== 'object' || object === null) {\n\t\t\t\t\tthrow new ValidationError(`Expected object, got ${typeToString(object)}`)\n\t\t\t\t}\n\n\t\t\t\tfor (const [key, value] of Object.entries(object)) {\n\t\t\t\t\tprefixError(key, () => {\n\t\t\t\t\t\tkeyValidator.validate(key)\n\t\t\t\t\t\tvalueValidator.validate(value)\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\treturn object as Record<Key, Value>\n\t\t\t},\n\t\t\t(knownGoodValue, newValue) => {\n\t\t\t\tif (typeof newValue !== 'object' || newValue === null) {\n\t\t\t\t\tthrow new ValidationError(`Expected object, got ${typeToString(newValue)}`)\n\t\t\t\t}\n\n\t\t\t\tlet isDifferent = false\n\n\t\t\t\tfor (const [key, value] of Object.entries(newValue)) {\n\t\t\t\t\tif (!hasOwnProperty(knownGoodValue, key)) {\n\t\t\t\t\t\tisDifferent = true\n\t\t\t\t\t\tprefixError(key, () => {\n\t\t\t\t\t\t\tkeyValidator.validate(key)\n\t\t\t\t\t\t\tvalueValidator.validate(value)\n\t\t\t\t\t\t})\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tconst prev = getOwnProperty(knownGoodValue, key)\n\t\t\t\t\tconst next = value\n\t\t\t\t\t// sneaky quick check here to avoid the prefix + validator overhead\n\t\t\t\t\tif (Object.is(prev, next)) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tconst checked = prefixError(key, () => {\n\t\t\t\t\t\tif (valueValidator.validateUsingKnownGoodVersion) {\n\t\t\t\t\t\t\treturn valueValidator.validateUsingKnownGoodVersion(prev as any, next)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn valueValidator.validate(next)\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\tif (!Object.is(checked, prev)) {\n\t\t\t\t\t\tisDifferent = true\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (const key of Object.keys(knownGoodValue)) {\n\t\t\t\t\tif (!hasOwnProperty(newValue, key)) {\n\t\t\t\t\t\tisDifferent = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn isDifferent ? (newValue as Record<Key, Value>) : knownGoodValue\n\t\t\t}\n\t\t)\n\t}\n}\n\nfunction typeofValidator<T>(type: string): Validator<T> {\n\treturn new Validator((value) => {\n\t\tif (typeof value !== type) {\n\t\t\tthrow new ValidationError(`Expected ${type}, got ${typeToString(value)}`)\n\t\t}\n\t\treturn value as T\n\t})\n}\n\n/**\n * Validator that accepts any value without type checking. Useful as a starting point for\n * building custom validations or when you need to accept truly unknown data.\n *\n * @example\n * ```ts\n * const result = T.unknown.validate(anything) // Returns the value as-is\n * // result is typed as unknown\n * ```\n * @public\n */\nexport const unknown = new Validator((value) => value)\n/**\n * Validator that accepts any value and types it as 'any'. This should generally be avoided\n * as it bypasses type safety, but can be used as an escape hatch for prototyping.\n *\n * @example\n * ```ts\n * const result = T.any.validate(anything) // Returns the value as any\n * // result is typed as any - use with caution!\n * ```\n * @public\n */\nexport const any = new Validator((value): any => value)\n\n/**\n * Validator that ensures a value is a string.\n *\n * @example\n * ```ts\n * const name = T.string.validate(\"hello\") // Returns \"hello\" as string\n * T.string.validate(123) // Throws ValidationError: \"Expected string, got a number\"\n * ```\n * @public\n */\nexport const string = typeofValidator<string>('string')\n\n/**\n * Validator that ensures a value is a finite, non-NaN number. Rejects Infinity, -Infinity, and NaN.\n *\n * @example\n * ```ts\n * const count = T.number.validate(42) // Returns 42 as number\n * T.number.validate(NaN) // Throws ValidationError: \"Expected a number, got NaN\"\n * T.number.validate(Infinity) // Throws ValidationError: \"Expected a finite number, got Infinity\"\n * ```\n * @public\n */\nexport const number = typeofValidator<number>('number').check((number) => {\n\tif (Number.isNaN(number)) {\n\t\tthrow new ValidationError('Expected a number, got NaN')\n\t}\n\tif (!Number.isFinite(number)) {\n\t\tthrow new ValidationError(`Expected a finite number, got ${number}`)\n\t}\n})\n/**\n * Validator that ensures a value is a non-negative number (\\>= 0).\n * Despite the name \"positive\", this validator accepts zero.\n *\n * @example\n * ```ts\n * const price = T.positiveNumber.validate(29.99) // Returns 29.99\n * const free = T.positiveNumber.validate(0) // Returns 0 (valid)\n * T.positiveNumber.validate(-1) // Throws ValidationError: \"Expected a positive number, got -1\"\n * ```\n * @public\n */\nexport const positiveNumber = number.check((value) => {\n\tif (value < 0) throw new ValidationError(`Expected a positive number, got ${value}`)\n})\n/**\n * Validator that ensures a value is a positive number (\\> 0). Rejects zero and negative numbers.\n *\n * @example\n * ```ts\n * const quantity = T.nonZeroNumber.validate(0.01) // Returns 0.01\n * T.nonZeroNumber.validate(0) // Throws ValidationError: \"Expected a non-zero positive number, got 0\"\n * T.nonZeroNumber.validate(-5) // Throws ValidationError: \"Expected a non-zero positive number, got -5\"\n * ```\n * @public\n */\nexport const nonZeroNumber = number.check((value) => {\n\tif (value <= 0) throw new ValidationError(`Expected a non-zero positive number, got ${value}`)\n})\n/**\n * Validator that ensures a value is an integer (whole number).\n *\n * @example\n * ```ts\n * const count = T.integer.validate(42) // Returns 42\n * T.integer.validate(3.14) // Throws ValidationError: \"Expected an integer, got 3.14\"\n * T.integer.validate(-5) // Returns -5 (negative integers are valid)\n * ```\n * @public\n */\nexport const integer = number.check((value) => {\n\tif (!Number.isInteger(value)) throw new ValidationError(`Expected an integer, got ${value}`)\n})\n/**\n * Validator that ensures a value is a non-negative integer (\\>= 0).\n * Despite the name \"positive\", this validator accepts zero.\n *\n * @example\n * ```ts\n * const index = T.positiveInteger.validate(5) // Returns 5\n * const start = T.positiveInteger.validate(0) // Returns 0 (valid)\n * T.positiveInteger.validate(-1) // Throws ValidationError: \"Expected a positive integer, got -1\"\n * T.positiveInteger.validate(3.14) // Throws ValidationError: \"Expected an integer, got 3.14\"\n * ```\n * @public\n */\nexport const positiveInteger = integer.check((value) => {\n\tif (value < 0) throw new ValidationError(`Expected a positive integer, got ${value}`)\n})\n/**\n * Validator that ensures a value is a positive integer (\\> 0). Rejects zero and negative integers.\n *\n * @example\n * ```ts\n * const itemCount = T.nonZeroInteger.validate(1) // Returns 1\n * T.nonZeroInteger.validate(0) // Throws ValidationError: \"Expected a non-zero positive integer, got 0\"\n * T.nonZeroInteger.validate(-5) // Throws ValidationError: \"Expected a non-zero positive integer, got -5\"\n * ```\n * @public\n */\nexport const nonZeroInteger = integer.check((value) => {\n\tif (value <= 0) throw new ValidationError(`Expected a non-zero positive integer, got ${value}`)\n})\n\n/**\n * Validator that ensures a value is a boolean.\n *\n * @example\n * ```ts\n * const isActive = T.boolean.validate(true) // Returns true\n * const isEnabled = T.boolean.validate(false) // Returns false\n * T.boolean.validate(\"true\") // Throws ValidationError: \"Expected boolean, got a string\"\n * ```\n * @public\n */\nexport const boolean = typeofValidator<boolean>('boolean')\n/**\n * Validator that ensures a value is a bigint.\n *\n * @example\n * ```ts\n * const largeNumber = T.bigint.validate(123n) // Returns 123n\n * T.bigint.validate(123) // Throws ValidationError: \"Expected bigint, got a number\"\n * ```\n * @public\n */\nexport const bigint = typeofValidator<bigint>('bigint')\n/**\n * Creates a validator that only accepts a specific literal value.\n *\n * @param expectedValue - The exact value that must be matched\n * @returns A validator that only accepts the specified literal value\n * @throws ValidationError When the value doesn't match the expected literal\n * @example\n * ```ts\n * const trueValidator = T.literal(true)\n * trueValidator.validate(true) // Returns true\n * trueValidator.validate(false) // Throws ValidationError\n *\n * const statusValidator = T.literal(\"active\")\n * statusValidator.validate(\"active\") // Returns \"active\"\n * statusValidator.validate(\"inactive\") // Throws ValidationError\n * ```\n * @public\n */\nexport function literal<T extends string | number | boolean>(expectedValue: T): Validator<T> {\n\treturn new Validator((actualValue) => {\n\t\tif (actualValue !== expectedValue) {\n\t\t\tthrow new ValidationError(`Expected ${expectedValue}, got ${JSON.stringify(actualValue)}`)\n\t\t}\n\t\treturn expectedValue\n\t})\n}\n\n/**\n * Validator that ensures a value is an array. Does not validate the contents of the array.\n * Use T.arrayOf() to validate both the array structure and its contents.\n *\n * @example\n * ```ts\n * const items = T.array.validate([1, \"hello\", true]) // Returns unknown[]\n * T.array.validate(\"not array\") // Throws ValidationError: \"Expected an array, got a string\"\n *\n * // For typed arrays, use T.arrayOf:\n * const numbers = T.arrayOf(T.number).validate([1, 2, 3]) // Returns number[]\n * ```\n * @public\n */\nexport const array = new Validator<unknown[]>((value) => {\n\tif (!Array.isArray(value)) {\n\t\tthrow new ValidationError(`Expected an array, got ${typeToString(value)}`)\n\t}\n\treturn value\n})\n\n/**\n * Creates a validator for arrays where each element is validated using the provided validator.\n *\n * @param itemValidator - Validator to use for each array element\n * @returns An ArrayOfValidator that validates both array structure and element types\n * @throws ValidationError When the value is not an array or when any element is invalid\n * @example\n * ```ts\n * const numberArray = T.arrayOf(T.number)\n * numberArray.validate([1, 2, 3]) // Returns number[]\n * numberArray.validate([1, \"2\", 3]) // Throws ValidationError at index 1\n *\n * const userArray = T.arrayOf(T.object({ name: T.string, age: T.number }))\n * ```\n * @public\n */\nexport function arrayOf<T>(itemValidator: Validatable<T>): ArrayOfValidator<T> {\n\treturn new ArrayOfValidator(itemValidator)\n}\n\n/**\n * Validator that ensures a value is an object (non-null, non-array). Does not validate\n * the properties of the object.\n *\n * @example\n * ```ts\n * const obj = T.unknownObject.validate({ any: \"properties\" }) // Returns Record<string, unknown>\n * T.unknownObject.validate(null) // Throws ValidationError: \"Expected object, got null\"\n * T.unknownObject.validate([1, 2, 3]) // Throws ValidationError: \"Expected object, got an array\"\n * ```\n * @public\n */\nexport const unknownObject = new Validator<Record<string, unknown>>((value) => {\n\tif (typeof value !== 'object' || value === null) {\n\t\tthrow new ValidationError(`Expected object, got ${typeToString(value)}`)\n\t}\n\treturn value as Record<string, unknown>\n})\n\n/**\n * Creates a validator for objects with a defined shape. Each property is validated using\n * its corresponding validator from the config object.\n *\n * @param config - Object mapping property names to their validators\n * @returns An ObjectValidator that validates the object structure and all properties\n * @throws ValidationError When the value is not an object or when any property is invalid\n * @example\n * ```ts\n * const userValidator = T.object({\n * name: T.string,\n * age: T.number,\n * email: T.string.optional(),\n * isActive: T.boolean\n * })\n *\n * const user = userValidator.validate({\n * name: \"Alice\",\n * age: 25,\n * email: \"alice@example.com\",\n * isActive: true\n * })\n * // user is typed with full type safety\n * ```\n * @public\n */\nexport function object<Shape extends object>(config: {\n\treadonly [K in keyof Shape]: Validatable<Shape[K]>\n}): ObjectValidator<MakeUndefinedOptional<Shape>> {\n\treturn new ObjectValidator(config) as any\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\t(Object.getPrototypeOf(value) === Object.prototype ||\n\t\t\tObject.getPrototypeOf(value) === null ||\n\t\t\tObject.getPrototypeOf(value) === STRUCTURED_CLONE_OBJECT_PROTOTYPE)\n\t)\n}\n\nfunction isValidJson(value: any): value is JsonValue {\n\tif (\n\t\tvalue === null ||\n\t\ttypeof value === 'number' ||\n\t\ttypeof value === 'string' ||\n\t\ttypeof value === 'boolean'\n\t) {\n\t\treturn true\n\t}\n\n\tif (Array.isArray(value)) {\n\t\treturn value.every(isValidJson)\n\t}\n\n\tif (isPlainObject(value)) {\n\t\treturn Object.values(value).every(isValidJson)\n\t}\n\n\treturn false\n}\n\n/**\n * Validator that ensures a value is valid JSON (string, number, boolean, null, array, or plain object).\n * Rejects functions, undefined, symbols, and other non-JSON values.\n *\n * @example\n * ```ts\n * const data = T.jsonValue.validate({ name: \"Alice\", scores: [1, 2, 3], active: true })\n * T.jsonValue.validate(undefined) // Throws ValidationError\n * T.jsonValue.validate(() => {}) // Throws ValidationError\n * ```\n * @public\n */\nexport const jsonValue: Validator<JsonValue> = new Validator<JsonValue>(\n\t(value): JsonValue => {\n\t\tif (isValidJson(value)) {\n\t\t\treturn value as JsonValue\n\t\t}\n\n\t\tthrow new ValidationError(`Expected json serializable value, got ${typeof value}`)\n\t},\n\t(knownGoodValue, newValue) => {\n\t\tif (Array.isArray(knownGoodValue) && Array.isArray(newValue)) {\n\t\t\tlet isDifferent = knownGoodValue.length !== newValue.length\n\t\t\tfor (let i = 0; i < newValue.length; i++) {\n\t\t\t\tif (i >= knownGoodValue.length) {\n\t\t\t\t\tisDifferent = true\n\t\t\t\t\tjsonValue.validate(newValue[i])\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst prev = knownGoodValue[i]\n\t\t\t\tconst next = newValue[i]\n\t\t\t\tif (Object.is(prev, next)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst checked = jsonValue.validateUsingKnownGoodVersion!(prev, next)\n\t\t\t\tif (!Object.is(checked, prev)) {\n\t\t\t\t\tisDifferent = true\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn isDifferent ? (newValue as JsonValue) : knownGoodValue\n\t\t} else if (isPlainObject(knownGoodValue) && isPlainObject(newValue)) {\n\t\t\tlet isDifferent = false\n\t\t\tfor (const key of Object.keys(newValue)) {\n\t\t\t\tif (!hasOwnProperty(knownGoodValue, key)) {\n\t\t\t\t\tisDifferent = true\n\t\t\t\t\tjsonValue.validate(newValue[key])\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst prev = knownGoodValue[key]\n\t\t\t\tconst next = newValue[key]\n\t\t\t\tif (Object.is(prev, next)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst checked = jsonValue.validateUsingKnownGoodVersion!(prev!, next)\n\t\t\t\tif (!Object.is(checked, prev)) {\n\t\t\t\t\tisDifferent = true\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const key of Object.keys(knownGoodValue)) {\n\t\t\t\tif (!hasOwnProperty(newValue, key)) {\n\t\t\t\t\tisDifferent = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn isDifferent ? (newValue as JsonValue) : knownGoodValue\n\t\t} else {\n\t\t\treturn jsonValue.validate(newValue)\n\t\t}\n\t}\n)\n\n/**\n * Creates a validator for JSON dictionaries (objects with string keys and JSON-serializable values).\n *\n * @returns A DictValidator that validates string keys and JSON values\n * @throws ValidationError When keys are not strings or values are not JSON-serializable\n * @example\n * ```ts\n * const config = T.jsonDict().validate({\n * \"setting1\": \"value\",\n * \"setting2\": 42,\n * \"setting3\": [\"a\", \"b\", \"c\"],\n * \"setting4\": { nested: true }\n * })\n * ```\n * @public\n */\nexport function jsonDict(): DictValidator<string, JsonValue> {\n\treturn dict(string, jsonValue)\n}\n\n/**\n * Creates a validator for dictionary objects where both keys and values are validated.\n * Useful for validating objects used as key-value maps.\n *\n * @param keyValidator - Validator for object keys\n * @param valueValidator - Validator for object values\n * @returns A DictValidator that validates all keys and values\n * @throws ValidationError When any key or value is invalid\n * @example\n * ```ts\n * const scores = T.dict(T.string, T.number)\n * scores.validate({ \"alice\": 100, \"bob\": 85 }) // Valid\n *\n * const userPrefs = T.dict(T.string, T.object({\n * theme: T.literalEnum('light', 'dark'),\n * notifications: T.boolean\n * }))\n * ```\n * @public\n */\nexport function dict<Key extends string, Value>(\n\tkeyValidator: Validatable<Key>,\n\tvalueValidator: Validatable<Value>\n): DictValidator<Key, Value> {\n\treturn new DictValidator(keyValidator, valueValidator)\n}\n\n/**\n * Creates a validator for discriminated union types. Validates objects that can be one of\n * several variants, distinguished by a discriminator property.\n *\n * @param key - The discriminator property name used to determine the variant\n * @param config - Object mapping variant names to their validators\n * @returns A UnionValidator that validates based on the discriminator value\n * @throws ValidationError When the discriminator is invalid or the variant validation fails\n * @example\n * ```ts\n * const shapeValidator = T.union('type', {\n * circle: T.object({ type: T.literal('circle'), radius: T.number }),\n * square: T.object({ type: T.literal('square'), size: T.number }),\n * triangle: T.object({ type: T.literal('triangle'), base: T.number, height: T.number })\n * })\n *\n * const circle = shapeValidator.validate({ type: 'circle', radius: 5 })\n * // circle is typed as { type: 'circle'; radius: number }\n * ```\n * @public\n */\nexport function union<Key extends string, Config extends UnionValidatorConfig<Key, Config>>(\n\tkey: Key,\n\tconfig: Config\n): UnionValidator<Key, Config> {\n\treturn new UnionValidator(\n\t\tkey,\n\t\tconfig,\n\t\t(_unknownValue, unknownVariant) => {\n\t\t\tthrow new ValidationError(\n\t\t\t\t`Expected one of ${Object.keys(config)\n\t\t\t\t\t.map((key) => JSON.stringify(key))\n\t\t\t\t\t.join(' or ')}, got ${JSON.stringify(unknownVariant)}`,\n\t\t\t\t[key]\n\t\t\t)\n\t\t},\n\t\tfalse\n\t)\n}\n\n/**\n * Creates a validator for discriminated union types using number discriminators instead of strings.\n * This is an internal function used for specific cases where numeric discriminators are needed.\n *\n * @param key - The discriminator property name used to determine the variant\n * @param config - Object mapping variant names to their validators\n * @returns A UnionValidator that validates based on numeric discriminator values\n * @throws ValidationError When the discriminator is invalid or the variant validation fails\n * @internal\n */\nexport function numberUnion<Key extends string, Config extends UnionValidatorConfig<Key, Config>>(\n\tkey: Key,\n\tconfig: Config\n): UnionValidator<Key, Config> {\n\treturn new UnionValidator(\n\t\tkey,\n\t\tconfig,\n\t\t(unknownValue, unknownVariant) => {\n\t\t\tthrow new ValidationError(\n\t\t\t\t`Expected one of ${Object.keys(config)\n\t\t\t\t\t.map((key) => JSON.stringify(key))\n\t\t\t\t\t.join(' or ')}, got ${JSON.stringify(unknownVariant)}`,\n\t\t\t\t[key]\n\t\t\t)\n\t\t},\n\t\ttrue\n\t)\n}\n\n/**\n * Creates a validator for named model objects with enhanced error reporting. The model name\n * will be included in error messages to provide better debugging context.\n *\n * @param name - The name of the model (used in error messages)\n * @param validator - The validator for the model structure\n * @returns A Validator with enhanced error reporting that includes the model name\n * @throws ValidationError With model name context when validation fails\n * @example\n * ```ts\n * const userModel = T.model('User', T.object({\n * id: T.string,\n * name: T.string,\n * email: T.linkUrl\n * }))\n *\n * // Error message will be: \"At User.email: Expected a valid url, got 'invalid-email'\"\n * ```\n * @public\n */\nexport function model<T extends { readonly id: string }>(\n\tname: string,\n\tvalidator: Validatable<T>\n): Validator<T> {\n\treturn new Validator(\n\t\t(value) => {\n\t\t\treturn prefixError(name, () => validator.validate(value))\n\t\t},\n\t\t(prevValue, newValue) => {\n\t\t\treturn prefixError(name, () => {\n\t\t\t\tif (validator.validateUsingKnownGoodVersion) {\n\t\t\t\t\treturn validator.validateUsingKnownGoodVersion(prevValue, newValue)\n\t\t\t\t} else {\n\t\t\t\t\treturn validator.validate(newValue)\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t)\n}\n\n/**\n * Creates a validator that only accepts values from a given Set of allowed values.\n *\n * @param values - Set containing the allowed values\n * @returns A validator that only accepts values from the provided set\n * @throws ValidationError When the value is not in the allowed set\n * @example\n * ```ts\n * const allowedColors = new Set(['red', 'green', 'blue'] as const)\n * const colorValidator = T.setEnum(allowedColors)\n * colorValidator.validate('red') // Returns 'red'\n * colorValidator.validate('yellow') // Throws ValidationError\n * ```\n * @public\n */\nexport function setEnum<T>(values: ReadonlySet<T>): Validator<T> {\n\treturn new Validator((value) => {\n\t\tif (!values.has(value as T)) {\n\t\t\tconst valuesString = Array.from(values, (value) => JSON.stringify(value)).join(' or ')\n\t\t\tthrow new ValidationError(`Expected ${valuesString}, got ${value}`)\n\t\t}\n\t\treturn value as T\n\t})\n}\n\n/**\n * Creates a validator that accepts either the validated type or undefined.\n *\n * @param validator - The base validator to make optional\n * @returns A validator that accepts T or undefined\n * @example\n * ```ts\n * const optionalString = T.optional(T.string)\n * optionalString.validate(\"hello\") // Returns \"hello\"\n * optionalString.validate(undefined) // Returns undefined\n * optionalString.validate(null) // Throws ValidationError\n * ```\n * @public\n */\nexport function optional<T>(validator: Validatable<T>): Validator<T | undefined> {\n\treturn new Validator(\n\t\t(value) => {\n\t\t\tif (value === undefined) return undefined\n\t\t\treturn validator.validate(value)\n\t\t},\n\t\t(knownGoodValue, newValue) => {\n\t\t\tif (knownGoodValue === undefined && newValue === undefined) return undefined\n\t\t\tif (newValue === undefined) return undefined\n\t\t\tif (validator.validateUsingKnownGoodVersion && knownGoodValue !== undefined) {\n\t\t\t\treturn validator.validateUsingKnownGoodVersion(knownGoodValue as T, newValue)\n\t\t\t}\n\t\t\treturn validator.validate(newValue)\n\t\t}\n\t)\n}\n\n/**\n * Creates a validator that accepts either the validated type or null.\n *\n * @param validator - The base validator to make nullable\n * @returns A validator that accepts T or null\n * @example\n * ```ts\n * const nullableString = T.nullable(T.string)\n * nullableString.validate(\"hello\") // Returns \"hello\"\n * nullableString.validate(null) // Returns null\n * nullableString.validate(undefined) // Throws ValidationError\n * ```\n * @public\n */\nexport function nullable<T>(validator: Validatable<T>): Validator<T | null> {\n\treturn new Validator(\n\t\t(value) => {\n\t\t\tif (value === null) return null\n\t\t\treturn validator.validate(value)\n\t\t},\n\t\t(knownGoodValue, newValue) => {\n\t\t\tif (newValue === null) return null\n\t\t\tif (validator.validateUsingKnownGoodVersion && knownGoodValue !== null) {\n\t\t\t\treturn validator.validateUsingKnownGoodVersion(knownGoodValue as T, newValue)\n\t\t\t}\n\t\t\treturn validator.validate(newValue)\n\t\t}\n\t)\n}\n\n/**\n * Creates a validator that only accepts one of the provided literal values.\n * This is a convenience function that creates a setEnum from the provided values.\n *\n * @param values - The allowed literal values\n * @returns A validator that only accepts the provided literal values\n * @throws ValidationError When the value is not one of the allowed literals\n * @example\n * ```ts\n * const themeValidator = T.literalEnum('light', 'dark', 'auto')\n * themeValidator.validate('light') // Returns 'light'\n * themeValidator.validate('blue') // Throws ValidationError: Expected \"light\" or \"dark\" or \"auto\", got blue\n * ```\n * @public\n */\nexport function literalEnum<const Values extends readonly unknown[]>(\n\t...values: Values\n): Validator<Values[number]> {\n\treturn setEnum(new Set(values))\n}\n\nfunction parseUrl(str: string) {\n\ttry {\n\t\treturn new URL(str)\n\t} catch {\n\t\tif (str.startsWith('/') || str.startsWith('./')) {\n\t\t\ttry {\n\t\t\t\treturn new URL(str, 'http://example.com')\n\t\t\t} catch {\n\t\t\t\tthrow new ValidationError(`Expected a valid url, got ${JSON.stringify(str)}`)\n\t\t\t}\n\t\t}\n\t\tthrow new ValidationError(`Expected a valid url, got ${JSON.stringify(str)}`)\n\t}\n}\n\nconst validLinkProtocols = new Set(['http:', 'https:', 'mailto:'])\n\n/**\n * Validator for URLs that are safe to use as user-facing links. Accepts http, https, and mailto protocols.\n * This validator provides security by rejecting potentially dangerous protocols like javascript:.\n *\n * @example\n * ```ts\n * const link = T.linkUrl.validate(\"https://example.com\") // Valid\n * const email = T.linkUrl.validate(\"mailto:user@example.com\") // Valid\n * T.linkUrl.validate(\"\") // Valid (empty string allowed)\n * T.linkUrl.validate(\"javascript:alert(1)\") // Throws ValidationError (unsafe protocol)\n * ```\n * @public\n */\nexport const linkUrl = string.check((value) => {\n\tif (value === '') return\n\tconst url = parseUrl(value)\n\n\tif (!validLinkProtocols.has(url.protocol.toLowerCase())) {\n\t\tthrow new ValidationError(\n\t\t\t`Expected a valid url, got ${JSON.stringify(value)} (invalid protocol)`\n\t\t)\n\t}\n})\n\n// N.B. asset: is a reference to the local indexedDB object store.\nconst validSrcProtocols = new Set(['http:', 'https:', 'data:', 'asset:'])\n\n/**\n * Validator for URLs that are safe to use as asset sources. Accepts http, https, data, and asset protocols.\n * The asset: protocol refers to tldraw's local IndexedDB object store.\n *\n * @example\n * ```ts\n * const imageUrl = T.srcUrl.validate(\"https://example.com/image.png\") // Valid\n * const dataUrl = T.srcUrl.validate(\"data:image/png;base64,iVBORw0...\") // Valid\n * const assetUrl = T.srcUrl.validate(\"asset:abc123\") // Valid (local asset reference)\n * T.srcUrl.validate(\"\") // Valid (empty string allowed)\n * ```\n * @public\n */\nexport const srcUrl = string.check((value) => {\n\tif (value === '') return\n\tconst url = parseUrl(value)\n\n\tif (!validSrcProtocols.has(url.protocol.toLowerCase())) {\n\t\tthrow new ValidationError(\n\t\t\t`Expected a valid url, got ${JSON.stringify(value)} (invalid protocol)`\n\t\t)\n\t}\n})\n\n/**\n * Validator for HTTP and HTTPS URLs only. Rejects all other protocols.\n *\n * @example\n * ```ts\n * const apiUrl = T.httpUrl.validate(\"https://api.example.com\") // Valid\n * const httpUrl = T.httpUrl.validate(\"http://localhost:3000\") // Valid\n * T.httpUrl.validate(\"\") // Valid (empty string allowed)\n * T.httpUrl.validate(\"ftp://files.example.com\") // Throws ValidationError (not http/https)\n * ```\n * @public\n */\nexport const httpUrl = string.check((value) => {\n\tif (value === '') return\n\tconst url = parseUrl(value)\n\n\tif (!url.protocol.toLowerCase().match(/^https?:$/)) {\n\t\tthrow new ValidationError(\n\t\t\t`Expected a valid url, got ${JSON.stringify(value)} (invalid protocol)`\n\t\t)\n\t}\n})\n\n/**\n * Validator for IndexKey values used in tldraw's indexing system. An IndexKey is a string\n * that meets specific format requirements for use as a database index.\n *\n * @throws ValidationError When the string is not a valid IndexKey format\n * @example\n * ```ts\n * const key = T.indexKey.validate(\"valid_index_key\") // Returns IndexKey\n * T.indexKey.validate(\"invalid key!\") // Throws ValidationError (invalid format)\n * ```\n * @public\n */\nexport const indexKey = string.refine<IndexKey>((key) => {\n\ttry {\n\t\tvalidateIndexKey(key)\n\t\treturn key\n\t} catch {\n\t\tthrow new ValidationError(`Expected an index key, got ${JSON.stringify(key)}`)\n\t}\n})\n\n/**\n * Creates a validator that accepts values matching either of two validators.\n * Tries the first validator, and if it fails, tries the second validator.\n *\n * @param v1 - The first validator to try\n * @param v2 - The second validator to try if the first fails\n * @returns A validator that accepts values matching either validator\n * @throws ValidationError When the value matches neither validator (throws error from v2)\n * @example\n * ```ts\n * const stringOrNumber = T.or(T.string, T.number)\n * stringOrNumber.validate(\"hello\") // Returns \"hello\" as string\n * stringOrNumber.validate(42) // Returns 42 as number\n * stringOrNumber.validate(true) // Throws ValidationError from number validator\n * ```\n * @public\n */\nexport function or<T1, T2>(v1: Validatable<T1>, v2: Validatable<T2>): Validator<T1 | T2> {\n\treturn new Validator((value) => {\n\t\ttry {\n\t\t\treturn v1.validate(value)\n\t\t} catch {\n\t\t\treturn v2.validate(value)\n\t\t}\n\t})\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["object", "
|
|
4
|
+
"sourcesContent": ["import {\n\tIndexKey,\n\tJsonValue,\n\tMakeUndefinedOptional,\n\tSTRUCTURED_CLONE_OBJECT_PROTOTYPE,\n\texhaustiveSwitchError,\n\tgetOwnProperty,\n\thasOwnProperty,\n\tvalidateIndexKey,\n} from '@tldraw/utils'\n\n/** @internal */\nconst IS_DEV = process.env.NODE_ENV !== 'production'\n\n/**\n * A function that validates and returns a value of type T from unknown input.\n * The function should throw a ValidationError if the value is invalid.\n *\n * @param value - The unknown value to validate\n * @returns The validated value of type T\n * @throws \\{ValidationError\\} When the value doesn't match the expected type\n * @example\n * ```ts\n * const stringValidator: ValidatorFn<string> = (value) => {\n * if (typeof value !== 'string') {\n * throw new ValidationError('Expected string')\n * }\n * return value\n * }\n * ```\n * @public\n */\nexport type ValidatorFn<T> = (value: unknown) => T\n/**\n * A performance-optimized validation function that can use a previously validated value\n * to avoid revalidating unchanged parts of the data structure.\n *\n * @param knownGoodValue - A previously validated value of type In\n * @param value - The unknown value to validate\n * @returns The validated value of type Out\n * @throws ValidationError When the value doesn't match the expected type\n * @example\n * ```ts\n * const optimizedValidator: ValidatorUsingKnownGoodVersionFn<User> = (\n * knownGood,\n * newValue\n * ) => {\n * if (Object.is(knownGood, newValue)) return knownGood\n * return fullValidation(newValue)\n * }\n * ```\n * @public\n */\nexport type ValidatorUsingKnownGoodVersionFn<In, Out = In> = (\n\tknownGoodValue: In,\n\tvalue: unknown\n) => Out\n\n/**\n * Interface for objects that can validate unknown values and return typed results.\n * This is the core interface implemented by all validators in the validation system.\n *\n * @example\n * ```ts\n * const customValidator: Validatable<number> = {\n * validate(value) {\n * if (typeof value !== 'number') {\n * throw new ValidationError('Expected number')\n * }\n * return value\n * }\n * }\n * ```\n * @public\n */\nexport interface Validatable<T> {\n\t/**\n\t * Validates an unknown value and returns it with the correct type.\n\t *\n\t * @param value - The unknown value to validate\n\t * @returns The validated value with type T\n\t * @throws ValidationError When validation fails\n\t */\n\tvalidate(value: unknown): T\n\t/**\n\t * Performance-optimized validation that can use a previously validated value\n\t * to avoid revalidating unchanged parts of the data structure.\n\t *\n\t * If the value has not changed but is not referentially equal, the function\n\t * should return the previous value.\n\t *\n\t * @param knownGoodValue - A previously validated value\n\t * @param newValue - The new value to validate\n\t * @returns The validated value, potentially reusing the known good value for performance\n\t * @throws ValidationError When validation fails\n\t */\n\tvalidateUsingKnownGoodVersion?(knownGoodValue: T, newValue: unknown): T\n}\n\nfunction formatPath(path: ReadonlyArray<number | string>): string | null {\n\tif (!path.length) {\n\t\treturn null\n\t}\n\n\tlet formattedPath = ''\n\tfor (const item of path) {\n\t\tif (typeof item === 'number') {\n\t\t\tformattedPath += `.${item}`\n\t\t} else if (item.startsWith('(')) {\n\t\t\tif (formattedPath.endsWith(')')) {\n\t\t\t\tformattedPath = `${formattedPath.slice(0, -1)}, ${item.slice(1)}`\n\t\t\t} else {\n\t\t\t\tformattedPath += item\n\t\t\t}\n\t\t} else {\n\t\t\tformattedPath += `.${item}`\n\t\t}\n\t}\n\n\t// N.B. We don't want id's in the path because they make grouping in Sentry tough.\n\tformattedPath = formattedPath.replace(/id = [^,]+, /, '').replace(/id = [^)]+/, '')\n\n\tif (formattedPath.startsWith('.')) {\n\t\treturn formattedPath.slice(1)\n\t}\n\treturn formattedPath\n}\n\n/**\n * Error thrown when validation fails. Provides detailed information about what went wrong\n * and where in the data structure the error occurred.\n *\n * @example\n * ```ts\n * try {\n * validator.validate(invalidData)\n * } catch (error) {\n * if (error instanceof ValidationError) {\n * console.log(error.message) // \"At users.0.email: Expected valid URL\"\n * console.log(error.path) // ['users', 0, 'email']\n * console.log(error.rawMessage) // \"Expected valid URL\"\n * }\n * }\n * ```\n * @public\n */\nexport class ValidationError extends Error {\n\toverride name = 'ValidationError'\n\n\t/**\n\t * Creates a new ValidationError with contextual information about where the error occurred.\n\t *\n\t * rawMessage - The raw error message without path information\n\t * path - Array indicating the location in the data structure where validation failed\n\t */\n\tconstructor(\n\t\tpublic readonly rawMessage: string,\n\t\tpublic readonly path: ReadonlyArray<number | string> = []\n\t) {\n\t\tconst formattedPath = formatPath(path)\n\t\tconst indentedMessage = rawMessage\n\t\t\t.split('\\n')\n\t\t\t.map((line, i) => (i === 0 ? line : ` ${line}`))\n\t\t\t.join('\\n')\n\t\tsuper(path ? `At ${formattedPath}: ${indentedMessage}` : indentedMessage)\n\t}\n}\n\nfunction prefixError<T>(path: string | number, fn: () => T): T {\n\ttry {\n\t\treturn fn()\n\t} catch (err) {\n\t\tif (err instanceof ValidationError) {\n\t\t\tthrow new ValidationError(err.rawMessage, [path, ...err.path])\n\t\t}\n\t\tthrow new ValidationError((err as Error).toString(), [path])\n\t}\n}\n\nfunction typeToString(value: unknown): string {\n\tif (value === null) return 'null'\n\tif (Array.isArray(value)) return 'an array'\n\tconst type = typeof value\n\tswitch (type) {\n\t\tcase 'bigint':\n\t\tcase 'boolean':\n\t\tcase 'function':\n\t\tcase 'number':\n\t\tcase 'string':\n\t\tcase 'symbol':\n\t\t\treturn `a ${type}`\n\t\tcase 'object':\n\t\t\treturn `an ${type}`\n\t\tcase 'undefined':\n\t\t\treturn 'undefined'\n\t\tdefault:\n\t\t\texhaustiveSwitchError(type)\n\t}\n}\n\n/**\n * Utility type that extracts the validated type from a Validatable object.\n * Useful for deriving TypeScript types from validator definitions.\n *\n * @example\n * ```ts\n * const userValidator = T.object({ name: T.string, age: T.number })\n * type User = TypeOf<typeof userValidator> // { name: string; age: number }\n * ```\n * @public\n */\nexport type TypeOf<V extends Validatable<any>> = V extends Validatable<infer T> ? T : never\n\n/**\n * The main validator class that implements the Validatable interface. This is the base class\n * for all validators and provides methods for validation, type checking, and composing validators.\n *\n * @example\n * ```ts\n * const numberValidator = new Validator((value) => {\n * if (typeof value !== 'number') {\n * throw new ValidationError('Expected number')\n * }\n * return value\n * })\n *\n * const result = numberValidator.validate(42) // Returns 42 as number\n * ```\n * @public\n */\nexport class Validator<T> implements Validatable<T> {\n\t/**\n\t * Creates a new Validator instance.\n\t *\n\t * validationFn - Function that validates and returns a value of type T\n\t * validateUsingKnownGoodVersionFn - Optional performance-optimized validation function\n\t * skipSameValueCheck - Internal flag to skip dev check for validators that transform values\n\t */\n\tconstructor(\n\t\treadonly validationFn: ValidatorFn<T>,\n\t\treadonly validateUsingKnownGoodVersionFn?: ValidatorUsingKnownGoodVersionFn<T>,\n\t\t/** @internal */\n\t\treadonly skipSameValueCheck: boolean = false\n\t) {}\n\n\t/**\n\t * Validates an unknown value and returns it with the correct type. The returned value is\n\t * guaranteed to be referentially equal to the passed value.\n\t *\n\t * @param value - The unknown value to validate\n\t * @returns The validated value with type T\n\t * @throws ValidationError When validation fails\n\t * @example\n\t * ```ts\n\t * import { T } from '@tldraw/validate'\n\t *\n\t * const name = T.string.validate(\"Alice\") // Returns \"Alice\" as string\n\t * const title = T.string.validate(\"\") // Returns \"\" (empty strings are valid)\n\t *\n\t * // These will throw ValidationError:\n\t * T.string.validate(123) // Expected string, got a number\n\t * T.string.validate(null) // Expected string, got null\n\t * T.string.validate(undefined) // Expected string, got undefined\n\t * ```\n\t */\n\tvalidate(value: unknown): T {\n\t\tconst validated = this.validationFn(value)\n\t\tif (IS_DEV && !this.skipSameValueCheck && !Object.is(value, validated)) {\n\t\t\tthrow new ValidationError('Validator functions must return the same value they were passed')\n\t\t}\n\t\treturn validated\n\t}\n\n\t/**\n\t * Performance-optimized validation using a previously validated value. If the new value\n\t * is referentially equal to the known good value, returns the known good value immediately.\n\t *\n\t * @param knownGoodValue - A previously validated value\n\t * @param newValue - The new value to validate\n\t * @returns The validated value, potentially reusing the known good value\n\t * @throws ValidationError When validation fails\n\t * @example\n\t * ```ts\n\t * import { T } from '@tldraw/validate'\n\t *\n\t * const userValidator = T.object({\n\t * name: T.string,\n\t * settings: T.object({ theme: T.literalEnum('light', 'dark') })\n\t * })\n\t *\n\t * const user = userValidator.validate({ name: \"Alice\", settings: { theme: \"light\" } })\n\t *\n\t * // Later, with partially changed data:\n\t * const newData = { name: \"Alice\", settings: { theme: \"dark\" } }\n\t * const updated = userValidator.validateUsingKnownGoodVersion(user, newData)\n\t * // Only validates the changed 'theme' field for better performance\n\t * ```\n\t */\n\tvalidateUsingKnownGoodVersion(knownGoodValue: T, newValue: unknown): T {\n\t\tif (Object.is(knownGoodValue, newValue)) {\n\t\t\treturn knownGoodValue as T\n\t\t}\n\n\t\tif (this.validateUsingKnownGoodVersionFn) {\n\t\t\treturn this.validateUsingKnownGoodVersionFn(knownGoodValue, newValue)\n\t\t}\n\n\t\treturn this.validate(newValue)\n\t}\n\n\t/**\n\t * Type guard that checks if a value is valid without throwing an error.\n\t *\n\t * @param value - The value to check\n\t * @returns True if the value is valid, false otherwise\n\t * @example\n\t * ```ts\n\t * import { T } from '@tldraw/validate'\n\t *\n\t * function processUserInput(input: unknown) {\n\t * if (T.string.isValid(input)) {\n\t * // input is now typed as string within this block\n\t * return input.toUpperCase()\n\t * }\n\t * if (T.number.isValid(input)) {\n\t * // input is now typed as number within this block\n\t * return input.toFixed(2)\n\t * }\n\t * throw new Error('Expected string or number')\n\t * }\n\t * ```\n\t */\n\tisValid(value: unknown): value is T {\n\t\ttry {\n\t\t\tthis.validate(value)\n\t\t\treturn true\n\t\t} catch {\n\t\t\treturn false\n\t\t}\n\t}\n\n\t/**\n\t * Returns a new validator that also accepts null values.\n\t *\n\t * @returns A new validator that accepts T or null\n\t * @example\n\t * ```ts\n\t * import { T } from '@tldraw/validate'\n\t *\n\t * const assetValidator = T.object({\n\t * id: T.string,\n\t * name: T.string,\n\t * src: T.srcUrl.nullable(), // Can be null if not loaded yet\n\t * mimeType: T.string.nullable()\n\t * })\n\t *\n\t * const asset = assetValidator.validate({\n\t * id: \"image-123\",\n\t * name: \"photo.jpg\",\n\t * src: null, // Valid - asset not loaded yet\n\t * mimeType: \"image/jpeg\"\n\t * })\n\t * ```\n\t */\n\tnullable(): Validator<T | null> {\n\t\treturn nullable(this)\n\t}\n\n\t/**\n\t * Returns a new validator that also accepts undefined values.\n\t *\n\t * @returns A new validator that accepts T or undefined\n\t * @example\n\t * ```ts\n\t * import { T } from '@tldraw/validate'\n\t *\n\t * const shapeConfigValidator = T.object({\n\t * type: T.literal('rectangle'),\n\t * x: T.number,\n\t * y: T.number,\n\t * label: T.string.optional(), // Optional property\n\t * metadata: T.object({ created: T.string }).optional()\n\t * })\n\t *\n\t * // Both of these are valid:\n\t * const shape1 = shapeConfigValidator.validate({ type: 'rectangle', x: 0, y: 0 })\n\t * const shape2 = shapeConfigValidator.validate({\n\t * type: 'rectangle', x: 0, y: 0, label: \"My Shape\"\n\t * })\n\t * ```\n\t */\n\toptional(): Validator<T | undefined> {\n\t\treturn optional(this)\n\t}\n\n\t/**\n\t * Creates a new validator by refining this validator with additional logic that can transform\n\t * the validated value to a new type.\n\t *\n\t * @param otherValidationFn - Function that transforms/validates the value to type U\n\t * @returns A new validator that validates to type U\n\t * @throws ValidationError When validation or refinement fails\n\t * @example\n\t * ```ts\n\t * import { T, ValidationError } from '@tldraw/validate'\n\t *\n\t * // Transform string to ensure it starts with a prefix\n\t * const prefixedIdValidator = T.string.refine((id) => {\n\t * return id.startsWith('shape:') ? id : `shape:${id}`\n\t * })\n\t *\n\t * const id1 = prefixedIdValidator.validate(\"rectangle-123\") // Returns \"shape:rectangle-123\"\n\t * const id2 = prefixedIdValidator.validate(\"shape:circle-456\") // Returns \"shape:circle-456\"\n\t *\n\t * // Parse and validate JSON strings\n\t * const jsonValidator = T.string.refine((str) => {\n\t * try {\n\t * return JSON.parse(str)\n\t * } catch {\n\t * throw new ValidationError('Invalid JSON string')\n\t * }\n\t * })\n\t * ```\n\t */\n\trefine<U>(otherValidationFn: (value: T) => U): Validator<U> {\n\t\treturn new Validator(\n\t\t\t(value) => {\n\t\t\t\treturn otherValidationFn(this.validate(value))\n\t\t\t},\n\n\t\t\t(knownGoodValue, newValue) => {\n\t\t\t\tconst validated = this.validateUsingKnownGoodVersion(knownGoodValue as any, newValue)\n\t\t\t\tif (Object.is(knownGoodValue, validated)) {\n\t\t\t\t\treturn knownGoodValue\n\t\t\t\t}\n\t\t\t\treturn otherValidationFn(validated)\n\t\t\t},\n\t\t\ttrue // skipSameValueCheck: refine is designed to transform values\n\t\t)\n\t}\n\n\t/**\n\t * Adds an additional validation check without changing the resulting value type.\n\t * Can be called with just a check function, or with a name for better error messages.\n\t *\n\t * @param name - Name for the check (used in error messages)\n\t * @param checkFn - Function that validates the value (should throw on invalid input)\n\t * @returns A new validator with the additional check\n\t * @throws ValidationError When the check fails\n\t * @example\n\t * ```ts\n\t * import { T, ValidationError } from '@tldraw/validate'\n\t *\n\t * // Basic check without name\n\t * const evenNumber = T.number.check((value) => {\n\t * if (value % 2 !== 0) {\n\t * throw new ValidationError('Expected even number')\n\t * }\n\t * })\n\t *\n\t * // Named checks for better error messages in complex validators\n\t * const shapePositionValidator = T.object({\n\t * x: T.number.check('finite', (value) => {\n\t * if (!Number.isFinite(value)) {\n\t * throw new ValidationError('Position must be finite')\n\t * }\n\t * }),\n\t * y: T.number.check('within-bounds', (value) => {\n\t * if (value < -10000 || value > 10000) {\n\t * throw new ValidationError('Position must be within bounds (-10000 to 10000)')\n\t * }\n\t * })\n\t * })\n\t *\n\t * // Error will be: \"At x (check finite): Position must be finite\"\n\t * ```\n\t */\n\tcheck(name: string, checkFn: (value: T) => void): Validator<T>\n\t/**\n\t * Adds an additional validation check without changing the resulting value type.\n\t *\n\t * @param checkFn - Function that validates the value (should throw on invalid input)\n\t * @returns A new validator with the additional check\n\t * @throws ValidationError When the check fails\n\t */\n\tcheck(checkFn: (value: T) => void): Validator<T>\n\tcheck(nameOrCheckFn: string | ((value: T) => void), checkFn?: (value: T) => void): Validator<T> {\n\t\tif (typeof nameOrCheckFn === 'string') {\n\t\t\treturn this.refine((value) => {\n\t\t\t\tprefixError(`(check ${nameOrCheckFn})`, () => checkFn!(value))\n\t\t\t\treturn value\n\t\t\t})\n\t\t} else {\n\t\t\treturn this.refine((value) => {\n\t\t\t\tnameOrCheckFn(value)\n\t\t\t\treturn value\n\t\t\t})\n\t\t}\n\t}\n}\n\n/**\n * Validator for arrays where each element is validated using the provided item validator.\n * Extends the base Validator class with array-specific validation methods.\n *\n * @example\n * ```ts\n * const stringArray = new ArrayOfValidator(T.string)\n * const numbers = stringArray.validate([\"a\", \"b\", \"c\"]) // Returns string[]\n *\n * const userArray = T.arrayOf(T.object({ name: T.string, age: T.number }))\n * ```\n * @public\n */\nexport class ArrayOfValidator<T> extends Validator<T[]> {\n\t/**\n\t * Creates a new ArrayOfValidator.\n\t *\n\t * itemValidator - Validator used to validate each array element\n\t */\n\tconstructor(readonly itemValidator: Validatable<T>) {\n\t\tsuper(\n\t\t\t(value) => {\n\t\t\t\tconst arr = array.validate(value)\n\t\t\t\tfor (let i = 0; i < arr.length; i++) {\n\t\t\t\t\tif (IS_DEV) {\n\t\t\t\t\t\tprefixError(i, () => itemValidator.validate(arr[i]))\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Production: inline error handling to avoid closure overhead\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\titemValidator.validate(arr[i])\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tif (err instanceof ValidationError) {\n\t\t\t\t\t\t\t\tthrow new ValidationError(err.rawMessage, [i, ...err.path])\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthrow new ValidationError((err as Error).toString(), [i])\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn arr as T[]\n\t\t\t},\n\t\t\t(knownGoodValue, newValue) => {\n\t\t\t\t// Fast path: reference equality means no changes\n\t\t\t\tif (Object.is(knownGoodValue, newValue)) {\n\t\t\t\t\treturn knownGoodValue\n\t\t\t\t}\n\t\t\t\tif (!itemValidator.validateUsingKnownGoodVersion) return this.validate(newValue)\n\t\t\t\tconst arr = array.validate(newValue)\n\t\t\t\tlet isDifferent = knownGoodValue.length !== arr.length\n\t\t\t\tfor (let i = 0; i < arr.length; i++) {\n\t\t\t\t\tconst item = arr[i]\n\t\t\t\t\tif (i >= knownGoodValue.length) {\n\t\t\t\t\t\tisDifferent = true\n\t\t\t\t\t\tif (IS_DEV) {\n\t\t\t\t\t\t\tprefixError(i, () => itemValidator.validate(item))\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\titemValidator.validate(item)\n\t\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t\tif (err instanceof ValidationError) {\n\t\t\t\t\t\t\t\t\tthrow new ValidationError(err.rawMessage, [i, ...err.path])\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tthrow new ValidationError((err as Error).toString(), [i])\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\t// sneaky quick check here to avoid the prefix + validator overhead\n\t\t\t\t\tif (Object.is(knownGoodValue[i], item)) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tif (IS_DEV) {\n\t\t\t\t\t\tconst checkedItem = prefixError(i, () =>\n\t\t\t\t\t\t\titemValidator.validateUsingKnownGoodVersion!(knownGoodValue[i], item)\n\t\t\t\t\t\t)\n\t\t\t\t\t\tif (!Object.is(checkedItem, knownGoodValue[i])) {\n\t\t\t\t\t\t\tisDifferent = true\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst checkedItem = itemValidator.validateUsingKnownGoodVersion!(\n\t\t\t\t\t\t\t\tknownGoodValue[i],\n\t\t\t\t\t\t\t\titem\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tif (!Object.is(checkedItem, knownGoodValue[i])) {\n\t\t\t\t\t\t\t\tisDifferent = true\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tif (err instanceof ValidationError) {\n\t\t\t\t\t\t\t\tthrow new ValidationError(err.rawMessage, [i, ...err.path])\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthrow new ValidationError((err as Error).toString(), [i])\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn isDifferent ? (newValue as T[]) : knownGoodValue\n\t\t\t}\n\t\t)\n\t}\n\n\t/**\n\t * Returns a new validator that ensures the array is not empty.\n\t *\n\t * @returns A new validator that rejects empty arrays\n\t * @throws ValidationError When the array is empty\n\t * @example\n\t * ```ts\n\t * const nonEmptyStrings = T.arrayOf(T.string).nonEmpty()\n\t * nonEmptyStrings.validate([\"hello\"]) // Valid\n\t * nonEmptyStrings.validate([]) // Throws ValidationError\n\t * ```\n\t */\n\tnonEmpty() {\n\t\treturn this.check((value) => {\n\t\t\tif (value.length === 0) {\n\t\t\t\tthrow new ValidationError('Expected a non-empty array')\n\t\t\t}\n\t\t})\n\t}\n\n\t/**\n\t * Returns a new validator that ensures the array has more than one element.\n\t *\n\t * @returns A new validator that requires at least 2 elements\n\t * @throws ValidationError When the array has 1 or fewer elements\n\t * @example\n\t * ```ts\n\t * const multipleItems = T.arrayOf(T.string).lengthGreaterThan1()\n\t * multipleItems.validate([\"a\", \"b\"]) // Valid\n\t * multipleItems.validate([\"a\"]) // Throws ValidationError\n\t * ```\n\t */\n\tlengthGreaterThan1() {\n\t\treturn this.check((value) => {\n\t\t\tif (value.length <= 1) {\n\t\t\t\tthrow new ValidationError('Expected an array with length greater than 1')\n\t\t\t}\n\t\t})\n\t}\n}\n\n/**\n * Validator for objects with a defined shape. Each property is validated using its corresponding\n * validator from the config object. Can be configured to allow or reject unknown properties.\n *\n * @example\n * ```ts\n * const userValidator = new ObjectValidator({\n * name: T.string,\n * age: T.number,\n * email: T.string.optional()\n * })\n *\n * const user = userValidator.validate({\n * name: \"Alice\",\n * age: 25,\n * email: \"alice@example.com\"\n * })\n * ```\n * @public\n */\nexport class ObjectValidator<Shape extends object> extends Validator<Shape> {\n\t/**\n\t * Creates a new ObjectValidator.\n\t *\n\t * config - Object mapping property names to their validators\n\t * shouldAllowUnknownProperties - Whether to allow properties not defined in config\n\t */\n\tconstructor(\n\t\tpublic readonly config: {\n\t\t\treadonly [K in keyof Shape]: Validatable<Shape[K]>\n\t\t},\n\t\tprivate readonly shouldAllowUnknownProperties = false\n\t) {\n\t\tsuper(\n\t\t\t(object) => {\n\t\t\t\tif (typeof object !== 'object' || object === null) {\n\t\t\t\t\tthrow new ValidationError(`Expected object, got ${typeToString(object)}`)\n\t\t\t\t}\n\n\t\t\t\tfor (const key in config) {\n\t\t\t\t\tif (!hasOwnProperty(config, key)) continue\n\t\t\t\t\tconst validator = config[key as keyof typeof config]\n\t\t\t\t\tif (IS_DEV) {\n\t\t\t\t\t\tprefixError(key, () => {\n\t\t\t\t\t\t\t;(validator as Validatable<unknown>).validate(getOwnProperty(object, key))\n\t\t\t\t\t\t})\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Production: inline error handling to avoid closure overhead\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t;(validator as Validatable<unknown>).validate(getOwnProperty(object, key))\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tif (err instanceof ValidationError) {\n\t\t\t\t\t\t\t\tthrow new ValidationError(err.rawMessage, [key, ...err.path])\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthrow new ValidationError((err as Error).toString(), [key])\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!shouldAllowUnknownProperties) {\n\t\t\t\t\tfor (const key of Object.keys(object)) {\n\t\t\t\t\t\tif (!hasOwnProperty(config, key)) {\n\t\t\t\t\t\t\tthrow new ValidationError(`Unexpected property`, [key])\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn object as Shape\n\t\t\t},\n\t\t\t(knownGoodValue, newValue) => {\n\t\t\t\t// Fast path: reference equality means no changes\n\t\t\t\tif (Object.is(knownGoodValue, newValue)) {\n\t\t\t\t\treturn knownGoodValue\n\t\t\t\t}\n\t\t\t\tif (typeof newValue !== 'object' || newValue === null) {\n\t\t\t\t\tthrow new ValidationError(`Expected object, got ${typeToString(newValue)}`)\n\t\t\t\t}\n\n\t\t\t\tlet isDifferent = false\n\n\t\t\t\tfor (const key in config) {\n\t\t\t\t\tif (!hasOwnProperty(config, key)) continue\n\t\t\t\t\tconst validator = config[key as keyof typeof config]\n\t\t\t\t\tconst prev = getOwnProperty(knownGoodValue, key)\n\t\t\t\t\tconst next = getOwnProperty(newValue, key)\n\t\t\t\t\t// sneaky quick check here to avoid the prefix + validator overhead\n\t\t\t\t\tif (Object.is(prev, next)) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tif (IS_DEV) {\n\t\t\t\t\t\tconst checked = prefixError(key, () => {\n\t\t\t\t\t\t\tconst validatable = validator as Validatable<unknown>\n\t\t\t\t\t\t\tif (validatable.validateUsingKnownGoodVersion) {\n\t\t\t\t\t\t\t\treturn validatable.validateUsingKnownGoodVersion(prev, next)\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\treturn validatable.validate(next)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})\n\t\t\t\t\t\tif (!Object.is(checked, prev)) {\n\t\t\t\t\t\t\tisDifferent = true\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst validatable = validator as Validatable<unknown>\n\t\t\t\t\t\t\tconst checked = validatable.validateUsingKnownGoodVersion\n\t\t\t\t\t\t\t\t? validatable.validateUsingKnownGoodVersion(prev, next)\n\t\t\t\t\t\t\t\t: validatable.validate(next)\n\t\t\t\t\t\t\tif (!Object.is(checked, prev)) {\n\t\t\t\t\t\t\t\tisDifferent = true\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tif (err instanceof ValidationError) {\n\t\t\t\t\t\t\t\tthrow new ValidationError(err.rawMessage, [key, ...err.path])\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthrow new ValidationError((err as Error).toString(), [key])\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!shouldAllowUnknownProperties) {\n\t\t\t\t\tfor (const key of Object.keys(newValue)) {\n\t\t\t\t\t\tif (!hasOwnProperty(config, key)) {\n\t\t\t\t\t\t\tthrow new ValidationError(`Unexpected property`, [key])\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (const key of Object.keys(knownGoodValue)) {\n\t\t\t\t\tif (!hasOwnProperty(newValue, key)) {\n\t\t\t\t\t\tisDifferent = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn isDifferent ? (newValue as Shape) : knownGoodValue\n\t\t\t}\n\t\t)\n\t}\n\n\t/**\n\t * Returns a new validator that allows unknown properties in the validated object.\n\t *\n\t * @returns A new ObjectValidator that accepts extra properties\n\t * @example\n\t * ```ts\n\t * const flexibleUser = T.object({ name: T.string }).allowUnknownProperties()\n\t * flexibleUser.validate({ name: \"Alice\", extra: \"allowed\" }) // Valid\n\t * ```\n\t */\n\tallowUnknownProperties() {\n\t\treturn new ObjectValidator(this.config, true)\n\t}\n\n\t/**\n\t * Creates a new ObjectValidator by extending this validator with additional properties.\n\t *\n\t * @param extension - Object mapping new property names to their validators\n\t * @returns A new ObjectValidator that validates both original and extended properties\n\t * @example\n\t * ```ts\n\t * const baseUser = T.object({ name: T.string, age: T.number })\n\t * const adminUser = baseUser.extend({\n\t * permissions: T.arrayOf(T.string),\n\t * isAdmin: T.boolean\n\t * })\n\t * // adminUser validates: { name: string; age: number; permissions: string[]; isAdmin: boolean }\n\t * ```\n\t */\n\textend<Extension extends Record<string, unknown>>(extension: {\n\t\treadonly [K in keyof Extension]: Validatable<Extension[K]>\n\t}): ObjectValidator<Shape & Extension> {\n\t\treturn new ObjectValidator({ ...this.config, ...extension }) as any as ObjectValidator<\n\t\t\tShape & Extension\n\t\t>\n\t}\n}\n\n/**\n * Configuration type for union validators. Each variant must be a validator that produces\n * an object with the discriminator key set to the variant name.\n *\n * @example\n * ```ts\n * type ShapeConfig = UnionValidatorConfig<'type', {\n * circle: Validatable<{ type: 'circle'; radius: number }>\n * square: Validatable<{ type: 'square'; size: number }>\n * }>\n * ```\n * @public\n */\nexport type UnionValidatorConfig<Key extends string, Config> = {\n\treadonly [Variant in keyof Config]: Validatable<any> & {\n\t\tvalidate(input: any): { readonly [K in Key]: Variant }\n\t}\n}\n/**\n * Validator for discriminated union types. Validates objects that can be one of several variants,\n * distinguished by a discriminator property (key) that indicates which variant the object represents.\n *\n * @example\n * ```ts\n * const shapeValidator = new UnionValidator('type', {\n * circle: T.object({ type: T.literal('circle'), radius: T.number }),\n * square: T.object({ type: T.literal('square'), size: T.number })\n * }, () => { throw new Error('Unknown shape') }, false)\n *\n * const circle = shapeValidator.validate({ type: 'circle', radius: 5 })\n * // circle is typed as { type: 'circle'; radius: number }\n * ```\n * @public\n */\nexport class UnionValidator<\n\tKey extends string,\n\tConfig extends UnionValidatorConfig<Key, Config>,\n\tUnknownValue = never,\n> extends Validator<TypeOf<Config[keyof Config]> | UnknownValue> {\n\t/**\n\t * Creates a new UnionValidator.\n\t *\n\t * key - The discriminator property name used to determine the variant\n\t * config - Object mapping variant names to their validators\n\t * unknownValueValidation - Function to handle unknown variants\n\t * useNumberKeys - Whether the discriminator uses number keys instead of strings\n\t */\n\tconstructor(\n\t\tprivate readonly key: Key,\n\t\tprivate readonly config: Config,\n\t\tprivate readonly unknownValueValidation: (value: object, variant: string) => UnknownValue,\n\t\tprivate readonly useNumberKeys: boolean\n\t) {\n\t\tsuper(\n\t\t\t(input) => {\n\t\t\t\tthis.expectObject(input)\n\n\t\t\t\tconst { matchingSchema, variant } = this.getMatchingSchemaAndVariant(input)\n\t\t\t\tif (matchingSchema === undefined) {\n\t\t\t\t\treturn this.unknownValueValidation(input, variant)\n\t\t\t\t}\n\n\t\t\t\treturn prefixError(`(${key} = ${variant})`, () => matchingSchema.validate(input))\n\t\t\t},\n\t\t\t(prevValue, newValue) => {\n\t\t\t\t// Note: Object.is check is already done by base Validator class\n\t\t\t\tthis.expectObject(newValue)\n\t\t\t\tthis.expectObject(prevValue)\n\n\t\t\t\tconst { matchingSchema, variant } = this.getMatchingSchemaAndVariant(newValue)\n\t\t\t\tif (matchingSchema === undefined) {\n\t\t\t\t\treturn this.unknownValueValidation(newValue, variant)\n\t\t\t\t}\n\n\t\t\t\tif (getOwnProperty(prevValue, key) !== getOwnProperty(newValue, key)) {\n\t\t\t\t\t// the type has changed so bail out and do a regular validation\n\t\t\t\t\treturn prefixError(`(${key} = ${variant})`, () => matchingSchema.validate(newValue))\n\t\t\t\t}\n\n\t\t\t\treturn prefixError(`(${key} = ${variant})`, () => {\n\t\t\t\t\tif (matchingSchema.validateUsingKnownGoodVersion) {\n\t\t\t\t\t\treturn matchingSchema.validateUsingKnownGoodVersion(prevValue, newValue)\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn matchingSchema.validate(newValue)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\t\t)\n\t}\n\n\tprivate expectObject(value: unknown): asserts value is object {\n\t\tif (typeof value !== 'object' || value === null) {\n\t\t\tthrow new ValidationError(`Expected an object, got ${typeToString(value)}`, [])\n\t\t}\n\t}\n\n\tprivate getMatchingSchemaAndVariant(object: object): {\n\t\tmatchingSchema: Validatable<any> | undefined\n\t\tvariant: string\n\t} {\n\t\tconst variant = getOwnProperty(object, this.key)! as string & keyof Config\n\t\tif (!this.useNumberKeys && typeof variant !== 'string') {\n\t\t\tthrow new ValidationError(\n\t\t\t\t`Expected a string for key \"${this.key}\", got ${typeToString(variant)}`\n\t\t\t)\n\t\t} else if (this.useNumberKeys) {\n\t\t\t// Fast finite number check: numVariant - numVariant === 0 is false for Infinity and NaN\n\t\t\t// This avoids Number.isFinite function call overhead\n\t\t\tconst numVariant = Number(variant)\n\t\t\tif (numVariant - numVariant !== 0) {\n\t\t\t\tthrow new ValidationError(\n\t\t\t\t\t`Expected a number for key \"${this.key}\", got \"${variant as any}\"`\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tconst matchingSchema = hasOwnProperty(this.config, variant) ? this.config[variant] : undefined\n\t\treturn { matchingSchema, variant }\n\t}\n\n\t/**\n\t * Returns a new UnionValidator that can handle unknown variants using the provided function.\n\t *\n\t * @param unknownValueValidation - Function to validate/transform unknown variants\n\t * @returns A new UnionValidator that accepts unknown variants\n\t * @example\n\t * ```ts\n\t * const shapeValidator = T.union('type', { circle: circleValidator })\n\t * .validateUnknownVariants((obj, variant) => {\n\t * console.warn(`Unknown shape type: ${variant}`)\n\t * return obj as UnknownShape\n\t * })\n\t * ```\n\t */\n\tvalidateUnknownVariants<Unknown>(\n\t\tunknownValueValidation: (value: object, variant: string) => Unknown\n\t): UnionValidator<Key, Config, Unknown> {\n\t\treturn new UnionValidator(this.key, this.config, unknownValueValidation, this.useNumberKeys)\n\t}\n}\n\n/**\n * Validator for dictionary/map objects where both keys and values are validated.\n * Useful for validating objects used as key-value stores.\n *\n * @example\n * ```ts\n * const scoreDict = new DictValidator(T.string, T.number)\n * const scores = scoreDict.validate({\n * \"alice\": 100,\n * \"bob\": 85,\n * \"charlie\": 92\n * })\n * // scores is typed as Record<string, number>\n * ```\n * @public\n */\nexport class DictValidator<Key extends string, Value> extends Validator<Record<Key, Value>> {\n\t/**\n\t * Creates a new DictValidator.\n\t *\n\t * keyValidator - Validator for object keys\n\t * valueValidator - Validator for object values\n\t */\n\tconstructor(\n\t\tpublic readonly keyValidator: Validatable<Key>,\n\t\tpublic readonly valueValidator: Validatable<Value>\n\t) {\n\t\tsuper(\n\t\t\t(object) => {\n\t\t\t\tif (typeof object !== 'object' || object === null) {\n\t\t\t\t\tthrow new ValidationError(`Expected object, got ${typeToString(object)}`)\n\t\t\t\t}\n\n\t\t\t\t// Use for...in instead of Object.entries() to avoid array allocation\n\t\t\t\tfor (const key in object) {\n\t\t\t\t\tif (!hasOwnProperty(object, key)) continue\n\t\t\t\t\tif (IS_DEV) {\n\t\t\t\t\t\tprefixError(key, () => {\n\t\t\t\t\t\t\tkeyValidator.validate(key)\n\t\t\t\t\t\t\tvalueValidator.validate((object as Record<string, unknown>)[key])\n\t\t\t\t\t\t})\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Production: inline error handling to avoid closure overhead\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tkeyValidator.validate(key)\n\t\t\t\t\t\t\tvalueValidator.validate((object as Record<string, unknown>)[key])\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tif (err instanceof ValidationError) {\n\t\t\t\t\t\t\t\tthrow new ValidationError(err.rawMessage, [key, ...err.path])\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthrow new ValidationError((err as Error).toString(), [key])\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn object as Record<Key, Value>\n\t\t\t},\n\t\t\t(knownGoodValue, newValue) => {\n\t\t\t\tif (typeof newValue !== 'object' || newValue === null) {\n\t\t\t\t\tthrow new ValidationError(`Expected object, got ${typeToString(newValue)}`)\n\t\t\t\t}\n\n\t\t\t\tconst newObj = newValue as Record<string, unknown>\n\t\t\t\tlet isDifferent = false\n\t\t\t\tlet newKeyCount = 0\n\n\t\t\t\t// Use for...in instead of Object.entries() to avoid array allocation\n\t\t\t\tfor (const key in newObj) {\n\t\t\t\t\tif (!hasOwnProperty(newObj, key)) continue\n\t\t\t\t\tnewKeyCount++\n\n\t\t\t\t\tconst next = newObj[key]\n\n\t\t\t\t\tif (!hasOwnProperty(knownGoodValue, key)) {\n\t\t\t\t\t\tisDifferent = true\n\t\t\t\t\t\tif (IS_DEV) {\n\t\t\t\t\t\t\tprefixError(key, () => {\n\t\t\t\t\t\t\t\tkeyValidator.validate(key)\n\t\t\t\t\t\t\t\tvalueValidator.validate(next)\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tkeyValidator.validate(key)\n\t\t\t\t\t\t\t\tvalueValidator.validate(next)\n\t\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t\tif (err instanceof ValidationError) {\n\t\t\t\t\t\t\t\t\tthrow new ValidationError(err.rawMessage, [key, ...err.path])\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tthrow new ValidationError((err as Error).toString(), [key])\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tconst prev = (knownGoodValue as Record<string, unknown>)[key]\n\n\t\t\t\t\t// Quick reference equality check to avoid validator overhead\n\t\t\t\t\tif (Object.is(prev, next)) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tif (IS_DEV) {\n\t\t\t\t\t\tconst checked = prefixError(key, () => {\n\t\t\t\t\t\t\tif (valueValidator.validateUsingKnownGoodVersion) {\n\t\t\t\t\t\t\t\treturn valueValidator.validateUsingKnownGoodVersion(prev as Value, next)\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\treturn valueValidator.validate(next)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})\n\t\t\t\t\t\tif (!Object.is(checked, prev)) {\n\t\t\t\t\t\t\tisDifferent = true\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst checked = valueValidator.validateUsingKnownGoodVersion\n\t\t\t\t\t\t\t\t? valueValidator.validateUsingKnownGoodVersion(prev as Value, next)\n\t\t\t\t\t\t\t\t: valueValidator.validate(next)\n\t\t\t\t\t\t\tif (!Object.is(checked, prev)) {\n\t\t\t\t\t\t\t\tisDifferent = true\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tif (err instanceof ValidationError) {\n\t\t\t\t\t\t\t\tthrow new ValidationError(err.rawMessage, [key, ...err.path])\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthrow new ValidationError((err as Error).toString(), [key])\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Only check for removed keys if counts might differ\n\t\t\t\t// This avoids iterating over knownGoodValue when no keys were removed\n\t\t\t\tif (!isDifferent) {\n\t\t\t\t\tlet oldKeyCount = 0\n\t\t\t\t\tfor (const key in knownGoodValue) {\n\t\t\t\t\t\tif (hasOwnProperty(knownGoodValue, key)) {\n\t\t\t\t\t\t\toldKeyCount++\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (oldKeyCount !== newKeyCount) {\n\t\t\t\t\t\tisDifferent = true\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn isDifferent ? (newValue as Record<Key, Value>) : knownGoodValue\n\t\t\t}\n\t\t)\n\t}\n}\n\nfunction typeofValidator<T>(type: string): Validator<T> {\n\treturn new Validator((value) => {\n\t\tif (typeof value !== type) {\n\t\t\tthrow new ValidationError(`Expected ${type}, got ${typeToString(value)}`)\n\t\t}\n\t\treturn value as T\n\t})\n}\n\n/**\n * Validator that accepts any value without type checking. Useful as a starting point for\n * building custom validations or when you need to accept truly unknown data.\n *\n * @example\n * ```ts\n * const result = T.unknown.validate(anything) // Returns the value as-is\n * // result is typed as unknown\n * ```\n * @public\n */\nexport const unknown = new Validator((value) => value)\n/**\n * Validator that accepts any value and types it as 'any'. This should generally be avoided\n * as it bypasses type safety, but can be used as an escape hatch for prototyping.\n *\n * @example\n * ```ts\n * const result = T.any.validate(anything) // Returns the value as any\n * // result is typed as any - use with caution!\n * ```\n * @public\n */\nexport const any = new Validator((value): any => value)\n\n/**\n * Validator that ensures a value is a string.\n *\n * @example\n * ```ts\n * const name = T.string.validate(\"hello\") // Returns \"hello\" as string\n * T.string.validate(123) // Throws ValidationError: \"Expected string, got a number\"\n * ```\n * @public\n */\nexport const string = typeofValidator<string>('string')\n\n/**\n * Validator that ensures a value is a finite, non-NaN number. Rejects Infinity, -Infinity, and NaN.\n *\n * @example\n * ```ts\n * const count = T.number.validate(42) // Returns 42 as number\n * T.number.validate(NaN) // Throws ValidationError: \"Expected a number, got NaN\"\n * T.number.validate(Infinity) // Throws ValidationError: \"Expected a finite number, got Infinity\"\n * ```\n * @public\n */\nexport const number = new Validator<number>((value) => {\n\t// Fast path: check for valid finite number using arithmetic trick\n\t// value - value === 0 is false for Infinity and NaN (avoids function call overhead)\n\tif (Number.isFinite(value)) {\n\t\treturn value as number\n\t}\n\t// Slow path: determine specific error\n\tif (typeof value !== 'number') {\n\t\tthrow new ValidationError(`Expected number, got ${typeToString(value)}`)\n\t}\n\t// value !== value is true only for NaN (faster than Number.isNaN)\n\tif (value !== value) {\n\t\tthrow new ValidationError('Expected a number, got NaN')\n\t}\n\tthrow new ValidationError(`Expected a finite number, got ${value}`)\n})\n/**\n * Validator that ensures a value is a non-negative number (\\>= 0).\n * Despite the name \"positive\", this validator accepts zero.\n *\n * @example\n * ```ts\n * const price = T.positiveNumber.validate(29.99) // Returns 29.99\n * const free = T.positiveNumber.validate(0) // Returns 0 (valid)\n * T.positiveNumber.validate(-1) // Throws ValidationError: \"Expected a positive number, got -1\"\n * ```\n * @public\n */\nexport const positiveNumber = new Validator<number>((value) => {\n\tif (Number.isFinite(value) && (value as number) >= 0) {\n\t\treturn value as number\n\t}\n\tif (typeof value !== 'number') {\n\t\tthrow new ValidationError(`Expected number, got ${typeToString(value)}`)\n\t}\n\tif (value !== value) {\n\t\tthrow new ValidationError('Expected a number, got NaN')\n\t}\n\tif (value < 0) {\n\t\tthrow new ValidationError(`Expected a positive number, got ${value}`)\n\t}\n\tthrow new ValidationError(`Expected a finite number, got ${value}`)\n})\n/**\n * Validator that ensures a value is a positive number (\\> 0). Rejects zero and negative numbers.\n *\n * @example\n * ```ts\n * const quantity = T.nonZeroNumber.validate(0.01) // Returns 0.01\n * T.nonZeroNumber.validate(0) // Throws ValidationError: \"Expected a non-zero positive number, got 0\"\n * T.nonZeroNumber.validate(-5) // Throws ValidationError: \"Expected a non-zero positive number, got -5\"\n * ```\n * @public\n */\nexport const nonZeroNumber = new Validator<number>((value) => {\n\tif (Number.isFinite(value) && (value as number) > 0) {\n\t\treturn value as number\n\t}\n\tif (typeof value !== 'number') {\n\t\tthrow new ValidationError(`Expected number, got ${typeToString(value)}`)\n\t}\n\tif (value !== value) {\n\t\tthrow new ValidationError('Expected a number, got NaN')\n\t}\n\tif (value <= 0) {\n\t\tthrow new ValidationError(`Expected a non-zero positive number, got ${value}`)\n\t}\n\tthrow new ValidationError(`Expected a finite number, got ${value}`)\n})\n/**\n * Validator that ensures a value is a finite, non-zero number. Allows negative numbers.\n * Useful for scale factors that can be negative (for flipping) but not zero.\n *\n * @example\n * ```ts\n * const scale = T.nonZeroFiniteNumber.validate(-1.5) // Returns -1.5 (valid, allows negative)\n * T.nonZeroFiniteNumber.validate(0) // Throws ValidationError: \"Expected a non-zero number, got 0\"\n * T.nonZeroFiniteNumber.validate(Infinity) // Throws ValidationError\n * ```\n * @public\n */\nexport const nonZeroFiniteNumber = new Validator<number>((value) => {\n\tif (Number.isFinite(value) && (value as number) !== 0) {\n\t\treturn value as number\n\t}\n\tif (typeof value !== 'number') {\n\t\tthrow new ValidationError(`Expected number, got ${typeToString(value)}`)\n\t}\n\tif (value !== value) {\n\t\tthrow new ValidationError('Expected a number, got NaN')\n\t}\n\tif (value === 0) {\n\t\tthrow new ValidationError(`Expected a non-zero number, got 0`)\n\t}\n\tthrow new ValidationError(`Expected a finite number, got ${value}`)\n})\n/**\n * Validator that ensures a value is a number in the unit interval [0, 1].\n * Useful for opacity, percentages expressed as decimals, and other normalized values.\n *\n * @example\n * ```ts\n * const opacity = T.unitInterval.validate(0.5) // Returns 0.5\n * T.unitInterval.validate(0) // Returns 0 (valid)\n * T.unitInterval.validate(1) // Returns 1 (valid)\n * T.unitInterval.validate(1.5) // Throws ValidationError\n * T.unitInterval.validate(-0.1) // Throws ValidationError\n * ```\n * @public\n */\nexport const unitInterval = new Validator<number>((value) => {\n\tif (Number.isFinite(value) && (value as number) >= 0 && (value as number) <= 1) {\n\t\treturn value as number\n\t}\n\tif (typeof value !== 'number') {\n\t\tthrow new ValidationError(`Expected number, got ${typeToString(value)}`)\n\t}\n\tif (value !== value) {\n\t\tthrow new ValidationError('Expected a number, got NaN')\n\t}\n\tthrow new ValidationError(`Expected a number between 0 and 1, got ${value}`)\n})\n/**\n * Validator that ensures a value is an integer (whole number).\n *\n * @example\n * ```ts\n * const count = T.integer.validate(42) // Returns 42\n * T.integer.validate(3.14) // Throws ValidationError: \"Expected an integer, got 3.14\"\n * T.integer.validate(-5) // Returns -5 (negative integers are valid)\n * ```\n * @public\n */\nexport const integer = new Validator<number>((value) => {\n\t// Fast path: Number.isInteger checks typeof, finiteness, and integrality in one call\n\tif (Number.isInteger(value)) {\n\t\treturn value as number\n\t}\n\tif (typeof value !== 'number') {\n\t\tthrow new ValidationError(`Expected number, got ${typeToString(value)}`)\n\t}\n\tif (value !== value) {\n\t\tthrow new ValidationError('Expected a number, got NaN')\n\t}\n\tif (value - value !== 0) {\n\t\tthrow new ValidationError(`Expected a finite number, got ${value}`)\n\t}\n\tthrow new ValidationError(`Expected an integer, got ${value}`)\n})\n/**\n * Validator that ensures a value is a non-negative integer (\\>= 0).\n * Despite the name \"positive\", this validator accepts zero.\n *\n * @example\n * ```ts\n * const index = T.positiveInteger.validate(5) // Returns 5\n * const start = T.positiveInteger.validate(0) // Returns 0 (valid)\n * T.positiveInteger.validate(-1) // Throws ValidationError: \"Expected a positive integer, got -1\"\n * T.positiveInteger.validate(3.14) // Throws ValidationError: \"Expected an integer, got 3.14\"\n * ```\n * @public\n */\nexport const positiveInteger = new Validator<number>((value) => {\n\tif (Number.isInteger(value) && (value as number) >= 0) {\n\t\treturn value as number\n\t}\n\tif (typeof value !== 'number') {\n\t\tthrow new ValidationError(`Expected number, got ${typeToString(value)}`)\n\t}\n\tif (value !== value) {\n\t\tthrow new ValidationError('Expected a number, got NaN')\n\t}\n\tif (value - value !== 0) {\n\t\tthrow new ValidationError(`Expected a finite number, got ${value}`)\n\t}\n\tif (value < 0) {\n\t\tthrow new ValidationError(`Expected a positive integer, got ${value}`)\n\t}\n\tthrow new ValidationError(`Expected an integer, got ${value}`)\n})\n/**\n * Validator that ensures a value is a positive integer (\\> 0). Rejects zero and negative integers.\n *\n * @example\n * ```ts\n * const itemCount = T.nonZeroInteger.validate(1) // Returns 1\n * T.nonZeroInteger.validate(0) // Throws ValidationError: \"Expected a non-zero positive integer, got 0\"\n * T.nonZeroInteger.validate(-5) // Throws ValidationError: \"Expected a non-zero positive integer, got -5\"\n * ```\n * @public\n */\nexport const nonZeroInteger = new Validator<number>((value) => {\n\tif (Number.isInteger(value) && (value as number) > 0) {\n\t\treturn value as number\n\t}\n\tif (typeof value !== 'number') {\n\t\tthrow new ValidationError(`Expected number, got ${typeToString(value)}`)\n\t}\n\tif (value !== value) {\n\t\tthrow new ValidationError('Expected a number, got NaN')\n\t}\n\tif (value - value !== 0) {\n\t\tthrow new ValidationError(`Expected a finite number, got ${value}`)\n\t}\n\tif (value <= 0) {\n\t\tthrow new ValidationError(`Expected a non-zero positive integer, got ${value}`)\n\t}\n\tthrow new ValidationError(`Expected an integer, got ${value}`)\n})\n\n/**\n * Validator that ensures a value is a boolean.\n *\n * @example\n * ```ts\n * const isActive = T.boolean.validate(true) // Returns true\n * const isEnabled = T.boolean.validate(false) // Returns false\n * T.boolean.validate(\"true\") // Throws ValidationError: \"Expected boolean, got a string\"\n * ```\n * @public\n */\nexport const boolean = typeofValidator<boolean>('boolean')\n/**\n * Validator that ensures a value is a bigint.\n *\n * @example\n * ```ts\n * const largeNumber = T.bigint.validate(123n) // Returns 123n\n * T.bigint.validate(123) // Throws ValidationError: \"Expected bigint, got a number\"\n * ```\n * @public\n */\nexport const bigint = typeofValidator<bigint>('bigint')\n/**\n * Creates a validator that only accepts a specific literal value.\n *\n * @param expectedValue - The exact value that must be matched\n * @returns A validator that only accepts the specified literal value\n * @throws ValidationError When the value doesn't match the expected literal\n * @example\n * ```ts\n * const trueValidator = T.literal(true)\n * trueValidator.validate(true) // Returns true\n * trueValidator.validate(false) // Throws ValidationError\n *\n * const statusValidator = T.literal(\"active\")\n * statusValidator.validate(\"active\") // Returns \"active\"\n * statusValidator.validate(\"inactive\") // Throws ValidationError\n * ```\n * @public\n */\nexport function literal<T extends string | number | boolean>(expectedValue: T): Validator<T> {\n\treturn new Validator((actualValue) => {\n\t\tif (actualValue !== expectedValue) {\n\t\t\tthrow new ValidationError(`Expected ${expectedValue}, got ${JSON.stringify(actualValue)}`)\n\t\t}\n\t\treturn expectedValue\n\t})\n}\n\n/**\n * Validator that ensures a value is an array. Does not validate the contents of the array.\n * Use T.arrayOf() to validate both the array structure and its contents.\n *\n * @example\n * ```ts\n * const items = T.array.validate([1, \"hello\", true]) // Returns unknown[]\n * T.array.validate(\"not array\") // Throws ValidationError: \"Expected an array, got a string\"\n *\n * // For typed arrays, use T.arrayOf:\n * const numbers = T.arrayOf(T.number).validate([1, 2, 3]) // Returns number[]\n * ```\n * @public\n */\nexport const array = new Validator<unknown[]>((value) => {\n\tif (!Array.isArray(value)) {\n\t\tthrow new ValidationError(`Expected an array, got ${typeToString(value)}`)\n\t}\n\treturn value\n})\n\n/**\n * Creates a validator for arrays where each element is validated using the provided validator.\n *\n * @param itemValidator - Validator to use for each array element\n * @returns An ArrayOfValidator that validates both array structure and element types\n * @throws ValidationError When the value is not an array or when any element is invalid\n * @example\n * ```ts\n * const numberArray = T.arrayOf(T.number)\n * numberArray.validate([1, 2, 3]) // Returns number[]\n * numberArray.validate([1, \"2\", 3]) // Throws ValidationError at index 1\n *\n * const userArray = T.arrayOf(T.object({ name: T.string, age: T.number }))\n * ```\n * @public\n */\nexport function arrayOf<T>(itemValidator: Validatable<T>): ArrayOfValidator<T> {\n\treturn new ArrayOfValidator(itemValidator)\n}\n\n/**\n * Validator that ensures a value is an object (non-null, non-array). Does not validate\n * the properties of the object.\n *\n * @example\n * ```ts\n * const obj = T.unknownObject.validate({ any: \"properties\" }) // Returns Record<string, unknown>\n * T.unknownObject.validate(null) // Throws ValidationError: \"Expected object, got null\"\n * T.unknownObject.validate([1, 2, 3]) // Throws ValidationError: \"Expected object, got an array\"\n * ```\n * @public\n */\nexport const unknownObject = new Validator<Record<string, unknown>>((value) => {\n\tif (typeof value !== 'object' || value === null) {\n\t\tthrow new ValidationError(`Expected object, got ${typeToString(value)}`)\n\t}\n\treturn value as Record<string, unknown>\n})\n\n/**\n * Creates a validator for objects with a defined shape. Each property is validated using\n * its corresponding validator from the config object.\n *\n * @param config - Object mapping property names to their validators\n * @returns An ObjectValidator that validates the object structure and all properties\n * @throws ValidationError When the value is not an object or when any property is invalid\n * @example\n * ```ts\n * const userValidator = T.object({\n * name: T.string,\n * age: T.number,\n * email: T.string.optional(),\n * isActive: T.boolean\n * })\n *\n * const user = userValidator.validate({\n * name: \"Alice\",\n * age: 25,\n * email: \"alice@example.com\",\n * isActive: true\n * })\n * // user is typed with full type safety\n * ```\n * @public\n */\nexport function object<Shape extends object>(config: {\n\treadonly [K in keyof Shape]: Validatable<Shape[K]>\n}): ObjectValidator<MakeUndefinedOptional<Shape>> {\n\treturn new ObjectValidator(config) as any\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\t(Object.getPrototypeOf(value) === Object.prototype ||\n\t\t\tObject.getPrototypeOf(value) === null ||\n\t\t\tObject.getPrototypeOf(value) === STRUCTURED_CLONE_OBJECT_PROTOTYPE)\n\t)\n}\n\nfunction isValidJson(value: any): value is JsonValue {\n\tif (\n\t\tvalue === null ||\n\t\ttypeof value === 'number' ||\n\t\ttypeof value === 'string' ||\n\t\ttypeof value === 'boolean'\n\t) {\n\t\treturn true\n\t}\n\n\tif (Array.isArray(value)) {\n\t\treturn value.every(isValidJson)\n\t}\n\n\tif (isPlainObject(value)) {\n\t\treturn Object.values(value).every(isValidJson)\n\t}\n\n\treturn false\n}\n\n/**\n * Validator that ensures a value is valid JSON (string, number, boolean, null, array, or plain object).\n * Rejects functions, undefined, symbols, and other non-JSON values.\n *\n * @example\n * ```ts\n * const data = T.jsonValue.validate({ name: \"Alice\", scores: [1, 2, 3], active: true })\n * T.jsonValue.validate(undefined) // Throws ValidationError\n * T.jsonValue.validate(() => {}) // Throws ValidationError\n * ```\n * @public\n */\nexport const jsonValue: Validator<JsonValue> = new Validator<JsonValue>(\n\t(value): JsonValue => {\n\t\tif (isValidJson(value)) {\n\t\t\treturn value as JsonValue\n\t\t}\n\n\t\tthrow new ValidationError(`Expected json serializable value, got ${typeof value}`)\n\t},\n\t(knownGoodValue, newValue) => {\n\t\tif (Array.isArray(knownGoodValue) && Array.isArray(newValue)) {\n\t\t\tlet isDifferent = knownGoodValue.length !== newValue.length\n\t\t\tfor (let i = 0; i < newValue.length; i++) {\n\t\t\t\tif (i >= knownGoodValue.length) {\n\t\t\t\t\tisDifferent = true\n\t\t\t\t\tjsonValue.validate(newValue[i])\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst prev = knownGoodValue[i]\n\t\t\t\tconst next = newValue[i]\n\t\t\t\tif (Object.is(prev, next)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst checked = jsonValue.validateUsingKnownGoodVersion!(prev, next)\n\t\t\t\tif (!Object.is(checked, prev)) {\n\t\t\t\t\tisDifferent = true\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn isDifferent ? (newValue as JsonValue) : knownGoodValue\n\t\t} else if (isPlainObject(knownGoodValue) && isPlainObject(newValue)) {\n\t\t\tlet isDifferent = false\n\t\t\tfor (const key of Object.keys(newValue)) {\n\t\t\t\tif (!hasOwnProperty(knownGoodValue, key)) {\n\t\t\t\t\tisDifferent = true\n\t\t\t\t\tjsonValue.validate(newValue[key])\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst prev = knownGoodValue[key]\n\t\t\t\tconst next = newValue[key]\n\t\t\t\tif (Object.is(prev, next)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst checked = jsonValue.validateUsingKnownGoodVersion!(prev!, next)\n\t\t\t\tif (!Object.is(checked, prev)) {\n\t\t\t\t\tisDifferent = true\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const key of Object.keys(knownGoodValue)) {\n\t\t\t\tif (!hasOwnProperty(newValue, key)) {\n\t\t\t\t\tisDifferent = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn isDifferent ? (newValue as JsonValue) : knownGoodValue\n\t\t} else {\n\t\t\treturn jsonValue.validate(newValue)\n\t\t}\n\t}\n)\n\n/**\n * Creates a validator for JSON dictionaries (objects with string keys and JSON-serializable values).\n *\n * @returns A DictValidator that validates string keys and JSON values\n * @throws ValidationError When keys are not strings or values are not JSON-serializable\n * @example\n * ```ts\n * const config = T.jsonDict().validate({\n * \"setting1\": \"value\",\n * \"setting2\": 42,\n * \"setting3\": [\"a\", \"b\", \"c\"],\n * \"setting4\": { nested: true }\n * })\n * ```\n * @public\n */\nexport function jsonDict(): DictValidator<string, JsonValue> {\n\treturn dict(string, jsonValue)\n}\n\n/**\n * Creates a validator for dictionary objects where both keys and values are validated.\n * Useful for validating objects used as key-value maps.\n *\n * @param keyValidator - Validator for object keys\n * @param valueValidator - Validator for object values\n * @returns A DictValidator that validates all keys and values\n * @throws ValidationError When any key or value is invalid\n * @example\n * ```ts\n * const scores = T.dict(T.string, T.number)\n * scores.validate({ \"alice\": 100, \"bob\": 85 }) // Valid\n *\n * const userPrefs = T.dict(T.string, T.object({\n * theme: T.literalEnum('light', 'dark'),\n * notifications: T.boolean\n * }))\n * ```\n * @public\n */\nexport function dict<Key extends string, Value>(\n\tkeyValidator: Validatable<Key>,\n\tvalueValidator: Validatable<Value>\n): DictValidator<Key, Value> {\n\treturn new DictValidator(keyValidator, valueValidator)\n}\n\n/**\n * Creates a validator for discriminated union types. Validates objects that can be one of\n * several variants, distinguished by a discriminator property.\n *\n * @param key - The discriminator property name used to determine the variant\n * @param config - Object mapping variant names to their validators\n * @returns A UnionValidator that validates based on the discriminator value\n * @throws ValidationError When the discriminator is invalid or the variant validation fails\n * @example\n * ```ts\n * const shapeValidator = T.union('type', {\n * circle: T.object({ type: T.literal('circle'), radius: T.number }),\n * square: T.object({ type: T.literal('square'), size: T.number }),\n * triangle: T.object({ type: T.literal('triangle'), base: T.number, height: T.number })\n * })\n *\n * const circle = shapeValidator.validate({ type: 'circle', radius: 5 })\n * // circle is typed as { type: 'circle'; radius: number }\n * ```\n * @public\n */\nexport function union<Key extends string, Config extends UnionValidatorConfig<Key, Config>>(\n\tkey: Key,\n\tconfig: Config\n): UnionValidator<Key, Config> {\n\treturn new UnionValidator(\n\t\tkey,\n\t\tconfig,\n\t\t(_unknownValue, unknownVariant) => {\n\t\t\tthrow new ValidationError(\n\t\t\t\t`Expected one of ${Object.keys(config)\n\t\t\t\t\t.map((key) => JSON.stringify(key))\n\t\t\t\t\t.join(' or ')}, got ${JSON.stringify(unknownVariant)}`,\n\t\t\t\t[key]\n\t\t\t)\n\t\t},\n\t\tfalse\n\t)\n}\n\n/**\n * Creates a validator for discriminated union types using number discriminators instead of strings.\n * This is an internal function used for specific cases where numeric discriminators are needed.\n *\n * @param key - The discriminator property name used to determine the variant\n * @param config - Object mapping variant names to their validators\n * @returns A UnionValidator that validates based on numeric discriminator values\n * @throws ValidationError When the discriminator is invalid or the variant validation fails\n * @internal\n */\nexport function numberUnion<Key extends string, Config extends UnionValidatorConfig<Key, Config>>(\n\tkey: Key,\n\tconfig: Config\n): UnionValidator<Key, Config> {\n\treturn new UnionValidator(\n\t\tkey,\n\t\tconfig,\n\t\t(unknownValue, unknownVariant) => {\n\t\t\tthrow new ValidationError(\n\t\t\t\t`Expected one of ${Object.keys(config)\n\t\t\t\t\t.map((key) => JSON.stringify(key))\n\t\t\t\t\t.join(' or ')}, got ${JSON.stringify(unknownVariant)}`,\n\t\t\t\t[key]\n\t\t\t)\n\t\t},\n\t\ttrue\n\t)\n}\n\n/**\n * Creates a validator for named model objects with enhanced error reporting. The model name\n * will be included in error messages to provide better debugging context.\n *\n * @param name - The name of the model (used in error messages)\n * @param validator - The validator for the model structure\n * @returns A Validator with enhanced error reporting that includes the model name\n * @throws ValidationError With model name context when validation fails\n * @example\n * ```ts\n * const userModel = T.model('User', T.object({\n * id: T.string,\n * name: T.string,\n * email: T.linkUrl\n * }))\n *\n * // Error message will be: \"At User.email: Expected a valid url, got 'invalid-email'\"\n * ```\n * @public\n */\nexport function model<T extends { readonly id: string }>(\n\tname: string,\n\tvalidator: Validatable<T>\n): Validator<T> {\n\treturn new Validator(\n\t\t(value) => {\n\t\t\treturn prefixError(name, () => validator.validate(value))\n\t\t},\n\t\t(prevValue, newValue) => {\n\t\t\treturn prefixError(name, () => {\n\t\t\t\tif (validator.validateUsingKnownGoodVersion) {\n\t\t\t\t\treturn validator.validateUsingKnownGoodVersion(prevValue, newValue)\n\t\t\t\t} else {\n\t\t\t\t\treturn validator.validate(newValue)\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t)\n}\n\n/**\n * Creates a validator that only accepts values from a given Set of allowed values.\n *\n * @param values - Set containing the allowed values\n * @returns A validator that only accepts values from the provided set\n * @throws ValidationError When the value is not in the allowed set\n * @example\n * ```ts\n * const allowedColors = new Set(['red', 'green', 'blue'] as const)\n * const colorValidator = T.setEnum(allowedColors)\n * colorValidator.validate('red') // Returns 'red'\n * colorValidator.validate('yellow') // Throws ValidationError\n * ```\n * @public\n */\nexport function setEnum<T>(values: ReadonlySet<T>): Validator<T> {\n\treturn new Validator((value) => {\n\t\tif (!values.has(value as T)) {\n\t\t\tconst valuesString = Array.from(values, (value) => JSON.stringify(value)).join(' or ')\n\t\t\tthrow new ValidationError(`Expected ${valuesString}, got ${value}`)\n\t\t}\n\t\treturn value as T\n\t})\n}\n\n/**\n * Creates a validator that accepts either the validated type or undefined.\n *\n * @param validator - The base validator to make optional\n * @returns A validator that accepts T or undefined\n * @example\n * ```ts\n * const optionalString = T.optional(T.string)\n * optionalString.validate(\"hello\") // Returns \"hello\"\n * optionalString.validate(undefined) // Returns undefined\n * optionalString.validate(null) // Throws ValidationError\n * ```\n * @public\n */\nexport function optional<T>(validator: Validatable<T>): Validator<T | undefined> {\n\treturn new Validator(\n\t\t(value) => {\n\t\t\tif (value === undefined) return undefined\n\t\t\treturn validator.validate(value)\n\t\t},\n\t\t(knownGoodValue, newValue) => {\n\t\t\tif (newValue === undefined) return undefined\n\t\t\tif (validator.validateUsingKnownGoodVersion && knownGoodValue !== undefined) {\n\t\t\t\treturn validator.validateUsingKnownGoodVersion(knownGoodValue as T, newValue)\n\t\t\t}\n\t\t\treturn validator.validate(newValue)\n\t\t},\n\t\t// Propagate skipSameValueCheck from inner validator to allow refine wrappers\n\t\tvalidator instanceof Validator && validator.skipSameValueCheck\n\t)\n}\n\n/**\n * Creates a validator that accepts either the validated type or null.\n *\n * @param validator - The base validator to make nullable\n * @returns A validator that accepts T or null\n * @example\n * ```ts\n * const nullableString = T.nullable(T.string)\n * nullableString.validate(\"hello\") // Returns \"hello\"\n * nullableString.validate(null) // Returns null\n * nullableString.validate(undefined) // Throws ValidationError\n * ```\n * @public\n */\nexport function nullable<T>(validator: Validatable<T>): Validator<T | null> {\n\treturn new Validator(\n\t\t(value) => {\n\t\t\tif (value === null) return null\n\t\t\treturn validator.validate(value)\n\t\t},\n\t\t(knownGoodValue, newValue) => {\n\t\t\tif (newValue === null) return null\n\t\t\tif (validator.validateUsingKnownGoodVersion && knownGoodValue !== null) {\n\t\t\t\treturn validator.validateUsingKnownGoodVersion(knownGoodValue as T, newValue)\n\t\t\t}\n\t\t\treturn validator.validate(newValue)\n\t\t},\n\t\t// Propagate skipSameValueCheck from inner validator to allow refine wrappers\n\t\tvalidator instanceof Validator && validator.skipSameValueCheck\n\t)\n}\n\n/**\n * Creates a validator that only accepts one of the provided literal values.\n * This is a convenience function that creates a setEnum from the provided values.\n *\n * @param values - The allowed literal values\n * @returns A validator that only accepts the provided literal values\n * @throws ValidationError When the value is not one of the allowed literals\n * @example\n * ```ts\n * const themeValidator = T.literalEnum('light', 'dark', 'auto')\n * themeValidator.validate('light') // Returns 'light'\n * themeValidator.validate('blue') // Throws ValidationError: Expected \"light\" or \"dark\" or \"auto\", got blue\n * ```\n * @public\n */\nexport function literalEnum<const Values extends readonly unknown[]>(\n\t...values: Values\n): Validator<Values[number]> {\n\treturn setEnum(new Set(values))\n}\n\nfunction parseUrl(str: string) {\n\ttry {\n\t\treturn new URL(str)\n\t} catch {\n\t\tif (str.startsWith('/') || str.startsWith('./')) {\n\t\t\ttry {\n\t\t\t\treturn new URL(str, 'http://example.com')\n\t\t\t} catch {\n\t\t\t\tthrow new ValidationError(`Expected a valid url, got ${JSON.stringify(str)}`)\n\t\t\t}\n\t\t}\n\t\tthrow new ValidationError(`Expected a valid url, got ${JSON.stringify(str)}`)\n\t}\n}\n\nconst validLinkProtocols = new Set(['http:', 'https:', 'mailto:'])\n\n/**\n * Validator for URLs that are safe to use as user-facing links. Accepts http, https, and mailto protocols.\n * This validator provides security by rejecting potentially dangerous protocols like javascript:.\n *\n * @example\n * ```ts\n * const link = T.linkUrl.validate(\"https://example.com\") // Valid\n * const email = T.linkUrl.validate(\"mailto:user@example.com\") // Valid\n * T.linkUrl.validate(\"\") // Valid (empty string allowed)\n * T.linkUrl.validate(\"javascript:alert(1)\") // Throws ValidationError (unsafe protocol)\n * ```\n * @public\n */\nexport const linkUrl = string.check((value) => {\n\tif (value === '') return\n\tconst url = parseUrl(value)\n\n\tif (!validLinkProtocols.has(url.protocol.toLowerCase())) {\n\t\tthrow new ValidationError(\n\t\t\t`Expected a valid url, got ${JSON.stringify(value)} (invalid protocol)`\n\t\t)\n\t}\n})\n\n// N.B. asset: is a reference to the local indexedDB object store.\nconst validSrcProtocols = new Set(['http:', 'https:', 'data:', 'asset:'])\n\n/**\n * Validator for URLs that are safe to use as asset sources. Accepts http, https, data, and asset protocols.\n * The asset: protocol refers to tldraw's local IndexedDB object store.\n *\n * @example\n * ```ts\n * const imageUrl = T.srcUrl.validate(\"https://example.com/image.png\") // Valid\n * const dataUrl = T.srcUrl.validate(\"data:image/png;base64,iVBORw0...\") // Valid\n * const assetUrl = T.srcUrl.validate(\"asset:abc123\") // Valid (local asset reference)\n * T.srcUrl.validate(\"\") // Valid (empty string allowed)\n * ```\n * @public\n */\nexport const srcUrl = string.check((value) => {\n\tif (value === '') return\n\tconst url = parseUrl(value)\n\n\tif (!validSrcProtocols.has(url.protocol.toLowerCase())) {\n\t\tthrow new ValidationError(\n\t\t\t`Expected a valid url, got ${JSON.stringify(value)} (invalid protocol)`\n\t\t)\n\t}\n})\n\n/**\n * Validator for HTTP and HTTPS URLs only. Rejects all other protocols.\n *\n * @example\n * ```ts\n * const apiUrl = T.httpUrl.validate(\"https://api.example.com\") // Valid\n * const httpUrl = T.httpUrl.validate(\"http://localhost:3000\") // Valid\n * T.httpUrl.validate(\"\") // Valid (empty string allowed)\n * T.httpUrl.validate(\"ftp://files.example.com\") // Throws ValidationError (not http/https)\n * ```\n * @public\n */\nexport const httpUrl = string.check((value) => {\n\tif (value === '') return\n\tconst url = parseUrl(value)\n\n\tif (!url.protocol.toLowerCase().match(/^https?:$/)) {\n\t\tthrow new ValidationError(\n\t\t\t`Expected a valid url, got ${JSON.stringify(value)} (invalid protocol)`\n\t\t)\n\t}\n})\n\n/**\n * Validator for IndexKey values used in tldraw's indexing system. An IndexKey is a string\n * that meets specific format requirements for use as a database index.\n *\n * @throws ValidationError When the string is not a valid IndexKey format\n * @example\n * ```ts\n * const key = T.indexKey.validate(\"valid_index_key\") // Returns IndexKey\n * T.indexKey.validate(\"invalid key!\") // Throws ValidationError (invalid format)\n * ```\n * @public\n */\nexport const indexKey = string.refine<IndexKey>((key) => {\n\ttry {\n\t\tvalidateIndexKey(key)\n\t\treturn key\n\t} catch {\n\t\tthrow new ValidationError(`Expected an index key, got ${JSON.stringify(key)}`)\n\t}\n})\n\n/**\n * Creates a validator that accepts values matching either of two validators.\n * Tries the first validator, and if it fails, tries the second validator.\n *\n * @param v1 - The first validator to try\n * @param v2 - The second validator to try if the first fails\n * @returns A validator that accepts values matching either validator\n * @throws ValidationError When the value matches neither validator (throws error from v2)\n * @example\n * ```ts\n * const stringOrNumber = T.or(T.string, T.number)\n * stringOrNumber.validate(\"hello\") // Returns \"hello\" as string\n * stringOrNumber.validate(42) // Returns 42 as number\n * stringOrNumber.validate(true) // Throws ValidationError from number validator\n * ```\n * @public\n */\nexport function or<T1, T2>(v1: Validatable<T1>, v2: Validatable<T2>): Validator<T1 | T2> {\n\treturn new Validator((value) => {\n\t\ttry {\n\t\t\treturn v1.validate(value)\n\t\t} catch {\n\t\t\treturn v2.validate(value)\n\t\t}\n\t})\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["object", "key", "value"]
|
|
7
7
|
}
|
package/dist-esm/index.d.mts
CHANGED
|
@@ -322,6 +322,20 @@ declare function model<T extends {
|
|
|
322
322
|
readonly id: string;
|
|
323
323
|
}>(name: string, validator: Validatable<T>): Validator<T>;
|
|
324
324
|
|
|
325
|
+
/**
|
|
326
|
+
* Validator that ensures a value is a finite, non-zero number. Allows negative numbers.
|
|
327
|
+
* Useful for scale factors that can be negative (for flipping) but not zero.
|
|
328
|
+
*
|
|
329
|
+
* @example
|
|
330
|
+
* ```ts
|
|
331
|
+
* const scale = T.nonZeroFiniteNumber.validate(-1.5) // Returns -1.5 (valid, allows negative)
|
|
332
|
+
* T.nonZeroFiniteNumber.validate(0) // Throws ValidationError: "Expected a non-zero number, got 0"
|
|
333
|
+
* T.nonZeroFiniteNumber.validate(Infinity) // Throws ValidationError
|
|
334
|
+
* ```
|
|
335
|
+
* @public
|
|
336
|
+
*/
|
|
337
|
+
declare const nonZeroFiniteNumber: Validator<number>;
|
|
338
|
+
|
|
325
339
|
/**
|
|
326
340
|
* Validator that ensures a value is a positive integer (\> 0). Rejects zero and negative integers.
|
|
327
341
|
*
|
|
@@ -613,6 +627,8 @@ declare namespace T {
|
|
|
613
627
|
number,
|
|
614
628
|
positiveNumber,
|
|
615
629
|
nonZeroNumber,
|
|
630
|
+
nonZeroFiniteNumber,
|
|
631
|
+
unitInterval,
|
|
616
632
|
integer,
|
|
617
633
|
positiveInteger,
|
|
618
634
|
nonZeroInteger,
|
|
@@ -735,6 +751,22 @@ export declare type UnionValidatorConfig<Key extends string, Config> = {
|
|
|
735
751
|
};
|
|
736
752
|
};
|
|
737
753
|
|
|
754
|
+
/**
|
|
755
|
+
* Validator that ensures a value is a number in the unit interval [0, 1].
|
|
756
|
+
* Useful for opacity, percentages expressed as decimals, and other normalized values.
|
|
757
|
+
*
|
|
758
|
+
* @example
|
|
759
|
+
* ```ts
|
|
760
|
+
* const opacity = T.unitInterval.validate(0.5) // Returns 0.5
|
|
761
|
+
* T.unitInterval.validate(0) // Returns 0 (valid)
|
|
762
|
+
* T.unitInterval.validate(1) // Returns 1 (valid)
|
|
763
|
+
* T.unitInterval.validate(1.5) // Throws ValidationError
|
|
764
|
+
* T.unitInterval.validate(-0.1) // Throws ValidationError
|
|
765
|
+
* ```
|
|
766
|
+
* @public
|
|
767
|
+
*/
|
|
768
|
+
declare const unitInterval: Validator<number>;
|
|
769
|
+
|
|
738
770
|
/**
|
|
739
771
|
* Validator that accepts any value without type checking. Useful as a starting point for
|
|
740
772
|
* building custom validations or when you need to accept truly unknown data.
|
|
@@ -854,13 +886,17 @@ declare class ValidationError extends Error {
|
|
|
854
886
|
export declare class Validator<T> implements Validatable<T> {
|
|
855
887
|
readonly validationFn: ValidatorFn<T>;
|
|
856
888
|
readonly validateUsingKnownGoodVersionFn?: undefined | ValidatorUsingKnownGoodVersionFn<T>;
|
|
889
|
+
/* Excluded from this release type: skipSameValueCheck */
|
|
857
890
|
/**
|
|
858
891
|
* Creates a new Validator instance.
|
|
859
892
|
*
|
|
860
893
|
* validationFn - Function that validates and returns a value of type T
|
|
861
894
|
* validateUsingKnownGoodVersionFn - Optional performance-optimized validation function
|
|
895
|
+
* skipSameValueCheck - Internal flag to skip dev check for validators that transform values
|
|
862
896
|
*/
|
|
863
|
-
constructor(validationFn: ValidatorFn<T>, validateUsingKnownGoodVersionFn?: undefined | ValidatorUsingKnownGoodVersionFn<T
|
|
897
|
+
constructor(validationFn: ValidatorFn<T>, validateUsingKnownGoodVersionFn?: undefined | ValidatorUsingKnownGoodVersionFn<T>,
|
|
898
|
+
/** @internal */
|
|
899
|
+
skipSameValueCheck?: boolean);
|
|
864
900
|
/**
|
|
865
901
|
* Validates an unknown value and returns it with the correct type. The returned value is
|
|
866
902
|
* guaranteed to be referentially equal to the passed value.
|