UNPKG

snap-validate

Version:

Zero-dependency, ~4KB validation library for common patterns. CJS + ESM, Standard Schema support, no TypeScript compiler required.

365 lines (311 loc) 10 kB
declare module 'snap-validate' { /** * Standard Schema v1 (https://standardschema.dev), vendored per the spec's * recommendation so snap-validate stays zero-dependency. Tools like tRPC, * TanStack Form, and Hono consume schemas through this interface. */ export interface StandardSchemaV1<Input = unknown, Output = Input> { readonly '~standard': StandardSchemaV1.Props<Input, Output>; } export namespace StandardSchemaV1 { export interface Props<Input = unknown, Output = Input> { readonly version: 1; readonly vendor: string; readonly validate: ( value: unknown ) => Result<Output> | Promise<Result<Output>>; readonly types?: Types<Input, Output> | undefined; } export type Result<Output> = SuccessResult<Output> | FailureResult; export interface SuccessResult<Output> { readonly value: Output; readonly issues?: undefined; } export interface FailureResult { readonly issues: ReadonlyArray<Issue>; } export interface Issue { readonly message: string; readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined; } export interface PathSegment { readonly key: PropertyKey; } export interface Types<Input = unknown, Output = Input> { readonly input: Input; readonly output: Output; } export type InferInput<Schema extends StandardSchemaV1> = NonNullable< Schema['~standard']['types'] >['input']; export type InferOutput<Schema extends StandardSchemaV1> = NonNullable< Schema['~standard']['types'] >['output']; } /** * Result of a validation operation */ export class ValidationResult { constructor(isValid: boolean, errors?: string[]); isValid: boolean; errors: string[]; addError(message: string): ValidationResult; } /** * Password validation options */ export interface PasswordOptions { minLength?: number; requireUppercase?: boolean; requireLowercase?: boolean; requireNumbers?: boolean; requireSpecialChars?: boolean; } /** * Phone number format types */ export type PhoneFormat = 'us' | 'international' | 'simple'; /** * Country codes for zip code validation */ export type CountryCode = 'us' | 'ca' | 'uk'; /** * Custom validation function that returns boolean, an error string, or a * ValidationResult */ export type CustomValidatorFunction = ( value: any ) => boolean | string | ValidationResult; /** * Async custom validation function */ export type AsyncValidatorFunction = ( value: any ) => Promise<boolean | string | ValidationResult>; /** * Value transform/sanitize function used by transform() */ export type TransformFunction = (value: any) => any; /** * Conditional validation condition */ export type ConditionalFunction = (value: any) => boolean; /** * Conditional validator function */ export type ConditionalValidatorFunction = (value: any) => BaseValidator; /** * Base validator class with chainable validation methods */ export class BaseValidator { constructor(value: any); value: any; rules: Array<() => ValidationResult>; asyncRules: Array<() => Promise<ValidationResult>>; isOptional: boolean; /** * @deprecated No-op. A timer cannot interrupt a synchronous regex on a * single thread, so this value is ignored. Retained for compatibility. */ regexTimeout: number; /** * Set the field name used to prefix contextual error messages */ setFieldName(name: string): BaseValidator; /** * Make field required */ required(message?: string): BaseValidator; /** * Make field optional (skips validation if empty) */ optional(): BaseValidator; /** * @deprecated No-op, retained for backward compatibility and chainability. * Regex execution cannot be interrupted by a timeout on a single thread, so * this setting is ignored. */ setRegexTimeout(timeoutMs: number): BaseValidator; /** * Transform/sanitize the value before subsequent rules run */ transform(fn: TransformFunction, errorMessage?: string): BaseValidator; /** * Require the value to strictly equal compareValue */ equals(compareValue: any, message?: string): BaseValidator; /** * Require the value to be one of the allowed values */ oneOf(allowedValues: any[], message?: string): BaseValidator; /** * Require a numeric value between min and max (inclusive) */ between(min: number, max: number, message?: string): BaseValidator; /** * Set minimum length (string/array) or minimum value (number) */ min(length: number, message?: string): BaseValidator; /** * Set maximum length (string/array) or maximum value (number) */ max(length: number, message?: string): BaseValidator; /** * Require the value to be an array */ array(message?: string): BaseValidator; /** * Validate each item of an array (synchronous) */ arrayOf( validator: BaseValidator | ValidationFunction, message?: string ): BaseValidator; /** * Validate each item of an array (asynchronous) */ arrayOfAsync( validator: BaseValidator | ValidationFunction, message?: string ): BaseValidator; /** * Validate a nested object against a schema (synchronous) */ object(schema: Schema, message?: string): BaseValidator; /** * Validate a nested object against a schema (asynchronous) */ objectAsync(schema: Schema, message?: string): BaseValidator; /** * Validate against regex pattern (synchronous) */ pattern(regex: RegExp, message?: string): BaseValidator; /** * Validate against a regex pattern (asynchronous). Input-length and * static-safety guards apply; there is no runtime timeout interruption * (impossible for synchronous regex execution). */ patternAsync(regex: RegExp, message?: string): BaseValidator; /** * Conditional validation */ when( condition: boolean | ConditionalFunction, validator: BaseValidator | ConditionalValidatorFunction ): BaseValidator; /** * Custom synchronous validation */ custom( validatorFn: CustomValidatorFunction, message?: string ): BaseValidator; /** * Custom asynchronous validation */ customAsync( validatorFn: AsyncValidatorFunction, message?: string ): BaseValidator; /** * Standard Schema v1 interface (https://standardschema.dev). Rebinds this * instance's value on each validate() call: safe for sequential reuse, * but use toStandardSchema() for concurrent async validation. */ readonly '~standard': StandardSchemaV1.Props<unknown, unknown>; /** * Execute synchronous validation */ validate(): ValidationResult; /** * Execute asynchronous validation (includes sync rules) */ validateAsync(): Promise<ValidationResult>; } /** * Predefined validators */ export interface Validators { email(value: string): BaseValidator; phone(value: string, format?: PhoneFormat): BaseValidator; creditCard(value: string): BaseValidator; url(value: string): BaseValidator; password(value: string, options?: PasswordOptions): BaseValidator; alphanumeric(value: string): BaseValidator; numeric(value: string): BaseValidator; zipCode(value: string, country?: CountryCode): BaseValidator; } /** * Result of schema validation */ export interface SchemaValidationResult { isValid: boolean; errors: { [field: string]: ValidationResult }; getErrors(): { [field: string]: string[] }; } /** * Validation function type for schema */ export type ValidationFunction = (value: any) => BaseValidator; /** * Schema definition type */ export type Schema = { [field: string]: ValidationFunction | BaseValidator }; /** * Predefined validator instances */ export const validators: Validators; /** * Validate data against schema synchronously */ export function validate( schema: Schema, data: { [key: string]: any } ): SchemaValidationResult; /** * Validate data against schema asynchronously */ export function validateAsync( schema: Schema, data: { [key: string]: any } ): Promise<SchemaValidationResult>; /** * Safely test a regex asynchronously. Applies an input-length cap and the * isRegexSafe static heuristic, then runs the match. Returns a Promise. * * Note: there is NO runtime timeout interruption - a timer cannot stop a * synchronous regex on a single thread. * * @param timeoutMs @deprecated Ignored; retained for backward compatibility. */ export function safeRegexTest( regex: RegExp, str: string, timeoutMs?: number ): Promise<boolean>; /** * Safely test regex with input length protection (synchronous) */ export function safeRegexTestSync( regex: RegExp, str: string, maxLength?: number ): boolean; /** * Check if a regex pattern is safe (best-effort static heuristic) */ export function isRegexSafe(regex: RegExp): boolean; /** * Convert a snap-validate validator factory or schema object into a * reusable Standard Schema v1 (https://standardschema.dev), consumable by * tRPC, TanStack Form, Hono, and other Standard Schema tools. * * - Pass a factory `(value) => BaseValidator` for a single-value schema. * - Pass a snap-validate Schema object for object validation; issues carry * a `path` of [fieldName], and the success value is a shallow copy of the * input with transform()ed field values applied. */ export function toStandardSchema( input: ValidationFunction | Schema ): StandardSchemaV1<unknown, unknown>; }