@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
912 lines (876 loc) • 32.2 kB
JavaScript
import { InjectionToken, LOCALE_ID, inject } from '@angular/core';
import { formatDate } from '@angular/common';
const INTERNAL_ERROR_MERGE_DELIM = '::INTERNAL_MMSTACK_MERGE_DELIM::';
function defaultMergeMessage(errors) {
const first = errors.at(0);
if (!first)
return {
error: '',
tooltip: '',
};
if (errors.length === 1) {
if (first.length > 60) {
return {
error: `${first.slice(0, 60)}...`,
tooltip: first,
};
}
return {
error: first,
tooltip: '',
};
}
if (first.length > 40) {
return {
error: `${first.slice(0, 40)}..., +${errors.length - 1} issues`,
tooltip: errors.join('\n'),
};
}
return {
error: `${first}, +${errors.length - 1} issues`,
tooltip: errors.join('\n'),
};
}
function toTooltipFn(merge) {
return (errors) => {
const result = merge(errors);
if (typeof result === 'string') {
return {
error: result,
tooltip: '',
merged: errors.join(INTERNAL_ERROR_MERGE_DELIM),
};
}
return result;
};
}
function mergeValidators(...validators) {
if (!validators.length)
return () => [];
return (value) => validators.map((val) => val(value)).filter(Boolean);
}
function createMergeValidators(merge) {
const mergeFn = merge ? toTooltipFn(merge) : defaultMergeMessage;
return (validators) => {
const validate = mergeValidators(...validators);
const fn = ((value) => validate(value).join(INTERNAL_ERROR_MERGE_DELIM));
fn.resolve = (mergedError) => {
return mergeFn(mergedError.split(INTERNAL_ERROR_MERGE_DELIM));
};
return fn;
};
}
function defaultMaxLengthMessageFactory$1(max, elementsLabel) {
return `Max ${max} ${elementsLabel}`;
}
function createMaxLengthValidator$1(createMsg) {
return (max, elementsLabel = 'items') => {
const msg = createMsg(max, elementsLabel);
return (value) => {
const length = value?.length ?? 0;
if (length > max)
return msg;
return '';
};
};
}
function defaultMinLengthMessageFactory$1(min, elementsLabel) {
return `Min ${min} ${elementsLabel}`;
}
function createMinLengthValidator$1(createMsg) {
return (min, elementsLabel = 'items') => {
const msg = createMsg(min, elementsLabel);
return (value) => {
const length = value?.length ?? 0;
if (length < min)
return msg;
return '';
};
};
}
const DEFAULT_MESSAGES$4 = {
minLength: defaultMinLengthMessageFactory$1,
maxLength: defaultMaxLengthMessageFactory$1,
};
function createArrayValidators(factories, merger = createMergeValidators()) {
const t = { ...DEFAULT_MESSAGES$4, ...factories };
const base = {
minLength: createMinLengthValidator$1(t.minLength),
maxLength: createMaxLengthValidator$1(t.maxLength),
};
return {
...base,
all: (opt) => {
const validators = [];
if (opt.minLength !== undefined)
validators.push(base.minLength(opt.minLength, opt.elementsLabel));
if (opt.maxLength !== undefined)
validators.push(base.maxLength(opt.maxLength, opt.elementsLabel));
return merger(validators);
},
};
}
function defaultMustBeTreFactory() {
return `Must be true`;
}
function createMustBeTrueValidator(createMsg) {
return () => {
const msg = createMsg();
return (value) => {
if (value !== true)
return msg;
return '';
};
};
}
const DEFAULT_MESSAGES$3 = {
mustBeTrue: defaultMustBeTreFactory,
};
function createBooleanValidators(factories) {
const t = { ...DEFAULT_MESSAGES$3, ...factories };
return {
mustBeTrue: createMustBeTrueValidator(t.mustBeTrue),
};
}
function defaultMustBeMessageFactory(valueLabel) {
return `Must be ${valueLabel}`;
}
function createMustBeValidator(createMessage) {
return (value, valueLabel = `${value}`, matcher = Object.is) => {
const msg = createMessage(valueLabel);
return (currentValue) => {
if (!matcher(value, currentValue))
return msg;
return '';
};
};
}
function defaultMustBeEmptyMessageFactory() {
return defaultMustBeMessageFactory('empty');
}
function createMustBeEmptyValidator(createMessage) {
return () => createMustBeValidator(createMessage)(null);
}
function defaultNotMessageFactory(valueLabel) {
return `Cannot be ${valueLabel}`;
}
function createNotValidator(createMessage) {
return (value, valueLabel = `${value}`, matcher = Object.is) => {
const msg = createMessage(valueLabel);
return (currentValue) => {
if (matcher(value, currentValue))
return msg;
return '';
};
};
}
function defaultNotOneOfMessageFactory(values) {
return `Cannot be one of: ${values}`;
}
function defaultToLabel$1(value) {
return `${value}`;
}
function createNotOneOfValidator(createMessage) {
return (values, toLabel = defaultToLabel$1, identity = defaultToLabel$1, delimiter = ', ') => {
const valuesLabel = values.map(toLabel).join(delimiter);
const msg = createMessage(valuesLabel);
const map = new Map(values.map((v) => [identity(v), v]));
return (currentValue) => {
if (map.has(identity(currentValue)))
return msg;
return '';
};
};
}
function defaultOneOfMessageFactory(values) {
return `Must be one of: ${values}`;
}
function defaultToLabel(value) {
return `${value}`;
}
function createOneOfValidator(createMessage) {
return (values, toLabel = defaultToLabel, identity = defaultToLabel, delimiter = ', ') => {
const valuesLabel = values.map(toLabel).join(delimiter);
const msg = createMessage(valuesLabel);
const map = new Map(values.map((v) => [identity(v), v]));
return (currentValue) => {
if (!map.has(identity(currentValue)))
return msg;
return '';
};
};
}
function defaultRequiredMessageFactory(label = 'Field') {
return `${label} is required`;
}
function requiredNumber(value) {
return value !== null && value !== undefined;
}
function createRequiredValidator(createMsg) {
return (label = 'Field') => {
const msg = createMsg(label);
return (value) => {
if (typeof value === 'number' && !requiredNumber(value))
return msg;
if (!value)
return msg;
return '';
};
};
}
const DEFAULT_MESSAGES$2 = {
required: defaultRequiredMessageFactory,
mustBe: defaultMustBeMessageFactory,
mustBeNull: defaultMustBeEmptyMessageFactory,
not: defaultNotMessageFactory,
oneOf: defaultOneOfMessageFactory,
notOneOf: defaultNotOneOfMessageFactory,
};
/**
* Represents the consolidated object containing all available validator generators,
* configured with appropriate localization and date handling for the specified `TDate` type.
*
* Obtain this object using `injectValidators()` within an Angular injection context.
* Use the nested `.all()` methods (e.g., `validators.string.all({...})`) with their
* corresponding options types (e.g., `StringValidatorOptions`) to create combined
* validator functions for your form controls.
*
* Individual validators (e.g., `validators.general.required()`) are also available.
*
* @template TDate The type used for date values (e.g., Date, Luxon DateTime). Defaults to `Date`.
*/
function createGeneralValidators(factories) {
const t = { ...DEFAULT_MESSAGES$2, ...factories };
const mustBeNull = createMustBeEmptyValidator(t.mustBeNull);
return {
required: createRequiredValidator(t.required),
mustBe: createMustBeValidator(t.mustBe),
mustBeNull: createMustBeEmptyValidator(t.mustBeNull),
not: createNotValidator(t.not),
oneOf: (values, toLabel, identity, delimiter) => {
if (!values.length)
return mustBeNull();
return createOneOfValidator(t.oneOf)(values, toLabel, identity, delimiter);
},
notOneOf: createNotOneOfValidator(t.notOneOf),
};
}
function defaultIsDateMessageFactory() {
return `Must be a valid date`;
}
function createIsDateValidator(createMsg, toDate) {
const msg = createMsg();
return () => {
return (value) => {
if (value === null)
return '';
const date = toDate(value);
if (isNaN(date.getTime()))
return msg;
return '';
};
};
}
function defaultMaxDateMessageFactory(dateLabel) {
return `Must be before ${dateLabel}`;
}
function createMaxDateValidator(createMsg, toDate, formatDate, locale) {
return (date) => {
const d = toDate(date);
const matchTime = d.getTime();
const msg = createMsg(formatDate(d, locale));
return (value) => {
if (value === null)
return '';
if (toDate(value).getTime() > matchTime)
return msg;
return '';
};
};
}
function defaultMinDateMessageFactory(dateLabel) {
return `Must be after ${dateLabel}`;
}
function createMinDateValidator(createMsg, toDate, formatDate, locale) {
return (date) => {
const d = toDate(date);
const matchTime = d.getTime();
const msg = createMsg(formatDate(d, locale));
return (value) => {
if (value === null)
return '';
if (toDate(value).getTime() < matchTime)
return msg;
return '';
};
};
}
function isLuxonLike(date) {
if (!date)
return false;
return ('toJSDate' in date &&
'toUnixInteger' in date &&
typeof date.toJSDate === 'function' &&
typeof date.toUnixInteger === 'function');
}
function isMomentLike(date) {
if (!date)
return false;
return ('toDate' in date &&
'unix' in date &&
typeof date.toDate === 'function' &&
typeof date.unix === 'function');
}
function defaultToDate(date) {
if (date instanceof Date)
return date;
if (typeof date === 'string' || typeof date === 'number')
return new Date(date);
if (!date)
return new Date();
if (typeof date !== 'object')
throw new Error('Date is not number, string, null, undefined or object');
if (isMomentLike(date))
return date.toDate();
if (isLuxonLike(date))
return date.toJSDate();
return new Date();
}
function defaultFormatDate(date, locale, format = 'mediumDate') {
return formatDate(date, format, locale);
}
const DEFAULT_DATE_MESSAGES = {
min: defaultMinDateMessageFactory,
max: defaultMaxDateMessageFactory,
isDate: defaultIsDateMessageFactory,
};
function createDateValidators(factories, toDate = (defaultToDate), formatDate = defaultFormatDate, locale = 'en-US', generalValidators = createGeneralValidators(), merger = createMergeValidators()) {
const t = { ...DEFAULT_DATE_MESSAGES, ...factories };
const base = {
min: createMinDateValidator(t.min, toDate, formatDate, locale),
max: createMaxDateValidator(t.max, toDate, formatDate, locale),
isDate: createIsDateValidator(t.isDate, toDate),
};
const toLabel = (d) => d ? formatDate(toDate(d), locale) : 'null';
return {
...base,
all: (opt) => {
const validators = [];
if (opt.required)
validators.push(generalValidators.required(opt.messageOptions?.label));
validators.push(base.isDate());
if (opt.mustBe !== undefined) {
if (opt.mustBe === null)
validators.push(generalValidators.mustBeNull());
else {
const d = toDate(opt.mustBe);
const formatted = formatDate(d, locale);
validators.push(generalValidators.mustBe(d, formatted, (a, b) => {
if (!a && !b)
return true;
if (!a || !b)
return false;
return toDate(a).getTime() === toDate(b).getTime();
}));
}
}
if (opt.not !== undefined) {
if (opt.not === null)
validators.push(generalValidators.not(null));
else {
const d = toDate(opt.not);
const formatted = formatDate(d, locale);
validators.push(generalValidators.not(d, formatted, (a, b) => {
if (!a && !b)
return true;
if (!a || !b)
return false;
return toDate(a).getTime() === toDate(b).getTime();
}));
}
}
if (opt.min !== undefined)
validators.push(base.min(opt.min));
if (opt.max !== undefined)
validators.push(base.max(opt.max));
if (opt.oneOf) {
const dates = opt.oneOf.map((d) => (d ? toDate(d) : null));
validators.push(generalValidators.oneOf(dates, toLabel, (a) => a === null || a === undefined
? 'null'
: toDate(a).getTime().toString()));
}
if (opt.notOneOf) {
const dates = opt.notOneOf.map((d) => (d ? toDate(d) : null));
validators.push(generalValidators.notOneOf(dates, toLabel, (a) => a === null || a === undefined
? 'null'
: toDate(a).getTime().toString()));
}
return merger(validators);
},
util: {
toDate,
formatDate,
},
};
}
function createDateRangeValidators(factories, toDate = (defaultToDate), formatDate = defaultFormatDate, locale = 'en-US', generalValidators = createGeneralValidators(), merger = createMergeValidators()) {
const t = { ...DEFAULT_DATE_MESSAGES, ...factories };
const base = {
min: createMinDateValidator(t.min, toDate, formatDate, locale),
max: createMaxDateValidator(t.max, toDate, formatDate, locale),
isDate: createIsDateValidator(t.isDate, toDate),
};
return {
...base,
all: (opt) => {
const validators = [];
if (opt.required) {
const val = generalValidators.required(opt.messageOptions?.label);
validators.push((value) => val(value.start) || val(value.end));
}
const isDateValidator = base.isDate();
validators.push((value) => isDateValidator(value.start) || isDateValidator(value.end));
if (opt.min !== undefined) {
const minVal = base.min(opt.min);
validators.push((value) => minVal(value.start));
}
if (opt.max !== undefined) {
const maxVal = base.max(opt.max);
validators.push((value) => maxVal(value.end));
}
validators.push((value) => {
if (value.start === null || value.end === null)
return '';
const minVal = base.min(value.start);
const maxVal = base.max(value.end);
return minVal(value.end) || maxVal(value.start);
});
return merger(validators);
},
util: {
toDate,
formatDate,
},
};
}
function defaultIntegerMessageFactory() {
return `Must be an integer`;
}
function createIntegerValidator(createMsg) {
return () => {
const msg = createMsg();
return (value) => {
if (value === null)
return '';
if (!Number.isInteger(value))
return msg;
return '';
};
};
}
function defaultIsNumberMessageFactory() {
return `Must be a number`;
}
function createIsNumberValidator(createMsg) {
return () => {
const msg = createMsg();
return (value) => {
if (value === null)
return '';
if (typeof value !== 'number' || isNaN(value))
return msg;
return '';
};
};
}
function defaultMaxMessageFactory(max) {
return `Must be at most ${max}`;
}
function createMaxValidator(createMsg) {
return (max) => {
const msg = createMsg(max);
return (value) => {
if (value === null)
return '';
if (value > max)
return msg;
return '';
};
};
}
function defaultMinMessageFactory(min) {
return `Must be at least ${min}`;
}
function createMinValidator(createMsg) {
return (min) => {
const msg = createMsg(min);
return (value) => {
if (value === null)
return '';
if (value < min)
return msg;
return '';
};
};
}
function defaultMultipleOfMessageFactory(multipleOf) {
return `Must be a multiple of ${multipleOf}`;
}
function createMultipleOfValidator(createMsg) {
return (multipleOf) => {
const msg = createMsg(multipleOf);
return (value) => {
if (value === null)
return '';
if (value % multipleOf !== 0)
return msg;
return '';
};
};
}
const DEFAULT_MESSAGES$1 = {
min: defaultMinMessageFactory,
max: defaultMaxMessageFactory,
isNumber: defaultIsNumberMessageFactory,
multipleOf: defaultMultipleOfMessageFactory,
integer: defaultIntegerMessageFactory,
};
function createNumberValidators(factories, generalValidators = createGeneralValidators(), merger = createMergeValidators()) {
const t = { ...DEFAULT_MESSAGES$1, ...factories };
const base = {
min: createMinValidator(t.min),
max: createMaxValidator(t.max),
isNumber: createIsNumberValidator(t.isNumber),
multipleOf: createMultipleOfValidator(t.multipleOf),
integer: createIntegerValidator(t.integer),
};
return {
...base,
all: (opt) => {
const validators = [];
if (opt.required)
validators.push(generalValidators.required(opt.messageOptions?.label));
validators.push(base.isNumber());
if (opt.mustBe !== undefined)
validators.push(generalValidators.mustBe(opt.mustBe));
if (opt.not !== undefined)
validators.push(generalValidators.not(opt.not));
if (opt.integer)
validators.push(base.integer());
if (opt.min !== undefined)
validators.push(base.min(opt.min));
if (opt.max !== undefined)
validators.push(base.max(opt.max));
if (opt.multipleOf !== undefined)
validators.push(base.multipleOf(opt.multipleOf));
if (opt.oneOf)
validators.push(generalValidators.oneOf(opt.oneOf));
if (opt.notOneOf)
validators.push(generalValidators.notOneOf(opt.notOneOf));
return merger(validators);
},
};
}
const EMAIL_REGEXP = /^(?=.{1,254}$)(?=.{1,64}@)[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
function defaultEmailMessageFactory() {
return `Must be a valid email`;
}
function createEmailValidator(createMsg) {
return () => {
const msg = createMsg();
return (value) => {
if (value === null)
return '';
if (!EMAIL_REGEXP.test(value))
return msg;
return '';
};
};
}
function defaultIsStringMessageFactory() {
return `Must be a string`;
}
function createIsStringValidator(createMsg) {
return () => {
const msg = createMsg();
return (value) => {
if (value === null)
return '';
if (typeof value !== 'string')
return msg;
return '';
};
};
}
function defaultMaxLengthMessageFactory(max) {
return defaultMaxLengthMessageFactory$1(max, 'characters');
}
function createMaxLengthValidator(createMsg) {
return createMaxLengthValidator$1((max) => createMsg(max));
}
function defaultMinLengthMessageFactory(min) {
return defaultMinLengthMessageFactory$1(min, 'characters');
}
function createMinLengthValidator(createMsg) {
return createMinLengthValidator$1((min) => createMsg(min));
}
function defaultPatternMessageFactory(patternLabel) {
return `Must match pattern ${patternLabel}`;
}
function createPatternValidator(createMsg) {
return (pattern) => {
const regex = new RegExp(pattern);
const msg = createMsg(regex.source);
return (value) => {
if (value === null)
return '';
if (!regex.test(value))
return msg;
return '';
};
};
}
function defaultTrimmedMessageFactory() {
return `Cannot contain leading or trailing whitespace`;
}
function createTrimmedValidator(createMsg) {
return () => {
const msg = createMsg();
return (value) => {
if (value === null)
return '';
if (value.trim().length !== value.length)
return msg;
return '';
};
};
}
const URI_REGEXP = /^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$/;
function defaultURIMessageFactory() {
return `Must be a valid URI`;
}
function createURIValidator(createMsg) {
return () => {
const msg = createMsg();
return (value) => {
if (value === null)
return '';
if (!URI_REGEXP.test(value))
return msg;
return '';
};
};
}
const DEFAULT_MESSAGES = {
email: defaultEmailMessageFactory,
uri: defaultURIMessageFactory,
pattern: defaultPatternMessageFactory,
trimmed: defaultTrimmedMessageFactory,
isString: defaultIsStringMessageFactory,
minLength: defaultMinLengthMessageFactory,
maxLength: defaultMaxLengthMessageFactory,
};
function createStringValidators(factories, generalValidators = createGeneralValidators(), merger = createMergeValidators()) {
const t = { ...DEFAULT_MESSAGES, ...factories };
const base = {
email: createEmailValidator(t.email),
uri: createURIValidator(t.uri),
pattern: createPatternValidator(t.pattern),
trimmed: createTrimmedValidator(t.trimmed),
isString: createIsStringValidator(t.isString),
minLength: createMinLengthValidator(t.minLength),
maxLength: createMaxLengthValidator(t.maxLength),
};
return {
...base,
all: (opt) => {
const validators = [];
if (opt.required)
validators.push(generalValidators.required(opt?.messageOptions?.label));
validators.push(base.isString());
if (opt.mustBe !== undefined)
validators.push(generalValidators.mustBe(opt.mustBe));
if (opt.not !== undefined)
validators.push(generalValidators.not(opt.not));
if (opt.trimmed)
validators.push(base.trimmed());
if (opt.minLength !== undefined)
validators.push(base.minLength(opt.minLength));
if (opt.maxLength)
validators.push(base.maxLength(opt.maxLength));
if (opt.pattern) {
switch (opt.pattern) {
case 'email':
validators.push(base.email());
break;
case 'uri':
validators.push(base.uri());
break;
default:
validators.push(base.pattern(opt.pattern));
break;
}
}
if (opt.oneOf)
validators.push(generalValidators.oneOf(opt.oneOf));
if (opt.notOneOf)
validators.push(generalValidators.notOneOf(opt.notOneOf));
return merger(validators);
},
};
}
const token = new InjectionToken('INTERNAL_MMSTACK_VALIDATORS');
let defaultValidators = null;
function createDefaultValidators() {
if (!defaultValidators) {
defaultValidators = createValidators({}, defaultToDate, defaultFormatDate, 'en-US');
}
return defaultValidators;
}
function createValidators(msg, toDate, formatDate, locale) {
const general = createGeneralValidators(msg?.general);
const merger = createMergeValidators(msg?.merge);
return {
general,
string: createStringValidators(msg?.string, general, merger),
number: createNumberValidators(msg?.number, general, merger),
date: createDateValidators(msg?.date, toDate, formatDate, locale, general, merger),
dateRange: createDateRangeValidators(msg?.date, toDate, formatDate, locale, general, merger),
array: createArrayValidators(msg?.array, merger),
boolean: createBooleanValidators(msg?.boolean),
};
}
/**
* Provides the configuration for the @mmstack/form-validation system within Angular's DI.
*
* Include the returned provider in your application's root providers (e.g., in `app.config.ts`)
* or relevant feature/route providers to enable localization of validation error messages
* and configure custom date handling.
*
* It automatically uses Angular's `LOCALE_ID` to determine which message factories to apply.
*
* @template TDate - The type used for date values throughout your application
* (e.g., `Date`, Luxon `DateTime`, Moment). Defaults to `Date`. This generic ensures
* type safety when providing custom `toDate` and `formatDate` functions.
* @param messageFactoryProvider - A function that receives the current `LOCALE_ID` string
* (e.g., 'en-US', 'de-DE') and should return an object containing optional custom
* message factory functions for various validator types (`general`, `string`, `number`, `date`, `array`, `boolean`).
* Only provide factories for the messages you want to override for that specific locale;
* defaults will be used for any unspecified factories. Return `undefined` or an empty
* object to use default messages for the locale.
* @param toDate - Optional function to convert input values (of type `TDate` or `string`)
* into standard JavaScript `Date` objects. This is used internally by date validators
* for comparisons. Defaults to a helper supporting `Date`, `string`, `number`, and
* common date library objects (Luxon, Moment).
* **Provide this function if your application uses a date type other than native `Date`**.
* @param formatDate - Optional function to format a `Date` object into a string suitable
* for display in date-related error messages (e.g., min/max date errors), respecting
* the provided `locale`. Defaults to using Angular's `formatDate` with 'mediumDate' format.
* @returns An Angular `Provider` configuration object to be added to your providers array.
*
* @example
* // In app.config.ts
* import { ApplicationConfig } from '@angular/core';
* import { provideValidatorConfig } from '@mmstack/form-validation';
* // If using a custom date type like Luxon's DateTime
* // import { DateTime } from 'luxon';
* // import { defaultToDate } from '@mmstack/form-validation'; // Or your custom util path
*
* export const appConfig: ApplicationConfig = {
* providers: [
* provideValidatorConfig((locale): Partial<MessageFactories> | void => {
* console.log('Configuring validators for locale:', locale);
* if (locale.startsWith('de')) { // Example for German
* return {
* general: { required: (label = 'Feld') => `${label} ist erforderlich.` },
* string: { minLength: (min) => `Mindestens ${min} Zeichen.` }
* // Only provide overrides needed for this locale
* };
* }
* // Return undefined or {} to use default messages for other locales
* })
*
* // Example if using Luxon DateTime:
* // provideValidatorConfig<DateTime>(
* // (locale) => { ... }, // your message factories
* // // Custom toDate function for Luxon
* // (d) => (d instanceof DateTime ? d.toJSDate() : defaultToDate(d)),
* // // Custom formatDate function for Luxon
* // (d, l) => DateTime.fromJSDate(d).setLocale(l).toLocaleString(DateTime.DATE_MED)
* // )
* ]
* };
*/
function provideValidatorConfig(factory, toDate = (defaultToDate), formatDate = defaultFormatDate) {
return {
provide: token,
useFactory: (locale) => createValidators(factory(locale), toDate, formatDate, locale),
deps: [LOCALE_ID],
};
}
/**
* Injects the configured `Validators` object within an Angular injection context.
*
* This function is the standard way to access the validation functions
* (e.g., `validators.string.all`, `validators.number.min`) inside your Angular
* components, services, directives, or form adapter factories.
*
* It ensures that you receive the set of validators configured with the appropriate
* localization (via `provideValidatorConfig` and `LOCALE_ID`) and custom date handling,
* if provided.
*
* If `provideValidatorConfig` was not used in the current or parent injectors,
* this function gracefully falls back to a default set of validators using
* English messages and default date handling (`Date` objects).
*
* @template TDate - The type used for date values in your application and configuration
* (e.g., `Date`, Luxon `DateTime`, Moment). This should match the type argument
* used in `provideValidatorConfig` if custom date handling was provided. Defaults to `Date`.
* @param injector - Optional. A specific Angular `Injector` instance to use for resolving
* the validators. If omitted, it uses the current injection context via `inject()`.
* @returns The configured `Validators<TDate>` object, ready to use for creating
* validator functions (e.g., `validators.string.all({ required: true })`).
*
* @example
* // In an Angular component or service:
* import { Component, inject } from '@angular/core';
* import { injectValidators } from '@mmstack/form-validation';
* import { formControl } from '@mmstack/form-core';
* // Assuming form is configured for native Date objects (or default)
*
* @Component({...})
* export class UserProfileComponent {
* private validators = injectValidators(); // Inject the validators
* // Or, if configured for Luxon DateTime:
* // private validators = injectValidators<DateTime>();
*
* // Use the injected validators to define form controls
* readonly emailControl = formControl('', {
* label: () => 'Email Address',
* validator: () => this.validators.string.all({ required: true, email: true })
* });
*
* readonly birthDateControl = formControl<Date | null>(null, {
* label: () => 'Date of Birth',
* validator: () => this.validators.date.all({ required: false, max: new Date() })
* });
*
* readonly numberOfPetsControl = formControl<number>(0, {
* label: () => 'Number of Pets',
* validator: () => this.validators.number.min(0, 'Pet count') // Using an individual validator
* });
* }
*/
function injectValidators(injector) {
const validators = (injector
? injector.get(token, null, {
optional: true,
})
: inject(token, { optional: true }));
return validators ?? createDefaultValidators();
}
/**
* Generated bundle index. Do not edit.
*/
export { injectValidators, provideValidatorConfig };
//# sourceMappingURL=mmstack-form-validation.mjs.map