@mmstack/form-validation
Version:
This is an internal library for providing localized validators :)
727 lines (692 loc) • 23.5 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) {
return {
error: first,
tooltip: '',
};
}
return {
error: `${first}, +${errors.length} 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$5 = {
minLength: defaultMinLengthMessageFactory$1,
maxLength: defaultMaxLengthMessageFactory$1,
};
function createArrayValidators(factories, merger = createMergeValidators()) {
const t = { ...DEFAULT_MESSAGES$5, ...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$4 = {
mustBeTrue: defaultMustBeTreFactory,
};
function createBooleanValidators(factories) {
const t = { ...DEFAULT_MESSAGES$4, ...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$3 = {
required: defaultRequiredMessageFactory,
mustBe: defaultMustBeMessageFactory,
mustBeNull: defaultMustBeEmptyMessageFactory,
not: defaultNotMessageFactory,
oneOf: defaultOneOfMessageFactory,
notOneOf: defaultNotOneOfMessageFactory,
};
function createGeneralValidators(factories) {
const t = { ...DEFAULT_MESSAGES$3, ...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) {
return () => {
const msg = createMsg();
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_MESSAGES$2 = {
min: defaultMinDateMessageFactory,
max: defaultMaxDateMessageFactory,
isDate: defaultIsDateMessageFactory,
};
function createDateValidators(factories, toDate = (defaultToDate), formatDate = defaultFormatDate, locale = 'en-US', generalValidators = createGeneralValidators(), merger = createMergeValidators()) {
const t = { ...DEFAULT_MESSAGES$2, ...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());
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);
},
};
}
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());
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());
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.oneOf)
validators.push(generalValidators.oneOf(opt.oneOf));
if (opt.notOneOf)
validators.push(generalValidators.notOneOf(opt.notOneOf));
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;
}
}
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),
array: createArrayValidators(msg?.array, merger),
boolean: createBooleanValidators(msg?.boolean),
};
}
function provideValidatorConfig(factory, toDate = (defaultToDate), formatDate = defaultFormatDate) {
return {
provide: token,
useFactory: (locale) => createValidators(factory(locale), toDate, formatDate, locale),
deps: [LOCALE_ID],
};
}
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