ascertain
Version:
0-Deps, simple, fast, for browser and node js object schema validator
1 lines • 36.1 kB
Source Map (JSON)
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Abstract base class for schema operators.\n *\n * Provides a common constructor that enforces having at least one schema.\n *\n * @template T - The type of data the operator validates.\n * @abstract\n * @internal\n */\nabstract class Operator<T> {\n constructor(public readonly schemas: Schema<T>[]) {\n if (schemas.length === 0) {\n throw new TypeError(`Operation schema ${this.constructor.name} must have at least one element`);\n }\n }\n}\n\n// https://standardschema.dev/\n\n/**\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\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\nclass Or<T> extends Operator<T> {}\n/**\n * Operator for validating data against any of the provided schemas (logical OR).\n *\n * Creates a schema that accepts data matching any one of the provided schemas.\n * This is useful for creating union types or alternative validation paths.\n *\n * @template T - The type of data the operator validates.\n * @param schemas - Multiple schemas where at least one must match the data.\n * @returns A schema that validates data against any of the provided schemas.\n *\n * @example\n * ```typescript\n * import { or, ascertain } from 'ascertain';\n *\n * // Create a schema that accepts either a string or number\n * const stringOrNumber = or(String, Number);\n *\n * ascertain(stringOrNumber, \"hello\", \"value\"); // ✓ Valid\n * ascertain(stringOrNumber, 42, \"value\"); // ✓ Valid\n * ascertain(stringOrNumber, true, \"value\"); // ✗ Throws error\n *\n * // Union of literal values\n * const statusSchema = or('pending', 'completed', 'failed');\n * ascertain(statusSchema, 'pending', \"status\"); // ✓ Valid\n *\n * // Complex schema combinations\n * const userIdSchema = or(Number, { id: Number, temp: Boolean });\n * ascertain(userIdSchema, 123, \"userId\"); // ✓ Valid\n * ascertain(userIdSchema, { id: 456, temp: true }, \"userId\"); // ✓ Valid\n * ```\n */\nexport const or = <T>(...schemas: Schema<T>[]) => new Or(schemas);\n\nclass And<T> extends Operator<T> {}\n/**\n * Operator for validating data against all provided schemas (logical AND).\n *\n * Creates a schema that requires data to match every one of the provided schemas.\n * This is useful for combining multiple validation requirements or adding constraints.\n *\n * @template T - The type of data the operator validates.\n * @param schemas - Multiple schemas that all must match the data.\n * @returns A schema that validates data against all of the provided schemas.\n *\n * @example\n * ```typescript\n * import { and, ascertain } from 'ascertain';\n *\n * // Combine object schema with additional constraints\n * const userSchema = and(\n * { name: String, age: Number },\n * { age: Number } // Additional constraint\n * );\n *\n * ascertain(userSchema, { name: \"John\", age: 25 }, \"user\"); // ✓ Valid\n *\n * // Ensure an object is both a Date and has specific methods\n * const validDateSchema = and(Date, { toISOString: Function });\n * ascertain(validDateSchema, new Date(), \"date\"); // ✓ Valid\n *\n * // Multiple validation layers\n * const positiveNumberSchema = and(Number, (n: number) => n > 0);\n * ascertain(positiveNumberSchema, 42, \"count\"); // ✓ Valid\n * ascertain(positiveNumberSchema, -5, \"count\"); // ✗ Throws error\n * ```\n */\nexport const and = <T>(...schemas: Schema<T>[]) => new And(schemas);\n\nclass Optional<T> extends Operator<T> {\n constructor(schema: Schema<T>) {\n super([schema]);\n }\n}\n/**\n * Operator for making a schema optional (nullable).\n *\n * Creates a schema that accepts the provided schema or null/undefined values.\n * This is useful for optional object properties or nullable fields.\n *\n * @template T - The type of data the operator validates.\n * @param schema - The schema to make optional.\n * @returns A schema that validates data against the provided schema or accepts null/undefined.\n *\n * @example\n * ```typescript\n * import { optional, ascertain } from 'ascertain';\n *\n * // Optional string field\n * const userSchema = {\n * name: String,\n * nickname: optional(String),\n * age: Number\n * };\n *\n * // All of these are valid\n * ascertain(userSchema, {\n * name: \"John\",\n * nickname: \"Johnny\",\n * age: 30\n * }, \"user\"); // ✓ Valid\n *\n * ascertain(userSchema, {\n * name: \"Jane\",\n * nickname: null,\n * age: 25\n * }, \"user\"); // ✓ Valid\n *\n * ascertain(userSchema, {\n * name: \"Bob\",\n * age: 35\n * // nickname is undefined\n * }, \"user\"); // ✓ Valid\n *\n * // Optional complex objects\n * const profileSchema = {\n * id: Number,\n * settings: optional({\n * theme: String,\n * notifications: Boolean\n * })\n * };\n * ```\n */\nexport const optional = <T>(schema: Schema<T>) => new Optional(schema);\n\nclass Tuple<T> extends Operator<T> {}\n/**\n * Operator for validating data against a fixed-length tuple of schemas.\n *\n * Creates a schema that validates arrays with a specific length and type for each position.\n * This is useful for coordinate pairs, RGB values, or any fixed-structure data.\n *\n * @template T - The type of data the operator validates (a tuple of types).\n * @param schemas - Schemas for each position in the tuple, in order.\n * @returns A schema that validates data as a tuple with the specified structure.\n *\n * @example\n * ```typescript\n * import { tuple, ascertain } from 'ascertain';\n *\n * // 2D coordinate tuple\n * const pointSchema = tuple(Number, Number);\n * ascertain(pointSchema, [10, 20], \"point\"); // ✓ Valid\n * ascertain(pointSchema, [1.5, 2.7], \"point\"); // ✓ Valid\n * ascertain(pointSchema, [10], \"point\"); // ✗ Throws error (too short)\n * ascertain(pointSchema, [10, 20, 30], \"point\"); // ✗ Throws error (too long)\n *\n * // RGB color tuple\n * const colorSchema = tuple(Number, Number, Number);\n * ascertain(colorSchema, [255, 128, 0], \"color\"); // ✓ Valid\n *\n * // Mixed type tuple\n * const userInfoSchema = tuple(String, Number, Boolean);\n * ascertain(userInfoSchema, [\"Alice\", 25, true], \"userInfo\"); // ✓ Valid\n *\n * // Nested tuple\n * const lineSchema = tuple(\n * tuple(Number, Number), // start point\n * tuple(Number, Number) // end point\n * );\n * ascertain(lineSchema, [[0, 0], [10, 10]], \"line\"); // ✓ Valid\n * ```\n */\nexport const tuple = <T>(...schemas: Schema<T>[]) => new Tuple(schemas);\n\nexport const fromBase64 = typeof Buffer === 'undefined' ? (value: string) => atob(value) : (value: string) => Buffer.from(value, 'base64').toString('utf-8');\n\nconst MULTIPLIERS = {\n ms: 1,\n s: 1000,\n m: 60000,\n h: 3600000,\n d: 86400000,\n w: 604800000,\n};\n\nexport const asError = <T>(message: string) => new TypeError(message) as unknown as T;\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 * @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 const result = parseFloat(value as string);\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 const matches = value?.match(/^(\\d*\\.?\\d*)(ms|s|m|h|d|w)?$/);\n if (matches) {\n const [, amount, unit = 'ms'] = matches;\n return parseInt(`${(parseFloat(amount) * MULTIPLIERS[unit as keyof typeof MULTIPLIERS]) / conversionFactor}`);\n }\n return asError(`Invalid value ${value}, expected a valid time format`);\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\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 varIndex = 0;\n\n register(value: unknown): number {\n if (!this.registry.includes(value)) {\n this.registry.push(value);\n }\n return this.registry.indexOf(value);\n }\n\n unique(prefix: string) {\n return `${prefix}$$${this.varIndex++}`;\n }\n}\n\nconst codeGenCollectErrors = (errorsAlias: string, code: string, extra: string = '') => `try {${code}} catch (e) {${errorsAlias}.push(e.message);${extra}}`;\nconst codeGenExpectNoErrors = (errorsAlias: string) => `if (${errorsAlias}.length !== 0) { throw new TypeError(${errorsAlias}.join('\\\\n')); }`;\nconst codeGenExpectNonError = (valueAlias: string, path: string) =>\n `if (${valueAlias} instanceof Error) { throw new TypeError(\\`\\${${valueAlias}.message} for path \"${path}\".\\`); }`;\nconst codeGenExpectNonNullable = (valueAlias: string, path: string) =>\n `if (${valueAlias} === null || ${valueAlias} === undefined) { throw new TypeError(\\`Invalid value \\${${valueAlias}} for path \"${path}\", expected non-nullable.\\`); }`;\nconst codeGenExpectObject = (valueAlias: string, path: string, instanceOf: string) =>\n `if (typeof ${valueAlias} !== 'object') { throw new TypeError(\\`Invalid type \\${typeof ${valueAlias}} for path \"${path}\", expected an instance of ${instanceOf}\\`); }`;\nconst codeGenExpectArray = (valueAlias: string, path: string) =>\n `if (!Array.isArray(${valueAlias})) { throw new TypeError(\\`Invalid instance of \\${${valueAlias}.constructor?.name} for path \"${path}\", expected an instance of Array.\\`); }`;\n\nconst codeGen = <T>(schema: Schema<T>, context: Context, valuePath: string, path: string): string => {\n if (schema instanceof And) {\n const valueAlias = context.unique('v');\n const errorsAlias = context.unique('err');\n const code = schema.schemas.map((s) => `try { ${codeGen(s, context, valueAlias, path)} } catch (e) { ${errorsAlias}.push(e.message); }`).join('\\n');\n return `// And\n const ${errorsAlias} = [];\n const ${valueAlias} = ${valuePath};\n ${code}\n ${codeGenExpectNoErrors(errorsAlias)}\n`;\n } else if (schema instanceof Or) {\n const valueAlias = context.unique('v');\n const errorsAlias = context.unique('err');\n const code = schema.schemas\n .map((s) => codeGen(s, context, valueAlias, path))\n .reduceRight((result, code) => codeGenCollectErrors(errorsAlias, code, result), codeGenExpectNoErrors(errorsAlias));\n return `// Or\nconst ${errorsAlias} = [];\nconst ${valueAlias} = ${valuePath};\n${code}\n `;\n } else if (schema instanceof Optional) {\n const valueAlias = context.unique('v');\n return `// Optional\nconst ${valueAlias} = ${valuePath};\nif (${valueAlias} !== undefined && ${valueAlias} !== null) { ${codeGen(schema.schemas[0], context, valueAlias, path)} }\n`;\n } else if (schema instanceof Tuple) {\n const valueAlias = context.unique('v');\n const errorsAlias = context.unique('err');\n const code: string[] = [\n '// Tuple',\n `const ${valueAlias} = ${valuePath};`,\n `const ${errorsAlias} = [];`,\n codeGenExpectNonNullable(valueAlias, path),\n codeGenExpectObject(valueAlias, path, 'Array'),\n codeGenExpectArray(valueAlias, path),\n `if (${valueAlias}.length > ${schema.schemas.length}) { throw new TypeError(\\`Invalid tuple length \\${${valueAlias}.length} for path \"${path}\", expected ${schema.schemas.length}.\\`); }`,\n ...schema.schemas.map((s, idx) => codeGenCollectErrors(errorsAlias, codeGen(s, context, `${valueAlias}[${idx}]`, `${path}[${idx}]`))),\n codeGenExpectNoErrors(errorsAlias),\n ];\n return code.join('\\n');\n } else if (typeof schema === 'function') {\n const index = context.register(schema);\n const valueAlias = context.unique('v');\n const registryAlias = context.unique('r');\n const code: string[] = [\n `const ${valueAlias} = ${valuePath};`,\n `const ${registryAlias} = ctx.registry[${index}];`,\n codeGenExpectNonNullable(valueAlias, path),\n ];\n if ((schema as unknown) !== Error && !(schema?.prototype instanceof Error)) {\n code.push(codeGenExpectNonError(valueAlias, path));\n }\n\n code.push(\n `if (typeof ${valueAlias} === 'object' && !(${valueAlias} instanceof ${registryAlias})) { throw new TypeError(\\`Invalid instance of \\${${valueAlias}?.constructor?.name} for path \"${path}\", expected an instance of ${schema?.name}\\`); }`,\n `if (typeof ${valueAlias} !== 'object' && ${valueAlias}?.constructor !== ${registryAlias}) { throw new TypeError(\\`Invalid type \\${${valueAlias}?.constructor?.name} for path \"${path}\", expected type ${schema?.name}\\`); }`,\n `if (Number.isNaN(${valueAlias}?.valueOf?.())) { throw new TypeError(\\`Invalid value \\${${valueAlias}} for path \"${path}\", expected a valid ${schema?.name}\\`); }`,\n );\n return code.join('\\n');\n } else if (Array.isArray(schema)) {\n const valueAlias = context.unique('v');\n const code: string[] = [\n `const ${valueAlias} = ${valuePath};`,\n codeGenExpectNonNullable(valueAlias, path),\n codeGenExpectNonError(valueAlias, path),\n codeGenExpectObject(valueAlias, path, 'Array'),\n codeGenExpectArray(valueAlias, path),\n ];\n if (schema.length > 0) {\n const value = context.unique('val');\n const key = context.unique('key');\n const errorsAlias = context.unique('err');\n code.push(`const ${errorsAlias} = [];`);\n code.push(\n ...schema.map(\n (s) => `${valueAlias}.forEach((${value},${key}) => { ${codeGenCollectErrors(errorsAlias, codeGen(s, context, value, `${path}[\\${${key}}]`))} });`,\n ),\n );\n\n code.push(codeGenExpectNoErrors(errorsAlias));\n }\n return code.join('\\n');\n } else if (typeof schema === 'object' && schema !== null) {\n if (schema instanceof RegExp) {\n const valueAlias = context.unique('v');\n return `\nconst ${valueAlias} = ${valuePath};\n${codeGenExpectNonNullable(valueAlias, path)}\n${codeGenExpectNonError(valueAlias, path)}\nif (!${schema.toString()}.test('' + ${valueAlias})) { throw new TypeError(\\`Invalid value \\${${valueAlias}} for path \"${path}\", expected to match ${schema.toString()}\\`); }\n`;\n } else {\n const valueAlias = context.unique('v');\n const code: string[] = [\n `const ${valueAlias} = ${valuePath};`,\n codeGenExpectNonNullable(valueAlias, path),\n codeGenExpectObject(valueAlias, path, 'Object'),\n codeGenExpectNonError(valueAlias, path),\n ];\n if ($keys in schema) {\n const keysAlias = context.unique('k');\n const errorsAlias = context.unique('err');\n const kAlias = context.unique('k');\n code.push(`\nconst ${keysAlias} = Object.keys(${valueAlias});\nconst ${errorsAlias} = [];\n${keysAlias}.forEach(${kAlias} => { ${codeGenCollectErrors(errorsAlias, codeGen(schema[$keys], context, kAlias, `${path}[\\${${kAlias}}]`))} });\n${codeGenExpectNoErrors(errorsAlias)}\n`);\n }\n if ($values in schema) {\n const vAlias = context.unique('val');\n const kAlias = context.unique('k');\n const entriesAlias = context.unique('en');\n const errorsAlias = context.unique('err');\n code.push(`\nconst ${entriesAlias} = Object.entries(${valueAlias});\nconst ${errorsAlias} = [];\n${entriesAlias}.forEach(([${kAlias},${vAlias}]) => { ${codeGenCollectErrors(errorsAlias, codeGen(schema[$values], context, vAlias, `${path}[\\${${kAlias}}]`))} });\n${codeGenExpectNoErrors(errorsAlias)}\n`);\n }\n if ($strict in schema && schema[$strict]) {\n const keysAlias = context.unique('k');\n const kAlias = context.unique('k');\n const extraAlias = context.unique('ex');\n code.push(`const ${keysAlias} = new Set(${JSON.stringify(Object.keys(schema))});`);\n code.push(`const ${extraAlias} = Object.keys(${valueAlias}).filter(${kAlias} => !${keysAlias}.has(${kAlias}));`);\n code.push(`if (${extraAlias}.length !== 0) { throw new TypeError(\\`Extra properties: \\${${extraAlias}}, are not allowed for path \"${path}\"\\`); }`);\n }\n code.push(...Object.entries(schema).map(([key, s]) => codeGen(s, context, `${valueAlias}['${key}']`, `${path}.${key}`)));\n return `${code.join('\\n')}`;\n }\n } else if (typeof schema === 'symbol') {\n const index = context.register(schema);\n const valueAlias = context.unique('v');\n const registryAlias = context.unique('r');\n\n return `\nconst ${valueAlias} = ${valuePath};\nconst ${registryAlias} = ctx.registry[${index}];\nif (typeof ${valueAlias} !== 'symbol') { throw new TypeError(\\`Invalid type \\${typeof ${valueAlias}} for path \"${path}\", expected symbol\\`); }\nif (${valueAlias} !== ${registryAlias}) { throw new TypeError(\\`Invalid value \\${${valueAlias}.toString()} for path \"${path}\", expected ${schema.toString()}\\`); }\n `;\n } else if (schema === null || schema === undefined) {\n const valueAlias = context.unique('v');\n return `\nconst ${valueAlias} = ${valuePath};\nif (${valueAlias} !== null && ${valueAlias} !== undefined ) { throw new TypeError(\\`Invalid value \\${JSON.stringify(${valueAlias})} for path \"${path}\", expected nullable\\`); }\n `;\n } else {\n const valueAlias = context.unique('v');\n const value = context.unique('val');\n return `\nconst ${valueAlias} = ${valuePath};\nconst ${value} = ${JSON.stringify(schema)};\n${codeGenExpectNonError(valueAlias, path)}\nif (typeof ${valueAlias} !== '${typeof schema}') { throw new TypeError(\\`Invalid type \\${typeof ${valueAlias}} for path \"${path}\", expected ${typeof schema}\\`); }\nif (${valueAlias} !== ${value}) { throw new TypeError(\\`Invalid value \\${JSON.stringify(${valueAlias})} for path \"${path}\", expected ${JSON.stringify(schema)}\\`); }\n`;\n }\n};\n\n/**\n * Compiles a schema into a validation function.\n *\n * This function takes a schema definition and generates a JavaScript function\n * that can be used to validate data against the schema.\n *\n * @template T - The type of data the schema validates.\n * @param schema - The schema to compile.\n * @param rootName - A name for the root of the data structure (used in error messages).\n * @returns A validation function that takes data as input and throws a TypeError if the data does not conform to the schema.\n *\n * @example\n * ```typescript\n * import { compile, optional, and, or } from 'ascertain';\n *\n * const userSchema = {\n * name: String,\n * age: Number,\n * email: optional(String),\n * role: or('admin', 'user', 'guest')\n * };\n *\n * const validateUser = compile(userSchema, 'User');\n *\n * // Valid data - no error thrown\n * validateUser({\n * name: 'John Doe',\n * age: 30,\n * email: 'john@example.com',\n * role: 'user'\n * });\n *\n * // Invalid data - throws TypeError\n * try {\n * validateUser({\n * name: 123, // Invalid: should be string\n * age: 'thirty' // Invalid: should be number\n * });\n * } catch (error) {\n * console.error(error.message); // Detailed validation errors\n * }\n * ```\n */\nexport const compile = <T>(schema: Schema<T>, rootName: string) => {\n const context = new Context();\n const code = codeGen(schema, context, 'data', rootName);\n const validator = new Function('ctx', 'data', code);\n return (data: T) => validator(context, data);\n};\n\n/**\n * Asserts that data conforms to a given schema.\n *\n * This function is a convenient wrapper around `compile`. It compiles the schema\n * and immediately validates the provided data against it.\n *\n * @template T - The type of data the schema validates.\n * @param schema - The schema to validate against.\n * @param data - The data to validate.\n * @param rootName - A name for the root of the data structure (used in error messages, defaults to '[root]').\n * @throws `{TypeError}` If the data does not conform to the schema.\n *\n * @example\n * ```typescript\n * import { ascertain, optional, and, or } from 'ascertain';\n *\n * const userSchema = {\n * name: String,\n * age: Number,\n * email: optional(String),\n * active: Boolean\n * };\n *\n * const userData = {\n * name: 'Alice',\n * age: 25,\n * email: 'alice@example.com',\n * active: true\n * };\n *\n * // Validate data - throws if invalid, otherwise continues silently\n * ascertain(userSchema, userData, 'UserData');\n * console.log('User data is valid!');\n *\n * // Example with invalid data\n * try {\n * ascertain(userSchema, {\n * name: 'Bob',\n * age: 'twenty-five', // Invalid: should be number\n * active: true\n * }, 'UserData');\n * } catch (error) {\n * console.error('Validation failed:', error.message);\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Array validation\n * const numbersSchema = [Number];\n * const numbers = [1, 2, 3, 4, 5];\n *\n * ascertain(numbersSchema, numbers, 'Numbers');\n *\n * // Tuple validation\n * const coordinateSchema = tuple(Number, Number);\n * const point = [10, 20];\n *\n * ascertain(coordinateSchema, point, 'Point');\n * ```\n */\nexport const ascertain = <T>(schema: Schema<T>, data: T, rootName = '[root]') => {\n compile(schema, rootName)(data);\n};\n"],"names":["$keys","$strict","$values","and","as","asError","ascertain","compile","fromBase64","optional","or","tuple","Operator","schemas","length","TypeError","name","Symbol","for","Or","And","Optional","schema","Tuple","Buffer","value","atob","from","toString","MULTIPLIERS","ms","s","m","h","d","w","message","string","number","result","parseFloat","Number","isNaN","date","Date","parse","valueOf","time","conversionFactor","matches","match","amount","unit","parseInt","boolean","test","array","delimiter","split","json","JSON","base64","Context","registry","varIndex","register","includes","push","indexOf","unique","prefix","codeGenCollectErrors","errorsAlias","code","extra","codeGenExpectNoErrors","codeGenExpectNonError","valueAlias","path","codeGenExpectNonNullable","codeGenExpectObject","instanceOf","codeGenExpectArray","codeGen","context","valuePath","map","join","reduceRight","idx","index","registryAlias","Error","prototype","Array","isArray","key","RegExp","keysAlias","kAlias","vAlias","entriesAlias","extraAlias","stringify","Object","keys","entries","undefined","rootName","validator","Function","data"],"mappings":"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"}