ascertain 2.0.87 → 2.1.0

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.
@@ -1 +1 @@
1
- {"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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"}
1
+ {"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 * ```\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\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 */\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\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 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 * 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.includes('.') || value.includes('e') || value.includes('E') ? parseFloat(value) : parseInt(value, 10);\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\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\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\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 valueAlias = context.unique('v');\n const code: string[] = [`const ${valueAlias} = ${valuePath};`, codeGenExpectNonNullable(valueAlias, path)];\n if ((schema as unknown) !== Error && !(schema?.prototype instanceof Error)) {\n code.push(codeGenExpectNonError(valueAlias, path));\n }\n\n const name = (schema as { name?: string })?.name;\n const primitiveType =\n name === 'String'\n ? 'string'\n : name === 'Number'\n ? 'number'\n : name === 'Boolean'\n ? 'boolean'\n : name === 'BigInt'\n ? 'bigint'\n : name === 'Symbol'\n ? 'symbol'\n : null;\n\n if (primitiveType) {\n code.push(\n `if (typeof ${valueAlias} !== '${primitiveType}') { throw new TypeError(\\`Invalid type \\${typeof ${valueAlias}} for path \"${path}\", expected type ${schema?.name}\\`); }`,\n );\n if (primitiveType === 'number') {\n code.push(\n `if (Number.isNaN(${valueAlias})) { throw new TypeError(\\`Invalid value \\${${valueAlias}} for path \"${path}\", expected a valid ${schema?.name}\\`); }`,\n );\n }\n } else if (name === 'Function') {\n code.push(\n `if (typeof ${valueAlias} !== 'function') { throw new TypeError(\\`Invalid type \\${typeof ${valueAlias}} for path \"${path}\", expected type Function\\`); }`,\n );\n } else {\n const index = context.register(schema);\n const registryAlias = context.unique('r');\n code.push(\n `const ${registryAlias} = ctx.registry[${index}];`,\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 }\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\n if (schema.length === 1) {\n code.push(\n ...schema.map(\n (s) =>\n `for (let ${key} = 0; ${key} < ${valueAlias}.length; ${key}++) { const ${value} = ${valueAlias}[${key}]; ${codeGenCollectErrors(errorsAlias, codeGen(s, context, value, `${path}[\\${${key}}]`))} }`,\n ),\n );\n } else {\n code.push(\n `if (${valueAlias}.length > ${schema.length}) { throw new TypeError(\\`Invalid tuple length \\${${valueAlias}.length} for path \"${path}\", expected ${schema.length}.\\`); }`,\n );\n code.push(...schema.map((s, idx) => codeGenCollectErrors(errorsAlias, codeGen(s, context, `${valueAlias}[${idx}]`, `${path}[${idx}]`))));\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(String(${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} = [];\nfor (const ${kAlias} of ${keysAlias}) { ${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} = [];\nfor (const [${kAlias}, ${vAlias}] of ${entriesAlias}) { ${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}[${JSON.stringify(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\n/**\n * Extracts the shape of a config object based on the schema keys.\n * Recursively picks only the properties defined in the schema.\n */\nexport type ExtractShape<C, S> = {\n [K in keyof S & keyof C]: S[K] extends object ? (C[K] extends object ? ExtractShape<C[K], S[K]> : C[K]) : C[K];\n};\n\n/**\n * Creates a typed validator function for a config object.\n *\n * Returns a function that validates a schema against the config and returns\n * the same config reference with a narrowed type containing only the validated fields.\n *\n * @template C - The type of the config object.\n * @param config - The config object to validate against.\n * @param rootName - A name for the root of the data structure (used in error messages).\n * @returns A validator function that takes a schema and returns the typed config subset.\n *\n * @example\n * ```typescript\n * import { createValidator, as } from 'ascertain';\n *\n * const config = {\n * app: { name: as.string(process.env.APP_NAME) },\n * kafka: { brokers: as.array(process.env.BROKERS, ',') },\n * redis: { host: as.string(process.env.REDIS_HOST) },\n * };\n *\n * const validate = createValidator(config, '[CONFIG]');\n *\n * // Consumer only validates what it needs\n * const { app, kafka } = validate({\n * app: { name: String },\n * kafka: { brokers: [String] },\n * });\n *\n * // app.name is typed as string\n * // kafka.brokers is typed as string[]\n * // redis is not accessible - TypeScript error\n * ```\n */\nexport const createValidator = <C>(config: C, rootName = '[root]') => {\n return <S extends Schema<Partial<C>>>(schema: S): ExtractShape<C, S> => {\n ascertain(schema as Schema<C>, config, rootName);\n return config as ExtractShape<C, S>;\n };\n};\n"],"names":["$keys","$strict","$values","and","as","asError","ascertain","compile","createValidator","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","TIME_REGEX","message","string","number","start","c0","charCodeAt","c1","result","Number","slice","isNaN","includes","parseFloat","parseInt","date","Date","parse","valueOf","time","conversionFactor","matches","match","amount","unit","multiplier","parsed","Math","floor","boolean","test","array","delimiter","split","json","JSON","base64","Context","registry","lookupMap","Map","varIndex","register","index","get","undefined","push","set","unique","prefix","codeGenCollectErrors","errorsAlias","code","extra","codeGenExpectNoErrors","codeGenExpectNonError","valueAlias","path","codeGenExpectNonNullable","codeGenExpectObject","instanceOf","codeGenExpectArray","codeGen","context","valuePath","map","join","reduceRight","idx","Error","prototype","primitiveType","registryAlias","Array","isArray","key","RegExp","keysAlias","kAlias","vAlias","entriesAlias","extraAlias","stringify","Object","keys","entries","rootName","validator","Function","data","config"],"mappings":";;;;;;;;;;;QAsBaA;eAAAA;;QAQAC;eAAAA;;QAJAC;eAAAA;;QAmFAC;eAAAA;;QAoIAC;eAAAA;;QAFAC;eAAAA;;QA2dAC;eAAAA;;QApEAC;eAAAA;;QAkHAC;eAAAA;;QAhiBAC;eAAAA;;QAlDAC;eAAAA;;QAxFAC;eAAAA;;QAgIAC;eAAAA;;;AArMb,MAAeC;;IACb,YAAY,AAAgBC,OAAoB,CAAE;aAAtBA,UAAAA;QAC1B,IAAIA,QAAQC,MAAM,KAAK,GAAG;YACxB,MAAM,IAAIC,UAAU,CAAC,iBAAiB,EAAE,IAAI,CAAC,WAAW,CAACC,IAAI,CAAC,+BAA+B,CAAC;QAChG;IACF;AACF;AAOO,MAAMjB,QAAQkB,OAAOC,GAAG,CAAC;AAIzB,MAAMjB,UAAUgB,OAAOC,GAAG,CAAC;AAI3B,MAAMlB,UAAUiB,OAAOC,GAAG,CAAC;AAgBlC,MAAMC,WAAcP;AAAa;AAgC1B,MAAMF,KAAK,CAAI,GAAGG,UAAyB,IAAIM,GAAGN;AAEzD,MAAMO,YAAeR;AAAa;AA6B3B,MAAMV,MAAM,CAAI,GAAGW,UAAyB,IAAIO,IAAIP;AAE3D,MAAMQ,iBAAoBT;IACxB,YAAYU,MAAiB,CAAE;QAC7B,KAAK,CAAC;YAACA;SAAO;IAChB;AACF;AAmDO,MAAMb,WAAW,CAAIa,SAAsB,IAAID,SAASC;AAE/D,MAAMC,cAAiBX;AAAa;AAsC7B,MAAMD,QAAQ,CAAI,GAAGE,UAAyB,IAAIU,MAAMV;AAUxD,MAAML,aAAa,OAAOgB,WAAW,cAAc,CAACC,QAAkBC,KAAKD,SAAS,CAACA,QAAkBD,OAAOG,IAAI,CAACF,OAAO,UAAUG,QAAQ,CAAC;AAEpJ,MAAMC,cAAc;IAClBC,IAAI;IACJC,GAAG;IACHC,GAAG;IACHC,GAAG;IACHC,GAAG;IACHC,GAAG;AACL;AAEA,MAAMC,aAAa;AAYZ,MAAMhC,UAAU,CAAIiC,UAAoB,IAAItB,UAAUsB;AAEtD,MAAMlC,KAAK;IAOhBmC,QAAQ,CAACb;QACP,OAAO,OAAOA,UAAU,WAAWA,QAAQrB,QAAQ,CAAC,eAAe,EAAEqB,MAAM,oBAAoB,CAAC;IAClG;IAcAc,QAAQ,CAACd;QACP,IAAI,OAAOA,UAAU,UAAU;YAC7B,OAAOrB,QAAQ,CAAC,cAAc,EAAEqB,MAAM,yBAAyB,CAAC;QAClE;QACA,MAAMe,QAAQf,KAAK,CAAC,EAAE,KAAK,OAAOA,KAAK,CAAC,EAAE,KAAK,MAAM,IAAI;QACzD,MAAMgB,KAAKhB,MAAMiB,UAAU,CAACF;QAC5B,MAAMG,KAAKlB,MAAMiB,UAAU,CAACF,QAAQ,KAAK;QAEzC,IAAIC,OAAO,MAAOE,CAAAA,OAAO,OAAOA,OAAO,OAAOA,OAAO,EAAC,GAAI;YAExD,MAAMC,SAASC,OAAOL,QAAQf,MAAMqB,KAAK,CAAC,KAAKrB;YAC/C,IAAIoB,OAAOE,KAAK,CAACH,SAAS,OAAOxC,QAAQ,CAAC,cAAc,EAAEqB,MAAM,yBAAyB,CAAC;YAC1F,OAAOA,KAAK,CAAC,EAAE,KAAK,MAAM,CAACmB,SAASA;QACtC;QAEA,MAAMA,SAASnB,MAAMuB,QAAQ,CAAC,QAAQvB,MAAMuB,QAAQ,CAAC,QAAQvB,MAAMuB,QAAQ,CAAC,OAAOC,WAAWxB,SAASyB,SAASzB,OAAO;QACvH,OAAOoB,OAAOE,KAAK,CAACH,UAAUxC,QAAQ,CAAC,cAAc,EAAEqB,MAAM,yBAAyB,CAAC,IAAImB;IAC7F;IAOAO,MAAM,CAAC1B;QACL,MAAMmB,SAASQ,KAAKC,KAAK,CAAC5B;QAC1B,MAAM0B,OAAO,IAAIC,KAAKR;QACtB,OAAOC,OAAOE,KAAK,CAACI,KAAKG,OAAO,MAAMlD,QAAQ,CAAC,eAAe,EAAEqB,MAAM,+BAA+B,CAAC,IAAI0B;IAC5G;IAQAI,MAAM,CAAC9B,OAA2B+B,mBAAmB,CAAC;QACpD,IAAI,CAAC/B,OAAO,OAAOrB,QAAQ,CAAC,cAAc,EAAEqB,MAAM,8BAA8B,CAAC;QAEjF,MAAMgC,UAAUhC,MAAMiC,KAAK,CAACtB;QAC5B,IAAI,CAACqB,SAAS,OAAOrD,QAAQ,CAAC,cAAc,EAAEqB,MAAM,8BAA8B,CAAC;QAEnF,MAAM,GAAGkC,QAAQC,OAAO,IAAI,CAAC,GAAGH;QAChC,MAAMI,aAAahC,WAAW,CAAC+B,KAAiC;QAChE,MAAME,SAASb,WAAWU;QAE1B,IAAI,CAACE,cAAchB,OAAOE,KAAK,CAACe,SAAS;YACvC,OAAO1D,QAAQ,CAAC,cAAc,EAAEqB,MAAM,8BAA8B,CAAC;QACvE;QAEA,OAAOsC,KAAKC,KAAK,CAAC,AAACF,SAASD,aAAcL;IAC5C;IAOAS,SAAS,CAACxC,QACR,uCAAuCyC,IAAI,CAACzC,SACxC,sBAAsByC,IAAI,CAACzC,SAC3BrB,QAAQ,CAAC,cAAc,EAAEqB,MAAM,yBAAyB,CAAC;IAQ/D0C,OAAO,CAAC1C,OAA2B2C,YAAgC3C,OAAO4C,QAAQD,cAAchE,QAAQ,CAAC,cAAc,EAAEqB,MAAM,mBAAmB,CAAC;IAQnJ6C,MAAM,CAAa7C;QACjB,IAAI;YACF,OAAO8C,KAAKlB,KAAK,CAAC5B;QACpB,EAAE,OAAM;YACN,OAAOrB,QAAQ,CAAC,cAAc,EAAEqB,MAAM,8BAA8B,CAAC;QACvE;IACF;IAOA+C,QAAQ,CAAC/C;QACP,IAAI;YACF,OAAOjB,WAAWiB;QACpB,EAAE,OAAM;YACN,OAAOrB,QAAQ,CAAC,cAAc,EAAEqB,MAAM,gCAAgC,CAAC;QACzE;IACF;AACF;AAQA,MAAMgD;IACYC,WAAsB,EAAE,CAAC;IACxBC,YAAkC,IAAIC,MAAM;IACrDC,WAAW,EAAE;IAErBC,SAASrD,KAAc,EAAU;QAC/B,MAAMsD,QAAQ,IAAI,CAACJ,SAAS,CAACK,GAAG,CAACvD;QACjC,IAAIsD,UAAUE,WAAW;YACvB,OAAOF;QACT;QACA;YACE,MAAMA,QAAQ,IAAI,CAACL,QAAQ,CAACQ,IAAI,CAACzD,SAAS;YAC1C,IAAI,CAACkD,SAAS,CAACQ,GAAG,CAAC1D,OAAOsD;YAC1B,OAAOA;QACT;IACF;IAEAK,OAAOC,MAAc,EAAE;QACrB,OAAO,GAAGA,OAAO,EAAE,EAAE,IAAI,CAACR,QAAQ,IAAI;IACxC;AACF;AAEA,MAAMS,uBAAuB,CAACC,aAAqBC,MAAcC,QAAgB,EAAE,GAAK,CAAC,KAAK,EAAED,KAAK,aAAa,EAAED,YAAY,iBAAiB,EAAEE,MAAM,CAAC,CAAC;AAC3J,MAAMC,wBAAwB,CAACH,cAAwB,CAAC,IAAI,EAAEA,YAAY,qCAAqC,EAAEA,YAAY,gBAAgB,CAAC;AAC9I,MAAMI,wBAAwB,CAACC,YAAoBC,OACjD,CAAC,IAAI,EAAED,WAAW,8CAA8C,EAAEA,WAAW,oBAAoB,EAAEC,KAAK,QAAQ,CAAC;AACnH,MAAMC,2BAA2B,CAACF,YAAoBC,OACpD,CAAC,IAAI,EAAED,WAAW,aAAa,EAAEA,WAAW,yDAAyD,EAAEA,WAAW,YAAY,EAAEC,KAAK,+BAA+B,CAAC;AACvK,MAAME,sBAAsB,CAACH,YAAoBC,MAAcG,aAC7D,CAAC,WAAW,EAAEJ,WAAW,8DAA8D,EAAEA,WAAW,YAAY,EAAEC,KAAK,2BAA2B,EAAEG,WAAW,MAAM,CAAC;AACxK,MAAMC,qBAAqB,CAACL,YAAoBC,OAC9C,CAAC,mBAAmB,EAAED,WAAW,kDAAkD,EAAEA,WAAW,8BAA8B,EAAEC,KAAK,uCAAuC,CAAC;AAE/K,MAAMK,UAAU,CAAI5E,QAAmB6E,SAAkBC,WAAmBP;IAC1E,IAAIvE,kBAAkBF,KAAK;QACzB,MAAMwE,aAAaO,QAAQf,MAAM,CAAC;QAClC,MAAMG,cAAcY,QAAQf,MAAM,CAAC;QACnC,MAAMI,OAAOlE,OAAOT,OAAO,CAACwF,GAAG,CAAC,CAACtE,IAAM,CAAC,MAAM,EAAEmE,QAAQnE,GAAGoE,SAASP,YAAYC,MAAM,eAAe,EAAEN,YAAY,mBAAmB,CAAC,EAAEe,IAAI,CAAC;QAC9I,OAAO,CAAC;QACJ,EAAEf,YAAY;QACd,EAAEK,WAAW,GAAG,EAAEQ,UAAU;EAClC,EAAEZ,KAAK;EACP,EAAEE,sBAAsBH,aAAa;AACvC,CAAC;IACC,OAAO,IAAIjE,kBAAkBH,IAAI;QAC/B,MAAMyE,aAAaO,QAAQf,MAAM,CAAC;QAClC,MAAMG,cAAcY,QAAQf,MAAM,CAAC;QACnC,MAAMI,OAAOlE,OAAOT,OAAO,CACxBwF,GAAG,CAAC,CAACtE,IAAMmE,QAAQnE,GAAGoE,SAASP,YAAYC,OAC3CU,WAAW,CAAC,CAAC3D,QAAQ4C,OAASF,qBAAqBC,aAAaC,MAAM5C,SAAS8C,sBAAsBH;QACxG,OAAO,CAAC;MACN,EAAEA,YAAY;MACd,EAAEK,WAAW,GAAG,EAAEQ,UAAU;AAClC,EAAEZ,KAAK;IACH,CAAC;IACH,OAAO,IAAIlE,kBAAkBD,UAAU;QACrC,MAAMuE,aAAaO,QAAQf,MAAM,CAAC;QAClC,OAAO,CAAC;MACN,EAAEQ,WAAW,GAAG,EAAEQ,UAAU;IAC9B,EAAER,WAAW,kBAAkB,EAAEA,WAAW,aAAa,EAAEM,QAAQ5E,OAAOT,OAAO,CAAC,EAAE,EAAEsF,SAASP,YAAYC,MAAM;AACrH,CAAC;IACC,OAAO,IAAIvE,kBAAkBC,OAAO;QAClC,MAAMqE,aAAaO,QAAQf,MAAM,CAAC;QAClC,MAAMG,cAAcY,QAAQf,MAAM,CAAC;QACnC,MAAMI,OAAiB;YACrB;YACA,CAAC,MAAM,EAAEI,WAAW,GAAG,EAAEQ,UAAU,CAAC,CAAC;YACrC,CAAC,MAAM,EAAEb,YAAY,MAAM,CAAC;YAC5BO,yBAAyBF,YAAYC;YACrCE,oBAAoBH,YAAYC,MAAM;YACtCI,mBAAmBL,YAAYC;YAC/B,CAAC,IAAI,EAAED,WAAW,YAAY,EAAEtE,OAAOT,OAAO,CAACC,MAAM,CAAC,kDAAkD,EAAE8E,WAAW,mBAAmB,EAAEC,KAAK,YAAY,EAAEvE,OAAOT,OAAO,CAACC,MAAM,CAAC,OAAO,CAAC;eACxLQ,OAAOT,OAAO,CAACwF,GAAG,CAAC,CAACtE,GAAGyE,MAAQlB,qBAAqBC,aAAaW,QAAQnE,GAAGoE,SAAS,GAAGP,WAAW,CAAC,EAAEY,IAAI,CAAC,CAAC,EAAE,GAAGX,KAAK,CAAC,EAAEW,IAAI,CAAC,CAAC;YAClId,sBAAsBH;SACvB;QACD,OAAOC,KAAKc,IAAI,CAAC;IACnB,OAAO,IAAI,OAAOhF,WAAW,YAAY;QACvC,MAAMsE,aAAaO,QAAQf,MAAM,CAAC;QAClC,MAAMI,OAAiB;YAAC,CAAC,MAAM,EAAEI,WAAW,GAAG,EAAEQ,UAAU,CAAC,CAAC;YAAEN,yBAAyBF,YAAYC;SAAM;QAC1G,IAAI,AAACvE,WAAuBmF,SAAS,CAAEnF,CAAAA,QAAQoF,qBAAqBD,KAAI,GAAI;YAC1EjB,KAAKN,IAAI,CAACS,sBAAsBC,YAAYC;QAC9C;QAEA,MAAM7E,OAAQM,QAA8BN;QAC5C,MAAM2F,gBACJ3F,SAAS,WACL,WACAA,SAAS,WACP,WACAA,SAAS,YACP,YACAA,SAAS,WACP,WACAA,SAAS,WACP,WACA;QAEd,IAAI2F,eAAe;YACjBnB,KAAKN,IAAI,CACP,CAAC,WAAW,EAAEU,WAAW,MAAM,EAAEe,cAAc,kDAAkD,EAAEf,WAAW,YAAY,EAAEC,KAAK,iBAAiB,EAAEvE,QAAQN,KAAK,MAAM,CAAC;YAE1K,IAAI2F,kBAAkB,UAAU;gBAC9BnB,KAAKN,IAAI,CACP,CAAC,iBAAiB,EAAEU,WAAW,4CAA4C,EAAEA,WAAW,YAAY,EAAEC,KAAK,oBAAoB,EAAEvE,QAAQN,KAAK,MAAM,CAAC;YAEzJ;QACF,OAAO,IAAIA,SAAS,YAAY;YAC9BwE,KAAKN,IAAI,CACP,CAAC,WAAW,EAAEU,WAAW,gEAAgE,EAAEA,WAAW,YAAY,EAAEC,KAAK,+BAA+B,CAAC;QAE7J,OAAO;YACL,MAAMd,QAAQoB,QAAQrB,QAAQ,CAACxD;YAC/B,MAAMsF,gBAAgBT,QAAQf,MAAM,CAAC;YACrCI,KAAKN,IAAI,CACP,CAAC,MAAM,EAAE0B,cAAc,gBAAgB,EAAE7B,MAAM,EAAE,CAAC,EAClD,CAAC,WAAW,EAAEa,WAAW,mBAAmB,EAAEA,WAAW,YAAY,EAAEgB,cAAc,kDAAkD,EAAEhB,WAAW,+BAA+B,EAAEC,KAAK,2BAA2B,EAAEvE,QAAQN,KAAK,MAAM,CAAC,EAC3O,CAAC,WAAW,EAAE4E,WAAW,iBAAiB,EAAEA,WAAW,kBAAkB,EAAEgB,cAAc,0CAA0C,EAAEhB,WAAW,+BAA+B,EAAEC,KAAK,iBAAiB,EAAEvE,QAAQN,KAAK,MAAM,CAAC,EAC7N,CAAC,iBAAiB,EAAE4E,WAAW,yDAAyD,EAAEA,WAAW,YAAY,EAAEC,KAAK,oBAAoB,EAAEvE,QAAQN,KAAK,MAAM,CAAC;QAEtK;QACA,OAAOwE,KAAKc,IAAI,CAAC;IACnB,OAAO,IAAIO,MAAMC,OAAO,CAACxF,SAAS;QAChC,MAAMsE,aAAaO,QAAQf,MAAM,CAAC;QAClC,MAAMI,OAAiB;YACrB,CAAC,MAAM,EAAEI,WAAW,GAAG,EAAEQ,UAAU,CAAC,CAAC;YACrCN,yBAAyBF,YAAYC;YACrCF,sBAAsBC,YAAYC;YAClCE,oBAAoBH,YAAYC,MAAM;YACtCI,mBAAmBL,YAAYC;SAChC;QACD,IAAIvE,OAAOR,MAAM,GAAG,GAAG;YACrB,MAAMW,QAAQ0E,QAAQf,MAAM,CAAC;YAC7B,MAAM2B,MAAMZ,QAAQf,MAAM,CAAC;YAC3B,MAAMG,cAAcY,QAAQf,MAAM,CAAC;YACnCI,KAAKN,IAAI,CAAC,CAAC,MAAM,EAAEK,YAAY,MAAM,CAAC;YAEtC,IAAIjE,OAAOR,MAAM,KAAK,GAAG;gBACvB0E,KAAKN,IAAI,IACJ5D,OAAO+E,GAAG,CACX,CAACtE,IACC,CAAC,SAAS,EAAEgF,IAAI,MAAM,EAAEA,IAAI,GAAG,EAAEnB,WAAW,SAAS,EAAEmB,IAAI,YAAY,EAAEtF,MAAM,GAAG,EAAEmE,WAAW,CAAC,EAAEmB,IAAI,GAAG,EAAEzB,qBAAqBC,aAAaW,QAAQnE,GAAGoE,SAAS1E,OAAO,GAAGoE,KAAK,IAAI,EAAEkB,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC;YAG3M,OAAO;gBACLvB,KAAKN,IAAI,CACP,CAAC,IAAI,EAAEU,WAAW,UAAU,EAAEtE,OAAOR,MAAM,CAAC,kDAAkD,EAAE8E,WAAW,mBAAmB,EAAEC,KAAK,YAAY,EAAEvE,OAAOR,MAAM,CAAC,OAAO,CAAC;gBAE3K0E,KAAKN,IAAI,IAAI5D,OAAO+E,GAAG,CAAC,CAACtE,GAAGyE,MAAQlB,qBAAqBC,aAAaW,QAAQnE,GAAGoE,SAAS,GAAGP,WAAW,CAAC,EAAEY,IAAI,CAAC,CAAC,EAAE,GAAGX,KAAK,CAAC,EAAEW,IAAI,CAAC,CAAC;YACtI;YAEAhB,KAAKN,IAAI,CAACQ,sBAAsBH;QAClC;QACA,OAAOC,KAAKc,IAAI,CAAC;IACnB,OAAO,IAAI,OAAOhF,WAAW,YAAYA,WAAW,MAAM;QACxD,IAAIA,kBAAkB0F,QAAQ;YAC5B,MAAMpB,aAAaO,QAAQf,MAAM,CAAC;YAClC,OAAO,CAAC;MACR,EAAEQ,WAAW,GAAG,EAAEQ,UAAU;AAClC,EAAEN,yBAAyBF,YAAYC,MAAM;AAC7C,EAAEF,sBAAsBC,YAAYC,MAAM;KACrC,EAAEvE,OAAOM,QAAQ,GAAG,aAAa,EAAEgE,WAAW,6CAA6C,EAAEA,WAAW,YAAY,EAAEC,KAAK,qBAAqB,EAAEvE,OAAOM,QAAQ,GAAG;AACzK,CAAC;QACG,OAAO;YACL,MAAMgE,aAAaO,QAAQf,MAAM,CAAC;YAClC,MAAMI,OAAiB;gBACrB,CAAC,MAAM,EAAEI,WAAW,GAAG,EAAEQ,UAAU,CAAC,CAAC;gBACrCN,yBAAyBF,YAAYC;gBACrCE,oBAAoBH,YAAYC,MAAM;gBACtCF,sBAAsBC,YAAYC;aACnC;YACD,IAAI9F,SAASuB,QAAQ;gBACnB,MAAM2F,YAAYd,QAAQf,MAAM,CAAC;gBACjC,MAAMG,cAAcY,QAAQf,MAAM,CAAC;gBACnC,MAAM8B,SAASf,QAAQf,MAAM,CAAC;gBAC9BI,KAAKN,IAAI,CAAC,CAAC;MACb,EAAE+B,UAAU,eAAe,EAAErB,WAAW;MACxC,EAAEL,YAAY;WACT,EAAE2B,OAAO,IAAI,EAAED,UAAU,IAAI,EAAE3B,qBAAqBC,aAAaW,QAAQ5E,MAAM,CAACvB,MAAM,EAAEoG,SAASe,QAAQ,GAAGrB,KAAK,IAAI,EAAEqB,OAAO,EAAE,CAAC,GAAG;AAC/I,EAAExB,sBAAsBH,aAAa;AACrC,CAAC;YACK;YACA,IAAItF,WAAWqB,QAAQ;gBACrB,MAAM6F,SAAShB,QAAQf,MAAM,CAAC;gBAC9B,MAAM8B,SAASf,QAAQf,MAAM,CAAC;gBAC9B,MAAMgC,eAAejB,QAAQf,MAAM,CAAC;gBACpC,MAAMG,cAAcY,QAAQf,MAAM,CAAC;gBACnCI,KAAKN,IAAI,CAAC,CAAC;MACb,EAAEkC,aAAa,kBAAkB,EAAExB,WAAW;MAC9C,EAAEL,YAAY;YACR,EAAE2B,OAAO,EAAE,EAAEC,OAAO,KAAK,EAAEC,aAAa,IAAI,EAAE9B,qBAAqBC,aAAaW,QAAQ5E,MAAM,CAACrB,QAAQ,EAAEkG,SAASgB,QAAQ,GAAGtB,KAAK,IAAI,EAAEqB,OAAO,EAAE,CAAC,GAAG;AACjK,EAAExB,sBAAsBH,aAAa;AACrC,CAAC;YACK;YACA,IAAIvF,WAAWsB,UAAUA,MAAM,CAACtB,QAAQ,EAAE;gBACxC,MAAMiH,YAAYd,QAAQf,MAAM,CAAC;gBACjC,MAAM8B,SAASf,QAAQf,MAAM,CAAC;gBAC9B,MAAMiC,aAAalB,QAAQf,MAAM,CAAC;gBAClCI,KAAKN,IAAI,CAAC,CAAC,MAAM,EAAE+B,UAAU,WAAW,EAAE1C,KAAK+C,SAAS,CAACC,OAAOC,IAAI,CAAClG,SAAS,EAAE,CAAC;gBACjFkE,KAAKN,IAAI,CAAC,CAAC,MAAM,EAAEmC,WAAW,eAAe,EAAEzB,WAAW,SAAS,EAAEsB,OAAO,KAAK,EAAED,UAAU,KAAK,EAAEC,OAAO,GAAG,CAAC;gBAC/G1B,KAAKN,IAAI,CAAC,CAAC,IAAI,EAAEmC,WAAW,4DAA4D,EAAEA,WAAW,6BAA6B,EAAExB,KAAK,OAAO,CAAC;YACnJ;YACAL,KAAKN,IAAI,IAAIqC,OAAOE,OAAO,CAACnG,QAAQ+E,GAAG,CAAC,CAAC,CAACU,KAAKhF,EAAE,GAAKmE,QAAQnE,GAAGoE,SAAS,GAAGP,WAAW,CAAC,EAAErB,KAAK+C,SAAS,CAACP,KAAK,CAAC,CAAC,EAAE,GAAGlB,KAAK,CAAC,EAAEkB,KAAK;YACnI,OAAO,GAAGvB,KAAKc,IAAI,CAAC,OAAO;QAC7B;IACF,OAAO,IAAI,OAAOhF,WAAW,UAAU;QACrC,MAAMyD,QAAQoB,QAAQrB,QAAQ,CAACxD;QAC/B,MAAMsE,aAAaO,QAAQf,MAAM,CAAC;QAClC,MAAMwB,gBAAgBT,QAAQf,MAAM,CAAC;QAErC,OAAO,CAAC;MACN,EAAEQ,WAAW,GAAG,EAAEQ,UAAU;MAC5B,EAAEQ,cAAc,gBAAgB,EAAE7B,MAAM;WACnC,EAAEa,WAAW,8DAA8D,EAAEA,WAAW,YAAY,EAAEC,KAAK;IAClH,EAAED,WAAW,KAAK,EAAEgB,cAAc,2CAA2C,EAAEhB,WAAW,uBAAuB,EAAEC,KAAK,YAAY,EAAEvE,OAAOM,QAAQ,GAAG;IACxJ,CAAC;IACH,OAAO,IAAIN,WAAW,QAAQA,WAAW2D,WAAW;QAClD,MAAMW,aAAaO,QAAQf,MAAM,CAAC;QAClC,OAAO,CAAC;MACN,EAAEQ,WAAW,GAAG,EAAEQ,UAAU;IAC9B,EAAER,WAAW,aAAa,EAAEA,WAAW,yEAAyE,EAAEA,WAAW,aAAa,EAAEC,KAAK;IACjJ,CAAC;IACH,OAAO;QACL,MAAMD,aAAaO,QAAQf,MAAM,CAAC;QAClC,MAAM3D,QAAQ0E,QAAQf,MAAM,CAAC;QAC7B,OAAO,CAAC;MACN,EAAEQ,WAAW,GAAG,EAAEQ,UAAU;MAC5B,EAAE3E,MAAM,GAAG,EAAE8C,KAAK+C,SAAS,CAAChG,QAAQ;AAC1C,EAAEqE,sBAAsBC,YAAYC,MAAM;WAC/B,EAAED,WAAW,MAAM,EAAE,OAAOtE,OAAO,kDAAkD,EAAEsE,WAAW,YAAY,EAAEC,KAAK,YAAY,EAAE,OAAOvE,OAAO;IACxJ,EAAEsE,WAAW,KAAK,EAAEnE,MAAM,0DAA0D,EAAEmE,WAAW,aAAa,EAAEC,KAAK,YAAY,EAAEtB,KAAK+C,SAAS,CAAChG,QAAQ;AAC9J,CAAC;IACC;AACF;AA6CO,MAAMhB,UAAU,CAAIgB,QAAmBoG;IAC5C,MAAMvB,UAAU,IAAI1B;IACpB,MAAMe,OAAOU,QAAQ5E,QAAQ6E,SAAS,QAAQuB;IAC9C,MAAMC,YAAY,IAAIC,SAAS,OAAO,QAAQpC;IAC9C,OAAO,CAACqC,OAAYF,UAAUxB,SAAS0B;AACzC;AA+DO,MAAMxH,YAAY,CAAIiB,QAAmBuG,MAASH,WAAW,QAAQ;IAC1EpH,QAAQgB,QAAQoG,UAAUG;AAC5B;AA4CO,MAAMtH,kBAAkB,CAAIuH,QAAWJ,WAAW,QAAQ;IAC/D,OAAO,CAA+BpG;QACpCjB,UAAUiB,QAAqBwG,QAAQJ;QACvC,OAAOI;IACT;AACF"}
package/build/index.d.ts CHANGED
@@ -101,10 +101,6 @@ declare class And<T> extends Operator<T> {
101
101
  * const validDateSchema = and(Date, { toISOString: Function });
102
102
  * ascertain(validDateSchema, new Date(), "date"); // ✓ Valid
103
103
  *
104
- * // Multiple validation layers
105
- * const positiveNumberSchema = and(Number, (n: number) => n > 0);
106
- * ascertain(positiveNumberSchema, 42, "count"); // ✓ Valid
107
- * ascertain(positiveNumberSchema, -5, "count"); // ✗ Throws error
108
104
  * ```
109
105
  */
110
106
  export declare const and: <T>(...schemas: Schema<T>[]) => And<T>;
@@ -202,7 +198,25 @@ declare class Tuple<T> extends Operator<T> {
202
198
  * ```
203
199
  */
204
200
  export declare const tuple: <T>(...schemas: Schema<T>[]) => Tuple<T>;
201
+ /**
202
+ * Decodes a base64-encoded string to UTF-8.
203
+ *
204
+ * Uses `Buffer` in Node.js environments and `atob` in browsers.
205
+ *
206
+ * @param value - The base64-encoded string to decode.
207
+ * @returns The decoded UTF-8 string.
208
+ */
205
209
  export declare const fromBase64: (value: string) => string;
210
+ /**
211
+ * Creates a TypeError with the given message, typed as T for deferred error handling.
212
+ *
213
+ * Used by `as.*` conversion utilities to return errors that can be caught
214
+ * during schema validation rather than throwing immediately.
215
+ *
216
+ * @template T - The expected return type (for type compatibility with conversion functions).
217
+ * @param message - The error message.
218
+ * @returns A TypeError instance typed as T.
219
+ */
206
220
  export declare const asError: <T>(message: string) => T;
207
221
  export declare const as: {
208
222
  /**
@@ -215,6 +229,13 @@ export declare const as: {
215
229
  /**
216
230
  * Attempts to convert a value to a number.
217
231
  *
232
+ * Supports integers, floats, scientific notation (1e10), and prefixed formats:
233
+ * - Hexadecimal: `0x` or `0X` (e.g., `'0xFF'` → 255)
234
+ * - Octal: `0o` or `0O` (e.g., `'0o77'` → 63)
235
+ * - Binary: `0b` or `0B` (e.g., `'0b1010'` → 10)
236
+ *
237
+ * All formats support optional leading sign (`+` or `-`).
238
+ *
218
239
  * @param value - The value to convert (expected to be a string representation of a number).
219
240
  * @returns The value as a number, or a TypeError if not a valid number.
220
241
  */
@@ -371,4 +392,46 @@ export declare const compile: <T>(schema: Schema<T>, rootName: string) => (data:
371
392
  * ```
372
393
  */
373
394
  export declare const ascertain: <T>(schema: Schema<T>, data: T, rootName?: string) => void;
395
+ /**
396
+ * Extracts the shape of a config object based on the schema keys.
397
+ * Recursively picks only the properties defined in the schema.
398
+ */
399
+ export type ExtractShape<C, S> = {
400
+ [K in keyof S & keyof C]: S[K] extends object ? (C[K] extends object ? ExtractShape<C[K], S[K]> : C[K]) : C[K];
401
+ };
402
+ /**
403
+ * Creates a typed validator function for a config object.
404
+ *
405
+ * Returns a function that validates a schema against the config and returns
406
+ * the same config reference with a narrowed type containing only the validated fields.
407
+ *
408
+ * @template C - The type of the config object.
409
+ * @param config - The config object to validate against.
410
+ * @param rootName - A name for the root of the data structure (used in error messages).
411
+ * @returns A validator function that takes a schema and returns the typed config subset.
412
+ *
413
+ * @example
414
+ * ```typescript
415
+ * import { createValidator, as } from 'ascertain';
416
+ *
417
+ * const config = {
418
+ * app: { name: as.string(process.env.APP_NAME) },
419
+ * kafka: { brokers: as.array(process.env.BROKERS, ',') },
420
+ * redis: { host: as.string(process.env.REDIS_HOST) },
421
+ * };
422
+ *
423
+ * const validate = createValidator(config, '[CONFIG]');
424
+ *
425
+ * // Consumer only validates what it needs
426
+ * const { app, kafka } = validate({
427
+ * app: { name: String },
428
+ * kafka: { brokers: [String] },
429
+ * });
430
+ *
431
+ * // app.name is typed as string
432
+ * // kafka.brokers is typed as string[]
433
+ * // redis is not accessible - TypeScript error
434
+ * ```
435
+ */
436
+ export declare const createValidator: <C>(config: C, rootName?: string) => <S extends Schema<Partial<C>>>(schema: S) => ExtractShape<C, S>;
374
437
  export {};
package/build/index.js CHANGED
@@ -36,13 +36,25 @@ const MULTIPLIERS = {
36
36
  d: 86400000,
37
37
  w: 604800000
38
38
  };
39
+ const TIME_REGEX = /^(\d*\.?\d*)(ms|s|m|h|d|w)?$/;
39
40
  export const asError = (message)=>new TypeError(message);
40
41
  export const as = {
41
42
  string: (value)=>{
42
43
  return typeof value === 'string' ? value : asError(`Invalid value "${value}", expected a string`);
43
44
  },
44
45
  number: (value)=>{
45
- const result = parseFloat(value);
46
+ if (typeof value !== 'string') {
47
+ return asError(`Invalid value ${value}, expected a valid number`);
48
+ }
49
+ const start = value[0] === '-' || value[0] === '+' ? 1 : 0;
50
+ const c0 = value.charCodeAt(start);
51
+ const c1 = value.charCodeAt(start + 1) | 32;
52
+ if (c0 === 48 && (c1 === 120 || c1 === 111 || c1 === 98)) {
53
+ const result = Number(start ? value.slice(1) : value);
54
+ if (Number.isNaN(result)) return asError(`Invalid value ${value}, expected a valid number`);
55
+ return value[0] === '-' ? -result : result;
56
+ }
57
+ const result = value.includes('.') || value.includes('e') || value.includes('E') ? parseFloat(value) : parseInt(value, 10);
46
58
  return Number.isNaN(result) ? asError(`Invalid value ${value}, expected a valid number`) : result;
47
59
  },
48
60
  date: (value)=>{
@@ -51,12 +63,16 @@ export const as = {
51
63
  return Number.isNaN(date.valueOf()) ? asError(`Invalid value "${value}", expected a valid date format`) : date;
52
64
  },
53
65
  time: (value, conversionFactor = 1)=>{
54
- const matches = value?.match(/^(\d*\.?\d*)(ms|s|m|h|d|w)?$/);
55
- if (matches) {
56
- const [, amount, unit = 'ms'] = matches;
57
- return parseInt(`${parseFloat(amount) * MULTIPLIERS[unit] / conversionFactor}`);
66
+ if (!value) return asError(`Invalid value ${value}, expected a valid time format`);
67
+ const matches = value.match(TIME_REGEX);
68
+ if (!matches) return asError(`Invalid value ${value}, expected a valid time format`);
69
+ const [, amount, unit = 'ms'] = matches;
70
+ const multiplier = MULTIPLIERS[unit];
71
+ const parsed = parseFloat(amount);
72
+ if (!multiplier || Number.isNaN(parsed)) {
73
+ return asError(`Invalid value ${value}, expected a valid time format`);
58
74
  }
59
- return asError(`Invalid value ${value}, expected a valid time format`);
75
+ return Math.floor(parsed * multiplier / conversionFactor);
60
76
  },
61
77
  boolean: (value)=>/^(0|1|true|false|enabled|disabled)$/i.test(value) ? /^(1|true|enabled)$/i.test(value) : asError(`Invalid value ${value}, expected a boolean like`),
62
78
  array: (value, delimiter)=>value?.split?.(delimiter) ?? asError(`Invalid value ${value}, expected an array`),
@@ -77,12 +93,18 @@ export const as = {
77
93
  };
78
94
  class Context {
79
95
  registry = [];
96
+ lookupMap = new Map();
80
97
  varIndex = 0;
81
98
  register(value) {
82
- if (!this.registry.includes(value)) {
83
- this.registry.push(value);
99
+ const index = this.lookupMap.get(value);
100
+ if (index !== undefined) {
101
+ return index;
102
+ }
103
+ {
104
+ const index = this.registry.push(value) - 1;
105
+ this.lookupMap.set(value, index);
106
+ return index;
84
107
  }
85
- return this.registry.indexOf(value);
86
108
  }
87
109
  unique(prefix) {
88
110
  return `${prefix}$$${this.varIndex++}`;
@@ -130,24 +152,34 @@ if (${valueAlias} !== undefined && ${valueAlias} !== null) { ${codeGen(schema.sc
130
152
  codeGenExpectNonNullable(valueAlias, path),
131
153
  codeGenExpectObject(valueAlias, path, 'Array'),
132
154
  codeGenExpectArray(valueAlias, path),
133
- `if (${valueAlias}.length > ${schema.schemas.length}) { throw new TypeError(\`Invalid tuple length \${${valueAlias}.length} for path "${path}", expected ${schema.schemas.length}.\`); }`,
155
+ `if (${valueAlias}.length !== ${schema.schemas.length}) { throw new TypeError(\`Invalid tuple length \${${valueAlias}.length} for path "${path}", expected ${schema.schemas.length}.\`); }`,
134
156
  ...schema.schemas.map((s, idx)=>codeGenCollectErrors(errorsAlias, codeGen(s, context, `${valueAlias}[${idx}]`, `${path}[${idx}]`))),
135
157
  codeGenExpectNoErrors(errorsAlias)
136
158
  ];
137
159
  return code.join('\n');
138
160
  } else if (typeof schema === 'function') {
139
- const index = context.register(schema);
140
161
  const valueAlias = context.unique('v');
141
- const registryAlias = context.unique('r');
142
162
  const code = [
143
163
  `const ${valueAlias} = ${valuePath};`,
144
- `const ${registryAlias} = ctx.registry[${index}];`,
145
164
  codeGenExpectNonNullable(valueAlias, path)
146
165
  ];
147
166
  if (schema !== Error && !(schema?.prototype instanceof Error)) {
148
167
  code.push(codeGenExpectNonError(valueAlias, path));
149
168
  }
150
- code.push(`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}\`); }`, `if (typeof ${valueAlias} !== 'object' && ${valueAlias}?.constructor !== ${registryAlias}) { throw new TypeError(\`Invalid type \${${valueAlias}?.constructor?.name} for path "${path}", expected type ${schema?.name}\`); }`, `if (Number.isNaN(${valueAlias}?.valueOf?.())) { throw new TypeError(\`Invalid value \${${valueAlias}} for path "${path}", expected a valid ${schema?.name}\`); }`);
169
+ const name = schema?.name;
170
+ const primitiveType = name === 'String' ? 'string' : name === 'Number' ? 'number' : name === 'Boolean' ? 'boolean' : name === 'BigInt' ? 'bigint' : name === 'Symbol' ? 'symbol' : null;
171
+ if (primitiveType) {
172
+ code.push(`if (typeof ${valueAlias} !== '${primitiveType}') { throw new TypeError(\`Invalid type \${typeof ${valueAlias}} for path "${path}", expected type ${schema?.name}\`); }`);
173
+ if (primitiveType === 'number') {
174
+ code.push(`if (Number.isNaN(${valueAlias})) { throw new TypeError(\`Invalid value \${${valueAlias}} for path "${path}", expected a valid ${schema?.name}\`); }`);
175
+ }
176
+ } else if (name === 'Function') {
177
+ code.push(`if (typeof ${valueAlias} !== 'function') { throw new TypeError(\`Invalid type \${typeof ${valueAlias}} for path "${path}", expected type Function\`); }`);
178
+ } else {
179
+ const index = context.register(schema);
180
+ const registryAlias = context.unique('r');
181
+ code.push(`const ${registryAlias} = ctx.registry[${index}];`, `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}\`); }`, `if (typeof ${valueAlias} !== 'object' && ${valueAlias}?.constructor !== ${registryAlias}) { throw new TypeError(\`Invalid type \${${valueAlias}?.constructor?.name} for path "${path}", expected type ${schema?.name}\`); }`, `if (Number.isNaN(${valueAlias}?.valueOf?.())) { throw new TypeError(\`Invalid value \${${valueAlias}} for path "${path}", expected a valid ${schema?.name}\`); }`);
182
+ }
151
183
  return code.join('\n');
152
184
  } else if (Array.isArray(schema)) {
153
185
  const valueAlias = context.unique('v');
@@ -163,7 +195,12 @@ if (${valueAlias} !== undefined && ${valueAlias} !== null) { ${codeGen(schema.sc
163
195
  const key = context.unique('key');
164
196
  const errorsAlias = context.unique('err');
165
197
  code.push(`const ${errorsAlias} = [];`);
166
- code.push(...schema.map((s)=>`${valueAlias}.forEach((${value},${key}) => { ${codeGenCollectErrors(errorsAlias, codeGen(s, context, value, `${path}[\${${key}}]`))} });`));
198
+ if (schema.length === 1) {
199
+ code.push(...schema.map((s)=>`for (let ${key} = 0; ${key} < ${valueAlias}.length; ${key}++) { const ${value} = ${valueAlias}[${key}]; ${codeGenCollectErrors(errorsAlias, codeGen(s, context, value, `${path}[\${${key}}]`))} }`));
200
+ } else {
201
+ code.push(`if (${valueAlias}.length > ${schema.length}) { throw new TypeError(\`Invalid tuple length \${${valueAlias}.length} for path "${path}", expected ${schema.length}.\`); }`);
202
+ code.push(...schema.map((s, idx)=>codeGenCollectErrors(errorsAlias, codeGen(s, context, `${valueAlias}[${idx}]`, `${path}[${idx}]`))));
203
+ }
167
204
  code.push(codeGenExpectNoErrors(errorsAlias));
168
205
  }
169
206
  return code.join('\n');
@@ -174,7 +211,7 @@ if (${valueAlias} !== undefined && ${valueAlias} !== null) { ${codeGen(schema.sc
174
211
  const ${valueAlias} = ${valuePath};
175
212
  ${codeGenExpectNonNullable(valueAlias, path)}
176
213
  ${codeGenExpectNonError(valueAlias, path)}
177
- if (!${schema.toString()}.test('' + ${valueAlias})) { throw new TypeError(\`Invalid value \${${valueAlias}} for path "${path}", expected to match ${schema.toString()}\`); }
214
+ if (!${schema.toString()}.test(String(${valueAlias}))) { throw new TypeError(\`Invalid value \${${valueAlias}} for path "${path}", expected to match ${schema.toString()}\`); }
178
215
  `;
179
216
  } else {
180
217
  const valueAlias = context.unique('v');
@@ -191,7 +228,7 @@ if (!${schema.toString()}.test('' + ${valueAlias})) { throw new TypeError(\`Inva
191
228
  code.push(`
192
229
  const ${keysAlias} = Object.keys(${valueAlias});
193
230
  const ${errorsAlias} = [];
194
- ${keysAlias}.forEach(${kAlias} => { ${codeGenCollectErrors(errorsAlias, codeGen(schema[$keys], context, kAlias, `${path}[\${${kAlias}}]`))} });
231
+ for (const ${kAlias} of ${keysAlias}) { ${codeGenCollectErrors(errorsAlias, codeGen(schema[$keys], context, kAlias, `${path}[\${${kAlias}}]`))} }
195
232
  ${codeGenExpectNoErrors(errorsAlias)}
196
233
  `);
197
234
  }
@@ -203,7 +240,7 @@ ${codeGenExpectNoErrors(errorsAlias)}
203
240
  code.push(`
204
241
  const ${entriesAlias} = Object.entries(${valueAlias});
205
242
  const ${errorsAlias} = [];
206
- ${entriesAlias}.forEach(([${kAlias},${vAlias}]) => { ${codeGenCollectErrors(errorsAlias, codeGen(schema[$values], context, vAlias, `${path}[\${${kAlias}}]`))} });
243
+ for (const [${kAlias}, ${vAlias}] of ${entriesAlias}) { ${codeGenCollectErrors(errorsAlias, codeGen(schema[$values], context, vAlias, `${path}[\${${kAlias}}]`))} }
207
244
  ${codeGenExpectNoErrors(errorsAlias)}
208
245
  `);
209
246
  }
@@ -215,7 +252,7 @@ ${codeGenExpectNoErrors(errorsAlias)}
215
252
  code.push(`const ${extraAlias} = Object.keys(${valueAlias}).filter(${kAlias} => !${keysAlias}.has(${kAlias}));`);
216
253
  code.push(`if (${extraAlias}.length !== 0) { throw new TypeError(\`Extra properties: \${${extraAlias}}, are not allowed for path "${path}"\`); }`);
217
254
  }
218
- code.push(...Object.entries(schema).map(([key, s])=>codeGen(s, context, `${valueAlias}['${key}']`, `${path}.${key}`)));
255
+ code.push(...Object.entries(schema).map(([key, s])=>codeGen(s, context, `${valueAlias}[${JSON.stringify(key)}]`, `${path}.${key}`)));
219
256
  return `${code.join('\n')}`;
220
257
  }
221
258
  } else if (typeof schema === 'symbol') {
@@ -255,5 +292,11 @@ export const compile = (schema, rootName)=>{
255
292
  export const ascertain = (schema, data, rootName = '[root]')=>{
256
293
  compile(schema, rootName)(data);
257
294
  };
295
+ export const createValidator = (config, rootName = '[root]')=>{
296
+ return (schema)=>{
297
+ ascertain(schema, config, rootName);
298
+ return config;
299
+ };
300
+ };
258
301
 
259
302
  //# sourceMappingURL=index.js.map