@mmstack/form-validation
Version:
Provides a type-safe, composable, and localizable validation system designed specifically for use with [@mmstack/form-core](https://www.npmjs.com/package/@mmstack/form-core). It enables defining validation rules clearly within your TypeScript code and int
151 lines (150 loc) • 7.14 kB
TypeScript
import { Validator } from '../validator.type';
import { createEmailValidator } from './email';
import { createIsStringValidator } from './is-string';
import { createMaxLengthValidator } from './max-chars';
import { createMinLengthValidator } from './min-chars';
import { createPatternValidator } from './pattern';
import { createTrimmedValidator } from './trimmed';
import { createURIValidator } from './uri';
export type StringMessageFactories = {
email: Parameters<typeof createEmailValidator>[0];
uri: Parameters<typeof createURIValidator>[0];
pattern: Parameters<typeof createPatternValidator>[0];
trimmed: Parameters<typeof createTrimmedValidator>[0];
isString: Parameters<typeof createIsStringValidator>[0];
minLength: Parameters<typeof createMinLengthValidator>[0];
maxLength: Parameters<typeof createMaxLengthValidator>[0];
};
/**
* Configuration options for creating a combined string validator using the `.all()`
* method returned by `createStringValidators` (accessed via `injectValidators().string.all`).
*
* Pass an object of this type to `validators.string.all({...})` to specify which
* string-related validations should be included in the resulting validator function.
* The validation function returned by `.all()` expects an input value of type `string | null`.
*/
export type StringValidatorOptions = {
/**
* If `true`, the string value must not be `null`, `undefined`, or an empty string (`''`).
* Uses the configured 'required' validation message.
* Note: This behavior (checking for empty string) might differ from a generic `required`
* check on other types.
* @see Validators.general.required
* @example { required: true }
*/
required?: boolean;
/**
* Specifies the minimum allowed length of the string (inclusive).
* Validation fails if `value.length < minLength`.
* Note: Behavior with leading/trailing whitespace depends on whether `trimmed` is also used
* or if the underlying implementation trims by default. Assumed to operate on raw length unless specified otherwise.
* Uses the configured 'minLength' validation message.
* @example { minLength: 3 } // Must be at least 3 characters long
* @see Validators.string.minLength
*/
minLength?: number;
/**
* Specifies the maximum allowed length of the string (inclusive).
* Validation fails if `value.length > maxLength`.
* Uses the configured 'maxLength' validation message.
* @example { maxLength: 50 } // Cannot exceed 50 characters
* @see Validators.string.maxLength
*/
maxLength?: number;
/**
* If `true`, the string value must not have leading or trailing whitespace.
* Validation fails if `value !== value.trim()`.
* Uses the configured 'trimmed' validation message.
* @example { trimmed: true } // Value like " test " would be invalid
* @see Validators.string.trimmed
*/
trimmed?: boolean;
/**
* Requires the string to match a specific pattern. Accepts:
* - A `RegExp` object for custom patterns (e.g., `/^[a-z]+$/i`).
* - The string literal `'email'` to use a built-in email format validator.
* - The string literal `'uri'` to use a built-in URI/URL format validator.
* - Potentially other string representations of regex patterns (implementation dependent).
* Uses the configured 'pattern', 'email', or 'uri' validation message.
* @example { pattern: /^\d{3}-\d{2}-\d{4}$/ } // SSN format
* @example { pattern: 'email' } // Standard email format
* @example { pattern: 'uri' } // Standard URI format
* @see Validators.string.pattern
* @see Validators.string.email
* @see Validators.string.uri
*/
pattern?: RegExp | 'email' | 'uri' | Omit<string, 'email' | 'uri'>;
/**
* The string value must be exactly equal to the specified string (or `null`).
* Case-sensitive comparison.
* Uses the configured `mustBe` validation message.
* @example { mustBe: "CONFIRMED" }
* @example { mustBe: null }
* @see Validators.general.mustBe
* @see Validators.general.mustBeNull
*/
mustBe?: string | null;
/**
* The string value must *not* be equal to the specified string (or `null`).
* Case-sensitive comparison.
* Uses the configured `not` validation message.
* @example { not: "password" } // Cannot be the literal string "password"
* @see Validators.general.not
*/
not?: string | null;
/**
* The string value must be one of the strings (or `null`) included in the specified array.
* Case-sensitive comparison.
* Uses the configured `oneOf` validation message.
* @example { oneOf: ["PENDING", "APPROVED", "REJECTED", null] }
* @see Validators.general.oneOf
*/
oneOf?: (string | null)[];
/**
* The string value must *not* be any of the strings (or `null`) included in the specified array.
* Case-sensitive comparison.
* Uses the configured `notOneOf` validation message.
* @example { notOneOf: ["admin", "root"] }
* @see Validators.general.notOneOf
*/
notOneOf?: (string | null)[];
/**
* Optional configuration passed down to specific message factories.
* Primarily used by the `required` validator's message factory.
*/
messageOptions?: {
/**
* An optional label for the field (e.g., 'Username', 'Email Address')
* which can be incorporated into the 'required' error message by its factory.
* @example { required: true, messageOptions: { label: 'Email Address' } } // Error might be "Email Address is required"
*/
label?: string;
};
};
export declare function createStringValidators(factories?: Partial<StringMessageFactories>, generalValidators?: {
required: <T>(label?: string) => Validator<T>;
mustBe: <T>(value: T, valueLabel?: string, matcher?: (a: T, b: T) => boolean) => Validator<T>;
mustBeNull: <T>() => Validator<T>;
not: <T>(value: T, valueLabel?: string, matcher?: (a: T, b: T) => boolean) => Validator<T>;
oneOf: <T>(values: T[], toLabel?: (value: T) => string, identity?: (a: T) => string, delimiter?: string) => Validator<T>;
notOneOf: <T>(values: T[], toLabel?: (value: T) => string, identity?: (a: T) => string, delimiter?: string) => Validator<T>;
}, merger?: <T>(validators: Validator<T>[]) => ((value: T) => string) & {
resolve: (mergedError: string) => {
error: string;
tooltip: string;
};
}): {
all: (opt: StringValidatorOptions) => ((value: string | null) => string) & {
resolve: (mergedError: string) => {
error: string;
tooltip: string;
};
};
email: () => Validator<string | null>;
uri: () => Validator<string | null>;
pattern: (pattern: string | RegExp) => Validator<string | null>;
trimmed: () => Validator<string | null>;
isString: () => Validator<string | null>;
minLength: (min: number) => Validator<string | null>;
maxLength: (max: number) => Validator<string | null>;
};