UNPKG

ascertain

Version:

0-Deps, simple, fast, for browser and node js object schema validator

1 lines 123 kB
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Symbol for validating object keys against a schema.\n */\nexport const $keys = Symbol.for('@@keys');\n/**\n * Symbol for validating object values against a schema.\n */\nexport const $values = Symbol.for('@@values');\n/**\n * Symbol for enforcing strict object validation (no extra properties allowed).\n */\nexport const $strict = Symbol.for('@@strict');\n\nconst $op = Symbol.for('@@op');\n\nconst OR = Symbol.for('@@or');\nconst AND = Symbol.for('@@and');\nconst OPTIONAL = Symbol.for('@@optional');\nconst TUPLE = Symbol.for('@@tuple');\nconst DISCRIMINATED = Symbol.for('@@discriminated');\nconst CHECK = Symbol.for('@@check');\nconst ERR = Symbol.for('@@err');\n\ninterface ErrShape {\n readonly message: string;\n readonly [ERR]: true;\n}\nfunction ErrCtor(this: ErrShape, message: string): void {\n (this as { message: string }).message = message;\n}\n(ErrCtor.prototype as { [ERR]: true })[ERR] = true;\n\ntype Mutable<T> = { -readonly [K in keyof T]: T[K] };\n\ninterface OrShape<T> {\n readonly schemas: Schema<T>[];\n readonly [$op]: typeof OR;\n}\ninterface AndShape<T> {\n readonly schemas: Schema<T>[];\n readonly [$op]: typeof AND;\n}\ninterface OptionalShape<T> {\n readonly schemas: Schema<T>[];\n readonly [$op]: typeof OPTIONAL;\n}\ninterface TupleShape<T> {\n readonly schemas: Schema<T>[];\n readonly [$op]: typeof TUPLE;\n}\ninterface DiscriminatedShape<T> {\n readonly schemas: Schema<T>[];\n readonly [$op]: typeof DISCRIMINATED;\n readonly key: string;\n}\nexport interface CheckContext {\n ref(value: unknown): string;\n}\ninterface CheckShape {\n readonly [$op]: typeof CHECK;\n readonly compile: (value: string, ctx: CheckContext) => { check: string; message: string };\n}\n\ntype Tagged<T> = OrShape<T> | AndShape<T> | OptionalShape<T> | TupleShape<T> | DiscriminatedShape<T> | CheckShape;\n\nconst OrCtor = function <T>(this: OrShape<T>, schemas: Schema<T>[]) {\n (this as Mutable<OrShape<T>>).schemas = schemas;\n} as unknown as { new <T>(schemas: Schema<T>[]): OrShape<T>; prototype: { [$op]: typeof OR } };\nOrCtor.prototype[$op] = OR;\n\nconst AndCtor = function <T>(this: AndShape<T>, schemas: Schema<T>[]) {\n (this as Mutable<AndShape<T>>).schemas = schemas;\n} as unknown as { new <T>(schemas: Schema<T>[]): AndShape<T>; prototype: { [$op]: typeof AND } };\nAndCtor.prototype[$op] = AND;\n\nconst OptionalCtor = function <T>(this: OptionalShape<T>, schema: Schema<T>) {\n (this as Mutable<OptionalShape<T>>).schemas = [schema];\n} as unknown as { new <T>(schema: Schema<T>): OptionalShape<T>; prototype: { [$op]: typeof OPTIONAL } };\nOptionalCtor.prototype[$op] = OPTIONAL;\n\nconst TupleCtor = function <T>(this: TupleShape<T>, schemas: Schema<T>[]) {\n (this as Mutable<TupleShape<T>>).schemas = schemas;\n} as unknown as { new <T>(schemas: Schema<T>[]): TupleShape<T>; prototype: { [$op]: typeof TUPLE } };\nTupleCtor.prototype[$op] = TUPLE;\n\nconst DiscriminatedCtor = function <T>(this: DiscriminatedShape<T>, schemas: Schema<T>[], key: string) {\n (this as Mutable<DiscriminatedShape<T>>).schemas = schemas;\n (this as Mutable<DiscriminatedShape<T>>).key = key;\n} as unknown as { new <T>(schemas: Schema<T>[], key: string): DiscriminatedShape<T>; prototype: { [$op]: typeof DISCRIMINATED } };\nDiscriminatedCtor.prototype[$op] = DISCRIMINATED;\n\nconst CheckCtor = function (this: CheckShape, compileFn: CheckShape['compile']) {\n (this as Mutable<CheckShape>).compile = compileFn;\n} as unknown as { new (compileFn: CheckShape['compile']): CheckShape; prototype: { [$op]: typeof CHECK } };\nCheckCtor.prototype[$op] = CHECK;\n\n/**\n * Represents a schema for validating data.\n *\n * Schemas can be defined for various data types, including objects, arrays, and primitives.\n *\n * @template T - The type of data the schema validates.\n */\nexport type Schema<T> =\n T extends Record<string | number | symbol, unknown>\n ? { [K in keyof T]?: Schema<T[K]> | unknown } & { [$keys]?: Schema<keyof T> } & { [$values]?: Schema<T[keyof T]> } & { [$strict]?: boolean }\n : T extends Array<infer A>\n ? Schema<A>[] | unknown\n : unknown;\n\n/**\n * Operator for validating data against any of the provided schemas (logical OR).\n */\nexport const or = <T>(...schemas: Schema<T>[]): OrShape<T> => {\n if (schemas.length === 0) throw new TypeError('Operator requires at least one schema');\n return new OrCtor(schemas);\n};\n\n/**\n * Operator for validating data against all provided schemas (logical AND).\n */\nexport const and = <T>(...schemas: Schema<T>[]): AndShape<T> => {\n if (schemas.length === 0) throw new TypeError('Operator requires at least one schema');\n return new AndCtor(schemas);\n};\n\n/**\n * Operator for making a schema optional (nullable).\n */\nexport const optional = <T>(schema: Schema<T>): OptionalShape<T> => new OptionalCtor(schema);\n\n/**\n * Operator for validating data against a fixed-length tuple of schemas.\n */\nexport const tuple = <T>(...schemas: Schema<T>[]): TupleShape<T> => {\n if (schemas.length === 0) throw new TypeError('Operator requires at least one schema');\n return new TupleCtor(schemas);\n};\n\n/**\n * Operator for validating data against a discriminated union.\n *\n * Optimizes validation by checking the discriminant field first and only\n * validating the matching variant. More efficient than `or()` for unions\n * where each variant has a common field with a unique literal value.\n *\n * @param schemas - Array of object schemas, each with a discriminant field containing a literal value.\n * @param key - The name of the discriminant field present in all variants.\n *\n * @example\n * ```typescript\n * const messageSchema = discriminated([\n * { type: 'email', address: String },\n * { type: 'sms', phone: String },\n * { type: 'push', token: String },\n * ], 'type');\n * ```\n */\nexport const discriminated = <T>(schemas: Schema<T>[], key: string): DiscriminatedShape<T> => {\n if (schemas.length === 0) throw new TypeError('discriminated requires at least one schema');\n return new DiscriminatedCtor(schemas, key);\n};\n\n/**\n * Creates a custom validation check.\n * Accepts a predicate function or an object with a compile method for inlined checks.\n *\n * @param fnOrOpts - A predicate function `(value) => boolean` or an object with a `compile` method for code-generating checks.\n * @param message - Optional custom error message.\n */\nexport const check = (\n fnOrOpts: ((v: unknown) => boolean) | { compile: (value: string, ctx: CheckContext) => { check: string; message: string } },\n message?: string,\n): CheckShape => {\n if (typeof fnOrOpts === 'function') {\n return new CheckCtor((v, ctx) => {\n const fnRef = ctx.ref(fnOrOpts);\n return {\n check: `!${fnRef}(${v})`,\n message: message ? JSON.stringify(message) : `\\`check failed for value \\${${v}}\\``,\n };\n });\n }\n return new CheckCtor(fnOrOpts.compile);\n};\n\n/**\n * Validates that a numeric value is greater than or equal to `n`.\n *\n * @param n - The minimum allowed value (inclusive).\n * @param message - Optional custom error message.\n */\nexport const min = (n: number, message?: string): CheckShape =>\n new CheckCtor((v) => ({\n check: `${v} < ${n}`,\n message: message ? JSON.stringify(message) : `\\`must be >= ${n}, got \\${${v}}\\``,\n }));\n\n/**\n * Validates that a numeric value is less than or equal to `n`.\n *\n * @param n - The maximum allowed value (inclusive).\n * @param message - Optional custom error message.\n */\nexport const max = (n: number, message?: string): CheckShape =>\n new CheckCtor((v) => ({\n check: `${v} > ${n}`,\n message: message ? JSON.stringify(message) : `\\`must be <= ${n}, got \\${${v}}\\``,\n }));\n\n/**\n * Validates that a value is an integer.\n *\n * @param message - Optional custom error message.\n */\nexport const integer = (message?: string): CheckShape =>\n new CheckCtor((v) => ({\n check: `!Number.isInteger(${v})`,\n message: message ? JSON.stringify(message) : `\\`must be an integer, got \\${${v}}\\``,\n }));\n\n/**\n * Validates that a value's length is greater than or equal to `n`.\n *\n * @param n - The minimum allowed length (inclusive).\n * @param message - Optional custom error message.\n */\nexport const minLength = (n: number, message?: string): CheckShape =>\n new CheckCtor((v) => ({\n check: `${v}.length < ${n}`,\n message: message ? JSON.stringify(message) : `\\`length must be >= ${n}, got \\${${v}.length}\\``,\n }));\n\n/**\n * Validates that a value's length is less than or equal to `n`.\n *\n * @param n - The maximum allowed length (inclusive).\n * @param message - Optional custom error message.\n */\nexport const maxLength = (n: number, message?: string): CheckShape =>\n new CheckCtor((v) => ({\n check: `${v}.length > ${n}`,\n message: message ? JSON.stringify(message) : `\\`length must be <= ${n}, got \\${${v}.length}\\``,\n }));\n\n/**\n * Validates that a numeric value is strictly greater than `n`.\n *\n * @param n - The exclusive lower bound.\n * @param message - Optional custom error message.\n */\nexport const gt = (n: number, message?: string): CheckShape =>\n new CheckCtor((v) => ({\n check: `${v} <= ${n}`,\n message: message ? JSON.stringify(message) : `\\`must be > ${n}, got \\${${v}}\\``,\n }));\n\n/**\n * Validates that a numeric value is strictly less than `n`.\n *\n * @param n - The exclusive upper bound.\n * @param message - Optional custom error message.\n */\nexport const lt = (n: number, message?: string): CheckShape =>\n new CheckCtor((v) => ({\n check: `${v} >= ${n}`,\n message: message ? JSON.stringify(message) : `\\`must be < ${n}, got \\${${v}}\\``,\n }));\n\n/**\n * Validates that a numeric value is a multiple of `n`.\n *\n * @param n - The divisor to check against.\n * @param message - Optional custom error message.\n */\nexport const multipleOf = (n: number, message?: string): CheckShape =>\n new CheckCtor((v) => ({\n check: `${v} % ${n} !== 0`,\n message: message ? JSON.stringify(message) : `\\`must be a multiple of ${n}, got \\${${v}}\\``,\n }));\n\n/**\n * Validates that an array contains only unique items.\n *\n * @param message - Optional custom error message.\n */\nexport const uniqueItems = (message?: string): CheckShape =>\n new CheckCtor((v) => ({\n check: `new Set(${v}).size !== ${v}.length`,\n message: message ? JSON.stringify(message) : `\\`must have unique items\\``,\n }));\n\ntype EnumLike = { [k: string]: string | number; [n: number]: string };\n\n/**\n * Validates that a value is one of the allowed values. Accepts an array or an enum-like object.\n *\n * @param values - Array of allowed values or an enum-like object.\n * @param message - Optional custom error message.\n */\nexport const oneOf = <T extends EnumLike>(values: (string | number)[] | T, message?: string): CheckShape => {\n const set = new Set(Array.isArray(values) ? values : Object.values(values));\n return new CheckCtor((v, ctx) => ({\n check: `!${ctx.ref(set)}.has(${v})`,\n message: message ? JSON.stringify(message) : `\\`must be one of [${[...set].map(toLiteral).join(', ')}], got \\${${v}}\\``,\n }));\n};\n\n/**\n * Decodes a base64-encoded string to UTF-8.\n *\n * Uses `Buffer` in Node.js environments and `atob` in browsers.\n *\n * @param value - The base64-encoded string to decode.\n * @returns The decoded UTF-8 string.\n */\nconst utf8Encoder = new TextEncoder();\nconst utf8Decoder = new TextDecoder('utf-8');\n\nconst fromBase64Bytes = (value: string): Uint8Array => {\n const bin = atob(value);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n};\n\nexport const fromBase64 = (value: string): string => utf8Decoder.decode(fromBase64Bytes(value));\n\nconst HEX_LUT = (() => {\n const t = new Int8Array(256).fill(-1);\n for (let i = 0; i < 10; i++) t[48 + i] = i;\n for (let i = 0; i < 6; i++) {\n t[97 + i] = 10 + i;\n t[65 + i] = 10 + i;\n }\n return t;\n})();\n\nconst fromHex = (value: string): Uint8Array => {\n let start = 0;\n if (value.length >= 2 && value.charCodeAt(0) === 48 && (value.charCodeAt(1) | 32) === 120) {\n start = 2;\n }\n const digits = value.length - start;\n if (digits === 0 || digits % 2 !== 0) throw new TypeError('invalid hex length');\n const out = new Uint8Array(digits / 2);\n for (let i = 0; i < out.length; i++) {\n const byte = (HEX_LUT[value.charCodeAt(start + i * 2)] << 4) | HEX_LUT[value.charCodeAt(start + i * 2 + 1)];\n if (byte < 0) throw new TypeError('invalid hex digit');\n out[i] = byte;\n }\n return out;\n};\n\nconst MULTIPLIERS = {\n ms: 1,\n s: 1000,\n m: 60000,\n h: 3600000,\n d: 86400000,\n w: 604800000,\n};\n\nconst TIME_REGEX = /^(\\d*\\.?\\d*)(ms|s|m|h|d|w)?$/;\n\n/**\n * Creates a TypeError with the given message, typed as T for deferred error handling.\n *\n * Used by `as.*` conversion utilities to return errors that can be caught\n * during schema validation rather than throwing immediately.\n *\n * @template T - The expected return type (for type compatibility with conversion functions).\n * @param message - The error message.\n * @returns A TypeError instance typed as T.\n */\nexport const asError = <T>(message: string) => new (ErrCtor as unknown as new (m: string) => { message: string; [ERR]: true })(message) as unknown as T;\n\n/**\n * Type casting utilities for parsing strings into typed values.\n * Useful for environment variables, query parameters, and other string inputs.\n * Returns a TypeError for invalid values, enabling deferred validation with `ascertain()`.\n */\nexport const as = {\n /**\n * Attempts to convert a value to a string.\n *\n * @param value - The value to convert.\n * @returns The value as a string, or a TypeError if not a string.\n */\n string: (value: string | undefined): string => {\n return typeof value === 'string' ? value : asError(`Invalid value \"${value}\", expected a string`);\n },\n /**\n * Attempts to convert a value to a number.\n *\n * Supports integers, floats, scientific notation (1e10), and prefixed formats:\n * - Hexadecimal: `0x` or `0X` (e.g., `'0xFF'` → 255)\n * - Octal: `0o` or `0O` (e.g., `'0o77'` → 63)\n * - Binary: `0b` or `0B` (e.g., `'0b1010'` → 10)\n *\n * All formats support optional leading sign (`+` or `-`).\n *\n * @param value - The value to convert (expected to be a string representation of a number).\n * @returns The value as a number, or a TypeError if not a valid number.\n */\n number: (value: string | undefined): number => {\n if (typeof value !== 'string') {\n return asError(`Invalid value ${value}, expected a valid number`);\n }\n const start = value[0] === '-' || value[0] === '+' ? 1 : 0;\n const c0 = value.charCodeAt(start);\n const c1 = value.charCodeAt(start + 1) | 32;\n\n if (c0 === 48 && (c1 === 120 || c1 === 111 || c1 === 98)) {\n // '0' followed by 'x', 'o', or 'b'\n const result = Number(start ? value.slice(1) : value);\n if (Number.isNaN(result)) return asError(`Invalid value ${value}, expected a valid number`);\n return value[0] === '-' ? -result : result;\n }\n\n const result = value.trim() ? Number(value) : NaN;\n return Number.isNaN(result) ? asError(`Invalid value ${value}, expected a valid number`) : result;\n },\n /**\n * Attempts to convert a value to a Date object.\n *\n * @param value - The value to convert (expected to be a string representation of a date).\n * @returns The value as a Date object, or a TypeError if not a valid date.\n */\n date: (value: string | undefined): Date => {\n const result = Date.parse(value as string);\n const date = new Date(result);\n return Number.isNaN(date.valueOf()) ? asError(`Invalid value \"${value}\", expected a valid date format`) : date;\n },\n /**\n * Attempts to convert a value to a time duration in milliseconds.\n *\n * @param value - The value to convert (e.g., \"5s\" for 5 seconds).\n * @param conversionFactor - Optional factor to divide the result by (default is 1).\n * @returns The time duration in milliseconds, or a TypeError if the format is invalid.\n */\n time: (value: string | undefined, conversionFactor = 1): number => {\n if (!value) return asError(`Invalid value ${value}, expected a valid time format`);\n\n const matches = value.match(TIME_REGEX);\n if (!matches) return asError(`Invalid value ${value}, expected a valid time format`);\n\n const [, amount, unit = 'ms'] = matches;\n const multiplier = MULTIPLIERS[unit as keyof typeof MULTIPLIERS];\n const parsed = parseFloat(amount);\n\n if (!multiplier || Number.isNaN(parsed)) {\n return asError(`Invalid value ${value}, expected a valid time format`);\n }\n\n return Math.floor((parsed * multiplier) / conversionFactor);\n },\n /**\n * Attempts to convert a value to a boolean.\n *\n * @param value - The boolean like value to convert (e.g., \"true\", \"1\", \"enabled\").\n * @returns The value as a boolean, or a TypeError if it could not be converted to a boolean.\n */\n boolean: (value: string | undefined): boolean =>\n /^(0|1|true|false|enabled|disabled)$/i.test(value as string)\n ? /^(1|true|enabled)$/i.test(value as string)\n : asError(`Invalid value ${value}, expected a boolean like`),\n /**\n * Attempts to convert a string into an array of strings by splitting it using the given delimiter.\n *\n * @param value - The string value to attempt to split into an array.\n * @param delimiter - The character or string used to separate elements in the input string.\n * @returns An array of strings if the conversion is successful, or a TypeError if the value is not a string.\n */\n array: (value: string | undefined, delimiter: string): string[] => value?.split?.(delimiter) ?? asError(`Invalid value ${value}, expected an array`),\n /**\n * Attempts to parse a JSON string into a JavaScript object.\n *\n * @template T - The expected type of the parsed JSON object.\n * @param value - The JSON string to attempt to parse.\n * @returns The parsed JSON object if successful, or a TypeError if the value is not valid JSON.\n */\n json: <T = object>(value: string | undefined): T => {\n try {\n return JSON.parse(value as string);\n } catch {\n return asError(`Invalid value ${value}, expected a valid JSON string`);\n }\n },\n /**\n * Attempts to decode a base64-encoded string.\n *\n * @param value - The base64-encoded string to attempt to decode.\n * @returns The decoded string if successful, or a TypeError if the value is not valid base64.\n */\n base64: (value: string | undefined): string => {\n try {\n return fromBase64(value as string);\n } catch {\n return asError(`Invalid value ${value}, expected a valid base64 string`);\n }\n },\n\n data: (value: string | undefined, type: 'utf-8' | 'hex' | 'base64' = 'utf-8'): Uint8Array => {\n if (typeof value !== 'string') return asError(`Invalid value ${value}, expected a string`);\n try {\n if (type === 'hex') return fromHex(value);\n if (type === 'base64') return fromBase64Bytes(value);\n return utf8Encoder.encode(value);\n } catch {\n return asError(`Invalid value ${value}, expected a valid ${type} string`);\n }\n },\n};\n\nconst DATETIME_RE = /^\\d{4}-[01]\\d-[0-3]\\d[t\\s](?:[0-2]\\d:[0-5]\\d:[0-5]\\d|23:59:60)(?:\\.\\d+)?(?:z|[+-]\\d{2}(?::?\\d{2})?)$/i;\nconst TIME_FMT_RE = /^(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d|23:59:60)(?:\\.\\d+)?(?:z|[+-]\\d{2}(?::?\\d{2})?)$/i;\nconst DURATION_RE = /^P(?!$)(\\d+Y)?(\\d+M)?(\\d+W)?(\\d+D)?(T(?=\\d)(\\d+H)?(\\d+M)?(\\d+S)?)?$/;\nconst EMAIL_RE = /^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i;\nconst IDN_EMAIL_RE =\n /^[a-z0-9!#$%&'*+/=?^_`{|}~\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF-]+)*@(?:[a-z0-9\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF](?:[a-z0-9\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF-]*[a-z0-9\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])?\\.)+[a-z0-9\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF](?:[a-z0-9\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF-]*[a-z0-9\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])?$/i;\nconst HOSTNAME_RE = /^(?=.{1,253}\\.?$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*\\.?$/i;\nconst IDN_HOSTNAME_RE =\n /^(?=.{1,253}\\.?$)[a-z0-9\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF](?:[a-z0-9\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF-]{0,61}[a-z0-9\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])?(?:\\.[a-z0-9\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF](?:[a-z0-9\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF-]{0,61}[a-z0-9\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])?)*\\.?$/i;\nconst IPV4_RE = /^(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)$/;\nconst IPV6_RE =\n /^((([0-9a-f]{1,4}:){7}([0-9a-f]{1,4}|:))|(([0-9a-f]{1,4}:){6}(:[0-9a-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9a-f]{1,4}:){5}(((:[0-9a-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9a-f]{1,4}:){4}(((:[0-9a-f]{1,4}){1,3})|((:[0-9a-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9a-f]{1,4}:){3}(((:[0-9a-f]{1,4}){1,4})|((:[0-9a-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9a-f]{1,4}:){2}(((:[0-9a-f]{1,4}){1,5})|((:[0-9a-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9a-f]{1,4}:){1}(((:[0-9a-f]{1,4}){1,6})|((:[0-9a-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9a-f]{1,4}){1,7})|((:[0-9a-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?$/i;\nconst URI_RE =\n /^(?:[a-z][a-z0-9+\\-.]*:)(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i;\nconst isUriRef = (s: string): boolean => URI_RE.test(s) || /^[a-z0-9\\-._~:/?#\\[\\]@!$&'()*+,;=%]*$/i.test(s);\nconst IRI_RE =\n /^(?:[a-z][a-z0-9+\\-.]*:)(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]|%[0-9a-f]{2})*)*|\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\\-._~!$&'()*+,;=:@\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]|%[0-9a-f]{2})*)*)(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]|%[0-9a-f]{2})*)?$/i;\nconst isIriRef = (s: string): boolean => IRI_RE.test(s) || /^[a-z0-9\\-._~:/?#\\[\\]@!$&'()*+,;=\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF%]*$/i.test(s);\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\nconst URI_TEMPLATE_RE =\n /^(?:(?:[^\\x00-\\x20\"'<>%\\\\^`{|}]|%[0-9a-f]{2})|\\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\\*)?)*\\})*$/i;\nconst JSON_POINTER_RE = /^(?:\\/(?:[^~/]|~0|~1)*)*$/;\nconst REL_JSON_POINTER_RE = /^(?:0|[1-9][0-9]*)(?:#|(?:\\/(?:[^~/]|~0|~1)*)*)$/;\n\nconst DAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\nconst isValidDate = (s: string): boolean => {\n const m = /^\\d{4}-(\\d{2})-(\\d{2})$/.exec(s);\n if (!m) return false;\n const month = +m[1],\n day = +m[2];\n if (month < 1 || month > 12 || day < 1) return false;\n if (month === 2) {\n const y = +s.slice(0, 4);\n return day <= (y % 4 === 0 && (y % 100 !== 0 || y % 400 === 0) ? 29 : 28);\n }\n return day <= DAYS[month];\n};\n\nconst isValidRegex = (s: string): boolean => {\n try {\n new RegExp(s);\n return true;\n } catch {\n return false;\n }\n};\n\nconst regexFormat = (re: RegExp, name: string, message?: string): CheckShape =>\n new CheckCtor((v, ctx) => ({\n check: `!${ctx.ref(re)}.test(${v})`,\n message: message ? JSON.stringify(message) : `\\`must be a valid ${name}, got \\${${v}}\\``,\n }));\n\nconst fnFormat = (fn: (s: string) => boolean, name: string, message?: string): CheckShape =>\n new CheckCtor((v, ctx) => ({\n check: `!${ctx.ref(fn)}(${v})`,\n message: message ? JSON.stringify(message) : `\\`must be a valid ${name}, got \\${${v}}\\``,\n }));\n\n/**\n * String format validators for common patterns (RFC 3339 date-time, email, URI, UUID, etc.).\n * Each method returns a CheckShape that can be composed with `and()` for schema validation.\n */\nexport const format = {\n dateTime: (message?: string): CheckShape => regexFormat(DATETIME_RE, 'date-time', message),\n date: (message?: string): CheckShape => fnFormat(isValidDate, 'date', message),\n time: (message?: string): CheckShape => regexFormat(TIME_FMT_RE, 'time', message),\n duration: (message?: string): CheckShape => regexFormat(DURATION_RE, 'duration', message),\n email: (message?: string): CheckShape => regexFormat(EMAIL_RE, 'email', message),\n idnEmail: (message?: string): CheckShape => regexFormat(IDN_EMAIL_RE, 'idn-email', message),\n hostname: (message?: string): CheckShape => regexFormat(HOSTNAME_RE, 'hostname', message),\n idnHostname: (message?: string): CheckShape => regexFormat(IDN_HOSTNAME_RE, 'idn-hostname', message),\n ipv4: (message?: string): CheckShape => regexFormat(IPV4_RE, 'ipv4', message),\n ipv6: (message?: string): CheckShape => regexFormat(IPV6_RE, 'ipv6', message),\n uri: (message?: string): CheckShape => regexFormat(URI_RE, 'uri', message),\n uriReference: (message?: string): CheckShape => fnFormat(isUriRef, 'uri-reference', message),\n iri: (message?: string): CheckShape => regexFormat(IRI_RE, 'iri', message),\n iriReference: (message?: string): CheckShape => fnFormat(isIriRef, 'iri-reference', message),\n uuid: (message?: string): CheckShape => regexFormat(UUID_RE, 'uuid', message),\n uriTemplate: (message?: string): CheckShape => regexFormat(URI_TEMPLATE_RE, 'uri-template', message),\n jsonPointer: (message?: string): CheckShape => regexFormat(JSON_POINTER_RE, 'json-pointer', message),\n relativeJsonPointer: (message?: string): CheckShape => regexFormat(REL_JSON_POINTER_RE, 'relative-json-pointer', message),\n regex: (message?: string): CheckShape => fnFormat(isValidRegex, 'regex', message),\n};\n\n/**\n * A class representing the context for schema validation.\n *\n * Stores a registry of values encountered during validation and provides methods for managing it.\n * @internal\n */\nclass Context {\n public readonly registry: unknown[] = [];\n private readonly lookupMap: Map<unknown, number> = new Map();\n private varIndex = 0;\n public pure = false;\n\n register(value: unknown): number {\n const index = this.lookupMap.get(value);\n if (index !== undefined) {\n return index;\n }\n {\n const index = this.registry.push(value) - 1;\n this.lookupMap.set(value, index);\n return index;\n }\n }\n\n unique(prefix: string) {\n return `${prefix}$$${this.varIndex++}`;\n }\n}\n\ntype Mode =\n | { fast: true; onFail?: string; indexed?: boolean }\n | { fast: false; firstError: true; issues: string; path: PropertyKey[]; pathExpr: string; startVar?: string; dynamicParts?: string[] }\n | {\n fast: false;\n firstError: false;\n issues: string;\n path: PropertyKey[];\n pathExpr: string;\n startVar?: string;\n issuesReady?: boolean;\n dynamicParts?: string[];\n };\n\nconst isTagged = (schema: unknown): schema is Tagged<unknown> => (schema as Tagged<unknown>)?.[$op] !== undefined;\n\nconst buildDynamicPathExpr = (staticPath: PropertyKey[], dynamicParts: string[]): string =>\n `[${[...staticPath.map((k) => JSON.stringify(k)), ...dynamicParts].join(',')}]`;\n\nconst childMode = (mode: Exclude<Mode, { fast: true }>, key: PropertyKey | { dynamic: string }, ctx: Context): Mode => {\n const carryReady = !mode.firstError && mode.issuesReady;\n if (typeof key === 'object' && 'dynamic' in key) {\n const dynamicParts = [...(mode.dynamicParts ?? []), key.dynamic];\n const m: Mode = {\n fast: false,\n firstError: mode.firstError,\n issues: mode.issues,\n path: mode.path,\n pathExpr: buildDynamicPathExpr(mode.path, dynamicParts),\n dynamicParts,\n };\n if (carryReady) (m as { issuesReady: boolean }).issuesReady = true;\n return m;\n }\n if (mode.dynamicParts) {\n const dynamicParts = [...mode.dynamicParts, JSON.stringify(key)];\n const m: Mode = {\n fast: false,\n firstError: mode.firstError,\n issues: mode.issues,\n path: mode.path,\n pathExpr: buildDynamicPathExpr(mode.path, dynamicParts),\n dynamicParts,\n };\n if (carryReady) (m as { issuesReady: boolean }).issuesReady = true;\n return m;\n }\n const newPath = [...mode.path, key];\n const pathExpr = `reg[${ctx.register(Object.freeze(newPath))}]`;\n const m: Mode = { fast: false, firstError: mode.firstError, issues: mode.issues, path: newPath, pathExpr };\n if (carryReady) (m as { issuesReady: boolean }).issuesReady = true;\n return m;\n};\n\nconst toLiteral = (value: unknown): string => (typeof value === 'bigint' ? `${value}n` : JSON.stringify(value));\n\nconst collapsibleTypeOf = (s: unknown): string | null =>\n s === String\n ? 'string'\n : s === Number\n ? 'number'\n : s === Boolean\n ? 'boolean'\n : s === BigInt\n ? 'bigint'\n : s === Symbol\n ? 'symbol'\n : typeof s === 'function' && (s as { name?: string })?.name === 'Function'\n ? 'function'\n : null;\n\nconst buildCollapsedOr = (schemas: unknown[], v: string): string => {\n let hasNull = false;\n let hasUndefined = false;\n const groups = new Map<string, { ctor: boolean; literals: unknown[] }>();\n for (const s of schemas) {\n if (s === null) {\n hasNull = true;\n continue;\n }\n if (s === undefined) {\n hasUndefined = true;\n continue;\n }\n const ct = collapsibleTypeOf(s);\n if (ct) {\n let g = groups.get(ct);\n if (!g) {\n g = { ctor: false, literals: [] };\n groups.set(ct, g);\n }\n g.ctor = true;\n continue;\n }\n const t = typeof s;\n let g = groups.get(t);\n if (!g) {\n g = { ctor: false, literals: [] };\n groups.set(t, g);\n }\n g.literals.push(s);\n }\n const clauses: string[] = [];\n if (hasNull) clauses.push(`${v} === null`);\n if (hasUndefined) clauses.push(`${v} === undefined`);\n for (const [type, { ctor, literals }] of groups) {\n if (ctor) {\n clauses.push(type === 'number' ? `(typeof ${v} === 'number' && ${v} === ${v})` : `typeof ${v} === '${type}'`);\n } else if (literals.length === 1) {\n clauses.push(`${v} === ${toLiteral(literals[0])}`);\n } else {\n clauses.push(`(typeof ${v} === '${type}' && (${literals.map((l) => `${v} === ${toLiteral(l)}`).join(' || ')}))`);\n }\n }\n return clauses.join(' || ');\n};\n\nconst buildExpectedDesc = (schemas: unknown[]): string => {\n const parts: string[] = [];\n for (const s of schemas) {\n if (s === null) parts.push('null');\n else if (s === undefined) parts.push('undefined');\n else if (collapsibleTypeOf(s) !== null) parts.push((s as { name: string }).name);\n else parts.push(toLiteral(s) as string);\n }\n return parts.join(', ');\n};\n\nconst isCollapsible = (s: unknown): boolean =>\n s === null || s === undefined || (typeof s !== 'object' && typeof s !== 'function' && typeof s !== 'symbol') || collapsibleTypeOf(s) !== null;\n\nconst codeGen = <T>(schema: Schema<T>, context: Context, valuePath: string, mode: Mode): string => {\n const emit = mode.fast\n ? null\n : mode.firstError\n ? (msg: string) => `${mode.issues} = [{ message: ${msg}, path: ${mode.pathExpr} }]; return ${mode.issues};`\n : !mode.firstError && mode.issuesReady\n ? (msg: string) => `${mode.issues}.push({ message: ${msg}, path: ${mode.pathExpr} });`\n : (msg: string) => `(${mode.issues} || (${mode.issues} = [])).push({ message: ${msg}, path: ${mode.pathExpr} });`;\n const fail = mode.fast ? (mode.onFail ?? 'return false;') : '';\n const errChk = (v: string) => (context.pure ? '' : ` || (typeof ${v} === 'object' && ${v} !== null && ${v}[err] === true)`);\n const errBranch = (v: string) =>\n context.pure ? '' : `else if (typeof ${v} === 'object' && ${v} !== null && ${v}[err] === true) { ${emit!(`\\`\\${${v}.message}\\``)} }`;\n\n if (isTagged(schema)) {\n const tag = schema[$op];\n if (tag === AND) {\n const valueAlias = context.unique('v');\n const code = schema.schemas.map((s) => codeGen(s, context, valueAlias, mode)).join('\\n');\n return `const ${valueAlias} = ${valuePath};\\n${code}`;\n } else if (tag === OR) {\n const valueAlias = context.unique('v');\n const foundValid = context.unique('valid');\n if (mode.fast) {\n const collapsible: unknown[] = [];\n const complex: Schema<T>[] = [];\n for (const s of schema.schemas) {\n if (isCollapsible(s)) collapsible.push(s);\n else complex.push(s as Schema<T>);\n }\n if (collapsible.length > 0 && complex.length === 0) {\n return `const ${valueAlias} = ${valuePath};\\nif (!(${buildCollapsedOr(collapsible, valueAlias)})) { ${fail} }`;\n }\n if (collapsible.length > 0) {\n const condition = buildCollapsedOr(collapsible, valueAlias);\n const branches = complex.map((s) => {\n const branchValid = context.unique('valid');\n const branchCode = codeGen(s, context, valueAlias, { ...mode, onFail: `${branchValid} = false;` });\n return `if (!${foundValid}) { let ${branchValid} = true; ${branchCode} if (${branchValid}) { ${foundValid} = true; } }`;\n });\n return `const ${valueAlias} = ${valuePath};\\nlet ${foundValid} = ${condition};\\n${branches.join('\\n')}\\nif (!${foundValid}) { ${fail} }`;\n }\n const branches = schema.schemas.map((s) => {\n const branchValid = context.unique('valid');\n const branchCode = codeGen(s, context, valueAlias, { ...mode, onFail: `${branchValid} = false;` });\n return `if (!${foundValid}) { let ${branchValid} = true; ${branchCode} if (${branchValid}) { ${foundValid} = true; } }`;\n });\n return `const ${valueAlias} = ${valuePath};\\nlet ${foundValid} = false;\\n${branches.join('\\n')}\\nif (!${foundValid}) { ${fail} }`;\n } else if (mode.firstError) {\n if (schema.schemas.every(isCollapsible)) {\n const condition = buildCollapsedOr(schema.schemas, valueAlias);\n const expected = buildExpectedDesc(schema.schemas);\n return `const ${valueAlias} = ${valuePath};\\nif (!(${condition})) { ${mode.issues} = [{ message: \\`Invalid value \\${${valueAlias}}, expected one of: ${expected}\\`, path: ${mode.pathExpr} }]; return ${mode.issues}; }`;\n }\n const firstBranchIssues = context.unique('iss');\n const branches = schema.schemas.map((s, idx) => {\n const branchIssues = context.unique('iss');\n const branchCode = codeGen(s, context, valueAlias, {\n fast: false,\n firstError: true,\n issues: branchIssues,\n path: mode.path,\n pathExpr: mode.pathExpr,\n }).replace(new RegExp(`; return ${branchIssues};`, 'g'), ';');\n if (idx === 0) {\n return `if (!${foundValid}) { let ${branchIssues}; ${branchCode} if (!${branchIssues}) { ${foundValid} = true; } else { ${firstBranchIssues} = ${branchIssues}; } }`;\n }\n return `if (!${foundValid}) { let ${branchIssues}; ${branchCode} if (!${branchIssues}) { ${foundValid} = true; } }`;\n });\n return `const ${valueAlias} = ${valuePath};\\nlet ${firstBranchIssues};\\nlet ${foundValid} = false;\\n${branches.join('\\n')}\\nif (!${foundValid}) { return ${firstBranchIssues}; }`;\n } else {\n if (schema.schemas.every(isCollapsible)) {\n const condition = buildCollapsedOr(schema.schemas, valueAlias);\n const expected = buildExpectedDesc(schema.schemas);\n const push = mode.issuesReady\n ? `${mode.issues}.push({ message: \\`Invalid value \\${${valueAlias}}, expected one of: ${expected}\\`, path: ${mode.pathExpr} });`\n : `(${mode.issues} || (${mode.issues} = [])).push({ message: \\`Invalid value \\${${valueAlias}}, expected one of: ${expected}\\`, path: ${mode.pathExpr} });`;\n return `const ${valueAlias} = ${valuePath};\\nif (!(${condition})) { ${push} }`;\n }\n const localIssues = context.unique('iss');\n const branches = schema.schemas.map((s) => {\n const branchIssues = context.unique('iss');\n const branchCode = codeGen(s, context, valueAlias, {\n fast: false,\n firstError: false,\n issues: branchIssues,\n path: mode.path,\n pathExpr: mode.pathExpr,\n });\n return `if (!${foundValid}) { let ${branchIssues}; ${branchCode} if (!${branchIssues}) { ${foundValid} = true; } else { ${localIssues}.push(...${branchIssues}); } }`;\n });\n const pushExpr =\n !mode.fast && !mode.firstError && mode.issuesReady\n ? `${mode.issues}.push(...${localIssues})`\n : `(${mode.issues} || (${mode.issues} = [])).push(...${localIssues})`;\n return `const ${valueAlias} = ${valuePath};\\nconst ${localIssues} = [];\\nlet ${foundValid} = false;\\n${branches.join('\\n')}\\nif (!${foundValid}) { ${pushExpr}; }`;\n }\n } else if (tag === OPTIONAL) {\n const valueAlias = context.unique('v');\n const inner = (schema as OptionalShape<T>).schemas[0];\n if (!mode.fast && typeof inner === 'function') {\n const iname = (inner as { name?: string })?.name;\n const is = inner as unknown;\n const pt =\n is === String ? 'string' : is === Number ? 'number' : is === Boolean ? 'boolean' : is === BigInt ? 'bigint' : is === Symbol ? 'symbol' : null;\n if (pt) {\n const typeMsgs = Object.fromEntries(\n ['string', 'number', 'boolean', 'bigint', 'symbol', 'undefined', 'object', 'function'].map((t) => [t, `Invalid type ${t}, expected type ${iname}`]),\n );\n const typeMsgIdx = context.register(typeMsgs);\n const lines = [`const ${valueAlias} = ${valuePath};`, `if (${valueAlias} !== undefined && ${valueAlias} !== null) {`];\n lines.push(`if (typeof ${valueAlias} !== '${pt}') { ${emit!(`reg[${typeMsgIdx}][typeof ${valueAlias}]`)} }`);\n if (pt === 'number') lines.push(`else if (${valueAlias} !== ${valueAlias}) { ${emit!(`\"Invalid value NaN, expected a valid ${iname}\"`)} }`);\n lines.push(`}`);\n return lines.join('\\n');\n }\n }\n return `const ${valueAlias} = ${valuePath};\\nif (${valueAlias} !== undefined && ${valueAlias} !== null) { ${codeGen(inner, context, valueAlias, mode)} }`;\n } else if (tag === TUPLE) {\n const valueAlias = context.unique('v');\n if (mode.fast) {\n return `const ${valueAlias} = ${valuePath};\\nif (${valueAlias} === null || typeof ${valueAlias} !== 'object' || !Array.isArray(${valueAlias}) || ${valueAlias}.length !== ${schema.schemas.length}) { ${fail} }\\n${schema.schemas.map((s, idx) => codeGen(s, context, `${valueAlias}[${idx}]`, mode)).join('\\n')}`;\n } else {\n return [\n `const ${valueAlias} = ${valuePath};`,\n `if (${valueAlias} === null || ${valueAlias} === undefined) { ${emit!(`\\`Invalid value \\${${valueAlias}}, expected non-nullable\\``)} }`,\n `else if (typeof ${valueAlias} !== 'object') { ${emit!(`\\`Invalid type \\${typeof ${valueAlias}}, expected an instance of Array\\``)} }`,\n `else if (!Array.isArray(${valueAlias})) { ${emit!(`\\`Invalid instance of \\${${valueAlias}.constructor?.name}, expected an instance of Array\\``)} }`,\n `else if (${valueAlias}.length !== ${schema.schemas.length}) { ${emit!(`\\`Invalid tuple length \\${${valueAlias}.length}, expected ${schema.schemas.length}\\``)} }`,\n `else { ${schema.schemas.map((s, idx) => codeGen(s, context, `${valueAlias}[${idx}]`, childMode(mode, idx, context))).join('\\n')} }`,\n ].join('\\n');\n }\n } else if (tag === CHECK) {\n const valueAlias = context.unique('v');\n const ref = (v: unknown) => `reg[${context.register(v)}]`;\n const { check: cond, message } = (schema as CheckShape).compile(valueAlias, { ref });\n if (mode.fast) {\n return `const ${valueAlias} = ${valuePath};\\nif (${cond}) { ${fail} }`;\n }\n return `const ${valueAlias} = ${valuePath};\\nif (${cond}) { ${emit!(message)} }`;\n } else {\n const { key, schemas } = schema as DiscriminatedShape<T>;\n const valueAlias = context.unique('v');\n const discriminantAlias = context.unique('d');\n const keyStr = JSON.stringify(key);\n\n const variants: { value: unknown; schema: Schema<T> }[] = [];\n for (const s of schemas) {\n if (typeof s !== 'object' || s === null || !(key in s)) {\n throw new TypeError(`discriminated: each schema must have the discriminant key \"${key}\"`);\n }\n const discriminantValue = (s as Record<string, unknown>)[key];\n if (typeof discriminantValue !== 'string' && typeof discriminantValue !== 'number' && typeof discriminantValue !== 'boolean') {\n throw new TypeError(`discriminated: discriminant value must be a string, number, or boolean literal`);\n }\n variants.push({ value: discriminantValue, schema: s });\n }\n\n const genVariantProps = (s: Schema<T>, variantMode: Mode) => {\n const obj = s as Record<string, unknown>;\n return Object.entries(obj)\n .filter(([k]) => k !== key)\n .map(([k, ps]) =>\n codeGen(ps as Schema<T>, context, `${valueAlias}[${JSON.stringify(k)}]`, variantMode.fast ? variantMode : childMode(variantMode, k, context)),\n )\n .join('\\n');\n };\n\n if (mode.fast) {\n const branches = variants.map(({ value, schema: s }) => {\n return `if (${discriminantAlias} === ${JSON.stringify(value)}) { ${genVariantProps(s, mode)} }`;\n });\n return [\n `const ${valueAlias} = ${valuePath};`,\n `if (${valueAlias} === null || ${valueAlias} === undefined || typeof ${valueAlias} !== 'object'${errChk(valueAlias)}) { ${fail} }`,\n `const ${discriminantAlias} = ${valueAlias}[${keyStr}];`,\n branches.join(' else ') + ` else { ${fail} }`,\n ].join('\\n');\n } else {\n const validValues = variants.map((v) => JSON.stringify(v.value)).join(', ');\n const branches = variants.map(({ value, schema: s }) => {\n return `if (${discriminantAlias} === ${JSON.stringify(value)}) { ${genVariantProps(s, mode)} }`;\n });\n return [\n `const ${valueAlias} = ${valuePath};`,\n `if (${valueAlias} === null || ${valueAlias} === undefined) { ${emit!(`\\`Invalid value \\${${valueAlias}}, expected non-nullable\\``)} }`,\n `else if (typeof ${valueAlias} !== 'object') { ${emit!(`\\`Invalid type \\${typeof ${valueAlias}}, expected an object\\``)} }`,\n `${errBranch(valueAlias)}`,\n `else {`,\n ` const ${discriminantAlias} = ${valueAlias}[${keyStr}];`,\n ` ${branches.join(' else ')} else { ${emit!(`\"Invalid discriminant value \" + String(${discriminantAlias}) + \", expected one of: ${validValues.replace(/\"/g, \"'\")}\"`)} }`,\n `}`,\n ].join('\\n');\n }\n }\n }\n\n if (typeof schema === 'function') {\n const valueAlias = context.unique('v');\n const name = (schema as { name?: string })?.name;\n const s = schema as unknown;\n const primitiveType =\n s === String ? 'string' : s === Number ? 'number' : s === Boolean ? 'boolean' : s === BigInt ? 'bigint' : s === Symbol ? 'symbol' : null;\n\n if (mode.fast) {\n if (primitiveType) {\n const checks = [`typeof ${valueAlias} !== '${primitiveType}'`];\n if (primitiveType === 'number') checks.push(`${valueAlias} !== ${valueAlias}`);\n return `const ${valueAlias} = ${valuePath};\\nif (${checks.join(' || ')}) { ${fail} }`;\n } else if (name === 'Function') {\n return `const ${valueAlias} = ${valuePath};\\nif (typeof ${valueAlias} !== 'function') { ${fail} }`;\n } else {\n const isError = (schema as unknown) === Error || schema?.prototype instanceof Error;\n const index = context.register(schema);\n const registryAlias = context.unique('r');\n return `const ${valueAlias} = ${valuePath};\\nconst ${registryAlias} = reg[${index}];\\nif (${valueAlias} === null || ${valueAlias} === undefined${isError || context.pure ? '' : ` || (typeof ${valueAlias} === 'object' && ${valueAlias}[err] === true)`} || (typeof ${valueAlias} === 'object' && !(${valueAlias} instanceof ${registryAlias})) || (typeof ${valueAlias} !== 'object' && ${valueAlias}?.constructor !== ${registryAlias}) || Number.isNaN(${valueAlias}?.valueOf?.())) { ${fail} }`;\n }\n } else {\n const code: string[] = [`const ${valueAlias} = ${valuePath};`];\n if (primitiveType) {\n const typeMsgs = Object.fromEntries(\n ['string', 'number', 'boolean', 'bigint', 'symbol', 'undefined', 'object', 'function'].map((t) => [t, `Invalid type ${t}, expected type ${name}`]),\n );\n const typeMsgIdx = context.register(typeMsgs);\n code.push(\n `if (${valueAlias} === null || ${valueAlias} === undefined) { ${emit!(`${valueAlias} === null ? \"Invalid value null, expected non-nullable\" : \"Invalid value undefined, expected non-nullable\"`)} }`,\n );\n code.push(`${errBranch(valueAlias)}`);\n code.push(`else if (typeof ${valueAlias} !== '${primitiveType}') { ${emit!(`reg[${typeMsgIdx}][typeof ${valueAlias}]`)} }`);\n if (primitiveType === 'number') code.push(`else if (${valueAlias} !== ${valueAlias}) { ${emit!(`\"Invalid value NaN, expected a valid ${name}\"`)} }`);\n } else if (name === 'Function') {\n code.push(`if (${valueAlias} === null || ${valueAlias} === undefined) { ${emit!(`\\`Invalid value \\${${valueAlias}}, expected non-nullable\\``)} }`);\n code.push(`${errBranch(valueAlias)}`);\n code.push(`else if (typeof ${valueAlias} !== 'function') { ${emit!(`\\`Invalid type \\${typeof ${valueAlias}}, expected type Function\\``)} }`);\n } else {\n const isError = (schema as unknown) === Error || schema?.prototype instanceof Error;\n const index = context.register(schema);\n const registryAlias = context.unique('r');\n code.push(`const ${registryAlias} = reg[${index}];`);\n code.push(`if (${valueAlias} === null || ${valueAlias} === undefined) { ${emit!(`\\`Invalid value \\${${valueAlias}}, expected non-nullable\\``)} }`);\n if (!isError) code.push(`${errBranch(valueAlias)}`);\n code.push(\n `el