form-validity
Advanced tools
Comparing version 0.0.2 to 0.0.3
156
index.d.ts
@@ -1,65 +0,14 @@ | ||
interface Required { | ||
required: (message?: string) => this; | ||
} | ||
interface Min<Value> { | ||
min(value: Value | string, message?: string): this; | ||
} | ||
interface Max<Value> { | ||
max(value: Value | string, message?: string): this; | ||
} | ||
interface MinLength { | ||
minLength(number: number, message?: string): this; | ||
} | ||
interface MaxLength { | ||
maxLength(number: number, message?: string): this; | ||
} | ||
interface Pattern { | ||
pattern(regexp: RegExp, message?: string): this; | ||
} | ||
interface Step { | ||
step(number: number | string, message?: string): this; | ||
} | ||
interface Multiple<Count = void> { | ||
multiple(count: Count): this; | ||
} | ||
interface NoConstraint { | ||
} | ||
export interface FieldAttributes { | ||
type?: Exclude<keyof FieldOption, 'select' | 'textarea' | 'fieldset'>; | ||
required?: boolean; | ||
minLength?: number; | ||
maxLength?: number; | ||
min?: string | number; | ||
max?: string | number; | ||
step?: string | number; | ||
pattern?: string; | ||
multiple?: boolean; | ||
} | ||
export interface FieldOption { | ||
checkbox: Required; | ||
color: NoConstraint; | ||
date: Required & Min<Date> & Max<Date> & Step; | ||
datetime: Required & Min<Date> & Max<Date> & Step; | ||
'datetime-local': Required & Min<Date> & Max<Date> & Step; | ||
email: Required & MinLength & MaxLength & Pattern; | ||
fieldset: Multiple<Number>; | ||
file: Required; | ||
hidden: NoConstraint; | ||
month: Required & Min<Date> & Max<Date> & Step; | ||
number: Required & Min<number> & Max<number> & Step; | ||
password: Required & MinLength & MaxLength & Pattern; | ||
radio: Required; | ||
range: Min<number> & Max<number> & Step; | ||
search: Required & MinLength & MaxLength & Pattern; | ||
select: Required; | ||
tel: Required & MinLength & MaxLength & Pattern; | ||
text: Required & MinLength & MaxLength & Pattern; | ||
textarea: Required & MinLength & MaxLength; | ||
time: Required & Min<Date> & Max<Date> & Step; | ||
url: Required & MinLength & MaxLength & Pattern; | ||
week: Required & Min<Date> & Max<Date> & Step; | ||
} | ||
export interface Constraint { | ||
type: { | ||
value: keyof FieldOption; | ||
/** | ||
* | ||
*/ | ||
declare const symbol: unique symbol; | ||
export declare type FieldTag = 'input' | 'textarea' | 'select' | 'fieldset'; | ||
export declare type InputType = 'checkbox' | 'color' | 'date' | 'date' | 'datetime-local' | 'email' | 'fieldset' | 'file' | 'hidden' | 'month' | 'number' | 'password' | 'radio' | 'range' | 'search' | 'select' | 'tel' | 'text' | 'textarea' | 'time' | 'url' | 'week'; | ||
export declare type Field<Tag extends FieldTag = FieldTag, Type extends InputType | undefined = undefined> = (Tag extends 'input' ? Type extends 'checkbox' | 'file' | 'radio' ? Required : Type extends 'date' | 'datetime-local' | 'month' | 'time' | 'week' ? Required & Min<Date> & Max<Date> & Step : Type extends 'email' | 'password' | 'search' | 'tel' | 'text' | 'url' ? Required & MinLength & MaxLength & Pattern : Type extends 'number' ? Required & Min<number> & Max<number> & Step : Type extends 'range' ? Min<number> & Max<number> & Step : {} : Tag extends 'select' ? Required : Tag extends 'textarea' ? Required & MinLength & MaxLength : Tag extends 'fieldset' ? Multiple<number> : unknown) & { | ||
[symbol]: Constraint<Tag>; | ||
}; | ||
export declare type Constraint<Tag extends FieldTag = FieldTag> = { | ||
tag: Tag; | ||
type?: { | ||
value: InputType; | ||
message: string | undefined; | ||
@@ -98,47 +47,62 @@ }; | ||
}; | ||
} | ||
declare const symbol: unique symbol; | ||
export declare type Field<Type extends keyof FieldOption = keyof FieldOption> = FieldOption[Type] & { | ||
[symbol]: () => Constraint; | ||
}; | ||
/** | ||
* Helpers for constructing the field constraints | ||
* Helpers for constructing the field constraint based on the type | ||
* @see https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Constraint_validation#validation-related_attributes | ||
*/ | ||
export declare const f: { | ||
checkbox: () => Field<"checkbox">; | ||
color: () => Field<"color">; | ||
date: () => Field<"date">; | ||
datetime: () => Field<"datetime-local">; | ||
email: (message?: string | undefined) => Field<"email">; | ||
fieldset: () => Field<"fieldset">; | ||
file: () => Field<"file">; | ||
hidden: () => Field<"hidden">; | ||
month: () => Field<"month">; | ||
number: (message?: string | undefined) => Field<"number">; | ||
password: () => Field<"password">; | ||
radio: () => Field<"radio">; | ||
range: () => Field<"range">; | ||
search: () => Field<"search">; | ||
select: () => Field<"select">; | ||
tel: () => Field<"tel">; | ||
text: () => Field<"text">; | ||
textarea: () => Field<"textarea">; | ||
time: () => Field<"time">; | ||
url: (message?: string | undefined) => Field<"url">; | ||
week: () => Field<"week">; | ||
input: { | ||
<T extends "number" | "email" | "url">(type: T, message?: string | undefined): Field<"input", T>; | ||
<T_1 extends "textarea" | "select" | "fieldset" | "checkbox" | "color" | "date" | "datetime-local" | "file" | "hidden" | "month" | "password" | "radio" | "range" | "search" | "tel" | "text" | "time" | "week">(type: T_1): Field<"input", T_1>; | ||
}; | ||
select: () => Field<'select'>; | ||
textarea: () => Field<'textarea'>; | ||
fieldset: () => Field<'fieldset'>; | ||
}; | ||
export declare function getConstraint<Type extends keyof FieldOption>(field: Field<Type>): Constraint; | ||
export declare function getConstraint<Tag extends FieldTag>(field: Field<Tag>): Constraint<Tag>; | ||
export declare function isElement<T extends HTMLElement>(element: any, tag: string): element is T; | ||
export declare function isInputElement(element: unknown): element is HTMLInputElement; | ||
export declare function isSelectElement(element: unknown): element is HTMLSelectElement; | ||
export declare function isTextareaElement(element: unknown): element is HTMLTextAreaElement; | ||
export declare function isButtonElement(element: unknown): element is HTMLButtonElement; | ||
export declare function isDirtyField(element: HTMLSelectElement | HTMLInputElement | HTMLTextAreaElement): boolean; | ||
export declare function isDirty(element: unknown): boolean; | ||
export declare function isValidationConstraintSupported(element: unknown): element is HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement; | ||
export declare function shouldSkipValidate(element: unknown): boolean; | ||
export declare function draftUpdate(name: string, index?: number): { | ||
name: string; | ||
value: string; | ||
}; | ||
export declare function getDraft(payload: URLSearchParams | FormData): { | ||
name: string; | ||
index: number | null; | ||
} | null; | ||
export declare function parse<T>(payload: FormData | URLSearchParams | string, fieldsetCreator: ((value?: Record<string, any>) => Record<string, T>) | Record<string, T>): { | ||
value: Record<string, any>; | ||
error: Record<string, string> | null; | ||
isDraft: boolean; | ||
}; | ||
/** | ||
* Helpers | ||
*/ | ||
interface Required { | ||
required(message?: string): this; | ||
} | ||
interface Min<Value> { | ||
min(value: Value | string, message?: string): this; | ||
} | ||
interface Max<Value> { | ||
max(value: Value | string, message?: string): this; | ||
} | ||
interface MinLength { | ||
minLength(number: number, message?: string): this; | ||
} | ||
interface MaxLength { | ||
maxLength(number: number, message?: string): this; | ||
} | ||
interface Pattern { | ||
pattern(regexp: RegExp, message?: string): this; | ||
} | ||
interface Step { | ||
step(number: number | string, message?: string): this; | ||
} | ||
interface Multiple<Count = void> { | ||
multiple(count: Count): this; | ||
} | ||
export declare function checkCustomValidity(value: FormDataEntryValue, validity: ValidityState, constraint: Constraint): string | null; | ||
export {}; |
573
index.js
@@ -5,111 +5,113 @@ 'use strict'; | ||
var attributesByType = { | ||
// 'button': [], | ||
checkbox: ['required'], | ||
color: [], | ||
date: ['required', 'minLength', 'maxLength', 'pattern'], | ||
datetime: ['required', 'minLength', 'maxLength', 'pattern'], | ||
'datetime-local': ['required', 'minLength', 'maxLength', 'pattern'], | ||
email: ['required', 'minLength', 'maxLength', 'pattern'], | ||
fieldset: ['multiple'], | ||
file: ['required'], | ||
hidden: [], | ||
// 'image': [], | ||
month: ['required', 'minLength', 'maxLength', 'pattern'], | ||
number: ['required', 'minLength', 'maxLength', 'pattern'], | ||
password: ['required', 'minLength', 'maxLength', 'pattern'], | ||
radio: ['required'], | ||
range: ['min', 'max', 'step'], | ||
// 'reset': [], | ||
search: ['required', 'minLength', 'maxLength', 'pattern'], | ||
select: ['required'], | ||
// 'submit': [], | ||
tel: ['required', 'minLength', 'maxLength', 'pattern'], | ||
text: ['required', 'minLength', 'maxLength', 'pattern'], | ||
textarea: ['required', 'minLength', 'maxLength'], | ||
time: ['required', 'minLength', 'maxLength', 'pattern'], | ||
url: ['required', 'minLength', 'maxLength', 'pattern'], | ||
week: ['required', 'minLength', 'maxLength', 'pattern'] | ||
}; | ||
var symbol = Symbol('constraints'); | ||
/** | ||
* | ||
*/ | ||
var symbol = Symbol('constraint'); | ||
function createField(type, message) { | ||
var supportedAttributes = attributesByType[type]; | ||
var constraint = { | ||
type: { | ||
value: type, | ||
message: message | ||
} | ||
}; | ||
var field = { | ||
required(message) { | ||
constraint.required = { | ||
message | ||
}; | ||
return field; | ||
}, | ||
function configureF() { | ||
function createField(tag, type, message) { | ||
var constraint = { | ||
tag | ||
}; | ||
min(value, message) { | ||
constraint.min = { | ||
value, | ||
if (type) { | ||
constraint.type = { | ||
value: type, | ||
message | ||
}; | ||
return field; | ||
}, | ||
} | ||
max(value, message) { | ||
constraint.max = { | ||
value, | ||
message | ||
}; | ||
return field; | ||
}, | ||
return { | ||
required(message) { | ||
constraint.required = { | ||
message | ||
}; | ||
return this; | ||
}, | ||
minLength(value, message) { | ||
constraint.minLength = { | ||
value, | ||
message | ||
}; | ||
return field; | ||
}, | ||
min(value, message) { | ||
constraint.min = { | ||
value, | ||
message | ||
}; | ||
return this; | ||
}, | ||
maxLength(value, message) { | ||
constraint.maxLength = { | ||
value, | ||
message | ||
}; | ||
return field; | ||
}, | ||
max(value, message) { | ||
constraint.max = { | ||
value, | ||
message | ||
}; | ||
return this; | ||
}, | ||
pattern(value, message) { | ||
if (value.global || value.ignoreCase || value.multiline) { | ||
console.warn("global, ignoreCase, and multiline flags are not supported on the pattern attribute"); | ||
} else { | ||
var _constraint$pattern; | ||
minLength(value, message) { | ||
constraint.minLength = { | ||
value, | ||
message | ||
}; | ||
return this; | ||
}, | ||
constraint.pattern = ((_constraint$pattern = constraint.pattern) !== null && _constraint$pattern !== void 0 ? _constraint$pattern : []).concat({ | ||
maxLength(value, message) { | ||
constraint.maxLength = { | ||
value, | ||
message | ||
}); | ||
} | ||
}; | ||
return this; | ||
}, | ||
return field; | ||
}, | ||
pattern(value, message) { | ||
if (value.global || value.ignoreCase || value.multiline) { | ||
console.warn("global, ignoreCase, and multiline flags are not supported on the pattern attribute"); | ||
} else { | ||
var _constraint$pattern; | ||
multiple(value) { | ||
constraint.multiple = { | ||
value, | ||
message | ||
}; | ||
return field; | ||
}, | ||
constraint.pattern = ((_constraint$pattern = constraint.pattern) !== null && _constraint$pattern !== void 0 ? _constraint$pattern : []).concat({ | ||
value, | ||
message | ||
}); | ||
} | ||
[symbol]: () => constraint | ||
}; // @ts-ignore | ||
return this; | ||
}, | ||
return Object.fromEntries( // @ts-ignore | ||
[symbol, ...supportedAttributes].map(key => [key, field[key]])); | ||
multiple(value) { | ||
constraint.multiple = { | ||
value, | ||
message | ||
}; | ||
return this; | ||
}, | ||
[symbol]: constraint | ||
}; | ||
} | ||
function input(type, message) { | ||
// @ts-expect-error | ||
return createField('input', type, message); | ||
} | ||
function select() { | ||
return createField('select'); | ||
} | ||
function textarea() { | ||
return createField('textarea'); | ||
} | ||
function fieldset() { | ||
return createField('fieldset'); | ||
} | ||
return { | ||
input, | ||
select, | ||
textarea, | ||
fieldset | ||
}; | ||
} | ||
/** | ||
* Helpers for constructing the field constraints | ||
* Helpers for constructing the field constraint based on the type | ||
* @see https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Constraint_validation#validation-related_attributes | ||
@@ -119,63 +121,38 @@ */ | ||
var f = { | ||
// button: () => createField('button'), | ||
checkbox: () => createField('checkbox'), | ||
color: () => createField('color'), | ||
date: () => createField('date'), | ||
// datetime: () => createField('datetime'), | ||
datetime: () => createField('datetime-local'), | ||
// `datetime` is deprecated | ||
email: message => createField('email', message), | ||
fieldset: () => createField('fieldset'), | ||
file: () => createField('file'), | ||
hidden: () => createField('hidden'), | ||
// image: () => createField('image'), | ||
month: () => createField('month'), | ||
number: message => createField('number', message), | ||
password: () => createField('password'), | ||
radio: () => createField('radio'), | ||
range: () => createField('range'), | ||
// reset: () => createField('reset'), | ||
search: () => createField('search'), | ||
select: () => createField('select'), | ||
// submit: () => createField('submit'), | ||
tel: () => createField('tel'), | ||
text: () => createField('text'), | ||
textarea: () => createField('textarea'), | ||
time: () => createField('time'), | ||
url: message => createField('url', message), | ||
week: () => createField('week') | ||
}; | ||
var f = configureF(); | ||
function getConstraint(field) { | ||
return field[symbol](); | ||
} // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
if (typeof field[symbol] === 'undefined') { | ||
throw new Error('Provided config is not a field; Please ensure only field object is used'); | ||
} | ||
return field[symbol]; | ||
} | ||
function isElement(element, tag) { | ||
return !!element && element.tagName.toLowerCase() === tag; | ||
} | ||
function isInputElement(element) { | ||
return isElement(element, 'input'); | ||
} | ||
function isSelectElement(element) { | ||
return isElement(element, 'select'); | ||
} | ||
function isTextareaElement(element) { | ||
return isElement(element, 'textarea'); | ||
} | ||
function isButtonElement(element) { | ||
return isElement(element, 'button'); | ||
} | ||
function isDirtyField(element) { | ||
function isDirty(element) { | ||
if (isElement(element, 'form')) { | ||
for (var el of element.elements) { | ||
if (isDirty(el)) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
if (isElement(element, 'input') || isElement(element, 'textarea')) { | ||
return element.value !== element.defaultValue; | ||
} else if (isElement(element, 'select')) { | ||
} | ||
if (isElement(element, 'select')) { | ||
var _Array$from$find; | ||
return element.value !== ((_Array$from$find = Array.from(element.options).find(option => option.defaultSelected)) === null || _Array$from$find === void 0 ? void 0 : _Array$from$find.value); | ||
} else { | ||
return false; | ||
} | ||
return false; | ||
} | ||
function isValidationConstraintSupported(element) { | ||
if (!isInputElement(element) && !isSelectElement(element) && !isTextareaElement(element)) { | ||
if (!isElement(element, 'input') && !isElement(element, 'select') && !isElement(element, 'textarea')) { | ||
return false; | ||
@@ -187,5 +164,106 @@ } | ||
function shouldSkipValidate(element) { | ||
return isButtonElement(element) || isInputElement(element) ? element.formNoValidate : false; | ||
return isElement(element, 'button') || isElement(element, 'input') ? element.formNoValidate : false; | ||
} | ||
function draftUpdate(name, index) { | ||
return { | ||
name: '__form-validity__', | ||
value: [name].concat(typeof index === 'undefined' ? [] : ["".concat(index)]).join('|') | ||
}; | ||
} | ||
function getDraft(payload) { | ||
var update = payload.get('__form-validity__'); | ||
if (!update) { | ||
return null; | ||
} // We are mutating the payload here | ||
payload.delete('__form-validity__'); | ||
if (update instanceof File) { | ||
throw new Error('What?'); | ||
} | ||
var [name, indexString] = update.split('|'); | ||
var index = typeof indexString !== 'undefined' ? Number(indexString) : null; | ||
return { | ||
name, | ||
index | ||
}; | ||
} | ||
function parse(payload, fieldsetCreator) { | ||
var valueEntries = payload instanceof URLSearchParams || payload instanceof FormData ? payload : new URLSearchParams(payload); | ||
var update = getDraft(valueEntries); | ||
var value = unflatten(valueEntries); | ||
if (update) { | ||
var list = getItem(value, update.name); | ||
if (!Array.isArray(list) || update.index !== null && isNaN(update.index)) { | ||
throw new Error('Oops'); | ||
} | ||
if (update.index !== null) { | ||
list.splice(update.index, 1); | ||
} else { | ||
list.push({}); | ||
} | ||
} | ||
var fieldset = typeof fieldsetCreator === 'function' ? fieldsetCreator(value) : fieldsetCreator; | ||
var valueByName = Object.fromEntries(valueEntries); | ||
var errorEntries = []; | ||
if (!update) { | ||
for (var [name, field] of flatten(fieldset, f => typeof f[symbol] !== 'undefined')) { | ||
var constraint = getConstraint(field); | ||
var _value = valueByName[name]; | ||
var validity = validate(_value, constraint); | ||
var _message = checkCustomValidity(_value, validity, constraint); | ||
if (_message) { | ||
errorEntries.push([name, _message]); | ||
} | ||
} | ||
} | ||
return { | ||
value, | ||
error: errorEntries.length > 0 ? unflatten(errorEntries) : null, | ||
isDraft: update !== null | ||
}; | ||
} | ||
/** | ||
* Helpers | ||
*/ | ||
var pattern = /(\w+)\[(\d+)\]/; | ||
function getPaths(key) { | ||
return key.split('.').flatMap(key => { | ||
var matches = pattern.exec(key); | ||
if (!matches) { | ||
return key; | ||
} | ||
return [matches[1], Number(matches[2])]; | ||
}); | ||
} | ||
function getItem(obj, key, defaultValue) { | ||
var target = obj; | ||
for (var path of getPaths(key)) { | ||
if (typeof target[path] === 'undefined') { | ||
return defaultValue; | ||
} | ||
target = target[path]; | ||
} | ||
return target; | ||
} | ||
function flatten(item, isLeaf) { | ||
@@ -202,4 +280,4 @@ var prefix = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ''; | ||
} else { | ||
for (var [key, _value] of Object.entries(item)) { | ||
entries.push(...flatten(_value, isLeaf, prefix ? "".concat(prefix, ".").concat(key) : key)); | ||
for (var [key, _value2] of Object.entries(item)) { | ||
entries.push(...flatten(_value2, isLeaf, prefix ? "".concat(prefix, ".").concat(key) : key)); | ||
} | ||
@@ -212,15 +290,6 @@ } | ||
function unflatten(entries) { | ||
var pattern = /(\w+)\[(\d+)\]/; | ||
var result = {}; | ||
for (var [key, _value2] of entries) { | ||
var paths = key.split('.').flatMap(key => { | ||
var matches = pattern.exec(key); | ||
if (!matches) { | ||
return key; | ||
} | ||
return [matches[1], Number(matches[2])]; | ||
}); | ||
for (var [key, _value3] of entries) { | ||
var paths = getPaths(key); | ||
var length = paths.length; | ||
@@ -234,3 +303,3 @@ var lastIndex = length - 1; | ||
var next = paths[index + 1]; | ||
var newValue = _value2; | ||
var newValue = _value3; | ||
@@ -252,139 +321,111 @@ if (index != lastIndex) { | ||
function validate(value, constraint) { | ||
var _constraint$pattern2; | ||
var badInput = false; | ||
var customError = false; | ||
var patternMismatch = false; | ||
var rangeOverflow = false; | ||
var rangeUnderflow = false; | ||
var stepMismatch = false; | ||
var tooLong = false; | ||
var tooShort = false; | ||
var typeMismatch = false; | ||
var valueMissing = false; | ||
if (value instanceof File) { | ||
return 'File is not supported yet'; | ||
} | ||
var _constraint$type; | ||
if (constraint.required) { | ||
if (typeof value === 'undefined' || value === '') { | ||
var _constraint$required$; | ||
typeMismatch = ((_constraint$type = constraint.type) === null || _constraint$type === void 0 ? void 0 : _constraint$type.value) !== 'file'; | ||
} else { | ||
var _constraint$pattern$s, _constraint$pattern2, _constraint$type2, _constraint$type3; | ||
return (_constraint$required$ = constraint.required.message) !== null && _constraint$required$ !== void 0 ? _constraint$required$ : 'This field is required'; | ||
} | ||
} | ||
var isURL = value => { | ||
try { | ||
new URL(value); | ||
return true; | ||
} catch (_unused) { | ||
return false; | ||
} | ||
}; | ||
if (constraint.minLength) { | ||
if (typeof value === 'undefined' || value.length < constraint.minLength.value) { | ||
var _constraint$minLength; | ||
return (_constraint$minLength = constraint.minLength.message) !== null && _constraint$minLength !== void 0 ? _constraint$minLength : "This field must be at least ".concat(constraint.minLength.value, " characters"); | ||
} | ||
patternMismatch = (_constraint$pattern$s = (_constraint$pattern2 = constraint.pattern) === null || _constraint$pattern2 === void 0 ? void 0 : _constraint$pattern2.some(pattern => { | ||
var match = value === null || value === void 0 ? void 0 : value.match(pattern.value); | ||
return !match || value !== match[0]; | ||
})) !== null && _constraint$pattern$s !== void 0 ? _constraint$pattern$s : false; | ||
rangeOverflow = constraint.max ? typeof value !== 'undefined' && constraint.max.value instanceof Date && new Date(value) > constraint.max.value || typeof value !== 'undefined' && typeof constraint.max.value === 'number' && Number(value) > constraint.max.value : false; | ||
rangeUnderflow = constraint.min ? constraint.min.value instanceof Date && new Date(value !== null && value !== void 0 ? value : '') < constraint.min.value || typeof constraint.min.value === 'number' && Number(value !== null && value !== void 0 ? value : '') < constraint.min.value : false; | ||
tooLong = constraint.maxLength ? typeof value !== 'undefined' && value.length > constraint.maxLength.value : false; | ||
tooShort = constraint.minLength ? typeof value === 'undefined' || value.length < constraint.minLength.value : false; | ||
typeMismatch = ((_constraint$type2 = constraint.type) === null || _constraint$type2 === void 0 ? void 0 : _constraint$type2.value) === 'email' && !/^\S+@\S+$/.test(value !== null && value !== void 0 ? value : '') || ((_constraint$type3 = constraint.type) === null || _constraint$type3 === void 0 ? void 0 : _constraint$type3.value) === 'url' && !isURL(value !== null && value !== void 0 ? value : ''); | ||
valueMissing = typeof value === 'undefined' || value === ''; | ||
} | ||
if (constraint.maxLength) { | ||
if (typeof value !== 'undefined' && value.length > constraint.maxLength.value) { | ||
var _constraint$maxLength; | ||
return { | ||
badInput, | ||
customError, | ||
patternMismatch, | ||
rangeOverflow, | ||
rangeUnderflow, | ||
stepMismatch, | ||
tooLong, | ||
tooShort, | ||
typeMismatch, | ||
valid: !patternMismatch && !rangeOverflow && !rangeUnderflow && !stepMismatch && !tooLong && !tooShort && !typeMismatch && !valueMissing, | ||
valueMissing | ||
}; | ||
} | ||
return (_constraint$maxLength = constraint.maxLength.message) !== null && _constraint$maxLength !== void 0 ? _constraint$maxLength : "This field must be at most ".concat(constraint.maxLength.value, " characters"); | ||
} | ||
} | ||
function checkCustomValidity(value, validity, constraint) { | ||
if (validity.valueMissing) { | ||
var _constraint$required$, _constraint$required; | ||
if (constraint.min) { | ||
if (constraint.min.value instanceof Date && new Date(value !== null && value !== void 0 ? value : '') < constraint.min.value) { | ||
var _constraint$min$messa; | ||
return (_constraint$required$ = (_constraint$required = constraint.required) === null || _constraint$required === void 0 ? void 0 : _constraint$required.message) !== null && _constraint$required$ !== void 0 ? _constraint$required$ : null; | ||
} else if (validity.tooShort) { | ||
var _constraint$minLength, _constraint$minLength2; | ||
return (_constraint$min$messa = constraint.min.message) !== null && _constraint$min$messa !== void 0 ? _constraint$min$messa : "This field must be later than ".concat(constraint.min.value.toISOString()); | ||
} else if (typeof constraint.min.value === 'number' && Number(value !== null && value !== void 0 ? value : '') < constraint.min.value) { | ||
var _constraint$min$messa2; | ||
return (_constraint$minLength = (_constraint$minLength2 = constraint.minLength) === null || _constraint$minLength2 === void 0 ? void 0 : _constraint$minLength2.message) !== null && _constraint$minLength !== void 0 ? _constraint$minLength : null; | ||
} else if (validity.tooLong) { | ||
var _constraint$maxLength, _constraint$maxLength2; | ||
return (_constraint$min$messa2 = constraint.min.message) !== null && _constraint$min$messa2 !== void 0 ? _constraint$min$messa2 : "This field must be greater than or equal to ".concat(constraint.min.value); | ||
} | ||
} | ||
return (_constraint$maxLength = (_constraint$maxLength2 = constraint.maxLength) === null || _constraint$maxLength2 === void 0 ? void 0 : _constraint$maxLength2.message) !== null && _constraint$maxLength !== void 0 ? _constraint$maxLength : null; | ||
} else if (validity.stepMismatch) { | ||
var _constraint$step$mess, _constraint$step; | ||
if (constraint.max) { | ||
if (typeof value !== 'undefined' && constraint.max.value instanceof Date && new Date(value) > constraint.max.value) { | ||
var _constraint$max$messa; | ||
return (_constraint$step$mess = (_constraint$step = constraint.step) === null || _constraint$step === void 0 ? void 0 : _constraint$step.message) !== null && _constraint$step$mess !== void 0 ? _constraint$step$mess : null; | ||
} else if (validity.rangeUnderflow) { | ||
var _constraint$min$messa, _constraint$min; | ||
return (_constraint$max$messa = constraint.max.message) !== null && _constraint$max$messa !== void 0 ? _constraint$max$messa : "This field must be at earlier than ".concat(constraint.max.value.toISOString()); | ||
} else if (typeof value !== 'undefined' && typeof constraint.max.value === 'number' && Number(value) > constraint.max.value) { | ||
var _constraint$max$messa2; | ||
return (_constraint$min$messa = (_constraint$min = constraint.min) === null || _constraint$min === void 0 ? void 0 : _constraint$min.message) !== null && _constraint$min$messa !== void 0 ? _constraint$min$messa : null; | ||
} else if (validity.rangeOverflow) { | ||
var _constraint$max$messa, _constraint$max; | ||
return (_constraint$max$messa2 = constraint.max.message) !== null && _constraint$max$messa2 !== void 0 ? _constraint$max$messa2 : "This field must be less than or equal to ".concat(constraint.max.value); | ||
} | ||
} | ||
return (_constraint$max$messa = (_constraint$max = constraint.max) === null || _constraint$max === void 0 ? void 0 : _constraint$max.message) !== null && _constraint$max$messa !== void 0 ? _constraint$max$messa : null; | ||
} else if (validity.typeMismatch || validity.badInput) { | ||
var _constraint$type$mess, _constraint$type4; | ||
if (constraint.step) ; | ||
return (_constraint$type$mess = (_constraint$type4 = constraint.type) === null || _constraint$type4 === void 0 ? void 0 : _constraint$type4.message) !== null && _constraint$type$mess !== void 0 ? _constraint$type$mess : null; | ||
} else if (validity.patternMismatch) { | ||
if (!constraint.pattern) { | ||
return null; | ||
} else if (constraint.pattern.length === 1) { | ||
var _constraint$pattern$; | ||
if (constraint.type) { | ||
switch (constraint.type.value) { | ||
case 'email': | ||
if (!/^\S+\@\S+$/.test(value !== null && value !== void 0 ? value : '')) { | ||
var _constraint$type$mess; | ||
return (_constraint$pattern$ = constraint.pattern[0].message) !== null && _constraint$pattern$ !== void 0 ? _constraint$pattern$ : null; | ||
} else { | ||
var _constraint$pattern$f, _constraint$pattern$f2; | ||
return (_constraint$type$mess = constraint.type.message) !== null && _constraint$type$mess !== void 0 ? _constraint$type$mess : "This field must be a valid email"; | ||
} | ||
break; | ||
case 'url': | ||
var isURL = value => { | ||
try { | ||
new URL(value); | ||
return true; | ||
} catch (_unused) { | ||
return false; | ||
} | ||
}; | ||
if (!isURL(value !== null && value !== void 0 ? value : '')) { | ||
var _constraint$type$mess2; | ||
return (_constraint$type$mess2 = constraint.type.message) !== null && _constraint$type$mess2 !== void 0 ? _constraint$type$mess2 : "This field must be a valid URL"; | ||
} | ||
break; | ||
return (_constraint$pattern$f = (_constraint$pattern$f2 = constraint.pattern.find(pattern => pattern.value.test(value))) === null || _constraint$pattern$f2 === void 0 ? void 0 : _constraint$pattern$f2.message) !== null && _constraint$pattern$f !== void 0 ? _constraint$pattern$f : null; | ||
} | ||
} else { | ||
return ''; | ||
} | ||
if ((_constraint$pattern2 = constraint.pattern) !== null && _constraint$pattern2 !== void 0 && _constraint$pattern2.length) { | ||
var _pattern = constraint.pattern.find(pattern => { | ||
var match = value === null || value === void 0 ? void 0 : value.match(pattern.value); | ||
return !match || value !== match[0]; | ||
}); | ||
if (_pattern) { | ||
var _pattern$message; | ||
return (_pattern$message = _pattern.message) !== null && _pattern$message !== void 0 ? _pattern$message : "This field must be a valid format"; | ||
} | ||
} | ||
return null; | ||
} | ||
function parse(payload, fieldsetCreator) { | ||
var valueEntries = payload instanceof URLSearchParams || payload instanceof FormData ? payload : new URLSearchParams(payload); | ||
var value = unflatten(valueEntries); | ||
var fieldset = typeof fieldsetCreator === 'function' ? fieldsetCreator(value) : fieldsetCreator; | ||
var values = Object.fromEntries(valueEntries); | ||
var errorEntries = []; | ||
for (var [name, field] of flatten(fieldset, f => typeof f[symbol] === 'function')) { | ||
var constraint = getConstraint(field); | ||
var _value3 = values[name]; | ||
var _message = validate(_value3, constraint); | ||
if (_message) { | ||
errorEntries.push([name, _message]); | ||
} | ||
} | ||
return { | ||
value, | ||
error: errorEntries.length > 0 ? unflatten(errorEntries) : null | ||
}; | ||
} | ||
exports.checkCustomValidity = checkCustomValidity; | ||
exports.draftUpdate = draftUpdate; | ||
exports.f = f; | ||
exports.getConstraint = getConstraint; | ||
exports.isButtonElement = isButtonElement; | ||
exports.isDirtyField = isDirtyField; | ||
exports.getDraft = getDraft; | ||
exports.isDirty = isDirty; | ||
exports.isElement = isElement; | ||
exports.isInputElement = isInputElement; | ||
exports.isSelectElement = isSelectElement; | ||
exports.isTextareaElement = isTextareaElement; | ||
exports.isValidationConstraintSupported = isValidationConstraintSupported; | ||
exports.parse = parse; | ||
exports.shouldSkipValidate = shouldSkipValidate; |
@@ -1,110 +0,112 @@ | ||
var attributesByType = { | ||
// 'button': [], | ||
checkbox: ['required'], | ||
color: [], | ||
date: ['required', 'minLength', 'maxLength', 'pattern'], | ||
datetime: ['required', 'minLength', 'maxLength', 'pattern'], | ||
'datetime-local': ['required', 'minLength', 'maxLength', 'pattern'], | ||
email: ['required', 'minLength', 'maxLength', 'pattern'], | ||
fieldset: ['multiple'], | ||
file: ['required'], | ||
hidden: [], | ||
// 'image': [], | ||
month: ['required', 'minLength', 'maxLength', 'pattern'], | ||
number: ['required', 'minLength', 'maxLength', 'pattern'], | ||
password: ['required', 'minLength', 'maxLength', 'pattern'], | ||
radio: ['required'], | ||
range: ['min', 'max', 'step'], | ||
// 'reset': [], | ||
search: ['required', 'minLength', 'maxLength', 'pattern'], | ||
select: ['required'], | ||
// 'submit': [], | ||
tel: ['required', 'minLength', 'maxLength', 'pattern'], | ||
text: ['required', 'minLength', 'maxLength', 'pattern'], | ||
textarea: ['required', 'minLength', 'maxLength'], | ||
time: ['required', 'minLength', 'maxLength', 'pattern'], | ||
url: ['required', 'minLength', 'maxLength', 'pattern'], | ||
week: ['required', 'minLength', 'maxLength', 'pattern'] | ||
}; | ||
var symbol = Symbol('constraints'); | ||
/** | ||
* | ||
*/ | ||
var symbol = Symbol('constraint'); | ||
function createField(type, message) { | ||
var supportedAttributes = attributesByType[type]; | ||
var constraint = { | ||
type: { | ||
value: type, | ||
message: message | ||
} | ||
}; | ||
var field = { | ||
required(message) { | ||
constraint.required = { | ||
message | ||
}; | ||
return field; | ||
}, | ||
function configureF() { | ||
function createField(tag, type, message) { | ||
var constraint = { | ||
tag | ||
}; | ||
min(value, message) { | ||
constraint.min = { | ||
value, | ||
if (type) { | ||
constraint.type = { | ||
value: type, | ||
message | ||
}; | ||
return field; | ||
}, | ||
} | ||
max(value, message) { | ||
constraint.max = { | ||
value, | ||
message | ||
}; | ||
return field; | ||
}, | ||
return { | ||
required(message) { | ||
constraint.required = { | ||
message | ||
}; | ||
return this; | ||
}, | ||
minLength(value, message) { | ||
constraint.minLength = { | ||
value, | ||
message | ||
}; | ||
return field; | ||
}, | ||
min(value, message) { | ||
constraint.min = { | ||
value, | ||
message | ||
}; | ||
return this; | ||
}, | ||
maxLength(value, message) { | ||
constraint.maxLength = { | ||
value, | ||
message | ||
}; | ||
return field; | ||
}, | ||
max(value, message) { | ||
constraint.max = { | ||
value, | ||
message | ||
}; | ||
return this; | ||
}, | ||
pattern(value, message) { | ||
if (value.global || value.ignoreCase || value.multiline) { | ||
console.warn("global, ignoreCase, and multiline flags are not supported on the pattern attribute"); | ||
} else { | ||
var _constraint$pattern; | ||
minLength(value, message) { | ||
constraint.minLength = { | ||
value, | ||
message | ||
}; | ||
return this; | ||
}, | ||
constraint.pattern = ((_constraint$pattern = constraint.pattern) !== null && _constraint$pattern !== void 0 ? _constraint$pattern : []).concat({ | ||
maxLength(value, message) { | ||
constraint.maxLength = { | ||
value, | ||
message | ||
}); | ||
} | ||
}; | ||
return this; | ||
}, | ||
return field; | ||
}, | ||
pattern(value, message) { | ||
if (value.global || value.ignoreCase || value.multiline) { | ||
console.warn("global, ignoreCase, and multiline flags are not supported on the pattern attribute"); | ||
} else { | ||
var _constraint$pattern; | ||
multiple(value) { | ||
constraint.multiple = { | ||
value, | ||
message | ||
}; | ||
return field; | ||
}, | ||
constraint.pattern = ((_constraint$pattern = constraint.pattern) !== null && _constraint$pattern !== void 0 ? _constraint$pattern : []).concat({ | ||
value, | ||
message | ||
}); | ||
} | ||
[symbol]: () => constraint | ||
}; // @ts-ignore | ||
return this; | ||
}, | ||
return Object.fromEntries( // @ts-ignore | ||
[symbol, ...supportedAttributes].map(key => [key, field[key]])); | ||
multiple(value) { | ||
constraint.multiple = { | ||
value, | ||
message | ||
}; | ||
return this; | ||
}, | ||
[symbol]: constraint | ||
}; | ||
} | ||
function input(type, message) { | ||
// @ts-expect-error | ||
return createField('input', type, message); | ||
} | ||
function select() { | ||
return createField('select'); | ||
} | ||
function textarea() { | ||
return createField('textarea'); | ||
} | ||
function fieldset() { | ||
return createField('fieldset'); | ||
} | ||
return { | ||
input, | ||
select, | ||
textarea, | ||
fieldset | ||
}; | ||
} | ||
/** | ||
* Helpers for constructing the field constraints | ||
* Helpers for constructing the field constraint based on the type | ||
* @see https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Constraint_validation#validation-related_attributes | ||
@@ -114,63 +116,38 @@ */ | ||
var f = { | ||
// button: () => createField('button'), | ||
checkbox: () => createField('checkbox'), | ||
color: () => createField('color'), | ||
date: () => createField('date'), | ||
// datetime: () => createField('datetime'), | ||
datetime: () => createField('datetime-local'), | ||
// `datetime` is deprecated | ||
email: message => createField('email', message), | ||
fieldset: () => createField('fieldset'), | ||
file: () => createField('file'), | ||
hidden: () => createField('hidden'), | ||
// image: () => createField('image'), | ||
month: () => createField('month'), | ||
number: message => createField('number', message), | ||
password: () => createField('password'), | ||
radio: () => createField('radio'), | ||
range: () => createField('range'), | ||
// reset: () => createField('reset'), | ||
search: () => createField('search'), | ||
select: () => createField('select'), | ||
// submit: () => createField('submit'), | ||
tel: () => createField('tel'), | ||
text: () => createField('text'), | ||
textarea: () => createField('textarea'), | ||
time: () => createField('time'), | ||
url: message => createField('url', message), | ||
week: () => createField('week') | ||
}; | ||
var f = configureF(); | ||
function getConstraint(field) { | ||
return field[symbol](); | ||
} // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
if (typeof field[symbol] === 'undefined') { | ||
throw new Error('Provided config is not a field; Please ensure only field object is used'); | ||
} | ||
return field[symbol]; | ||
} | ||
function isElement(element, tag) { | ||
return !!element && element.tagName.toLowerCase() === tag; | ||
} | ||
function isInputElement(element) { | ||
return isElement(element, 'input'); | ||
} | ||
function isSelectElement(element) { | ||
return isElement(element, 'select'); | ||
} | ||
function isTextareaElement(element) { | ||
return isElement(element, 'textarea'); | ||
} | ||
function isButtonElement(element) { | ||
return isElement(element, 'button'); | ||
} | ||
function isDirtyField(element) { | ||
function isDirty(element) { | ||
if (isElement(element, 'form')) { | ||
for (var el of element.elements) { | ||
if (isDirty(el)) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
if (isElement(element, 'input') || isElement(element, 'textarea')) { | ||
return element.value !== element.defaultValue; | ||
} else if (isElement(element, 'select')) { | ||
} | ||
if (isElement(element, 'select')) { | ||
var _Array$from$find; | ||
return element.value !== ((_Array$from$find = Array.from(element.options).find(option => option.defaultSelected)) === null || _Array$from$find === void 0 ? void 0 : _Array$from$find.value); | ||
} else { | ||
return false; | ||
} | ||
return false; | ||
} | ||
function isValidationConstraintSupported(element) { | ||
if (!isInputElement(element) && !isSelectElement(element) && !isTextareaElement(element)) { | ||
if (!isElement(element, 'input') && !isElement(element, 'select') && !isElement(element, 'textarea')) { | ||
return false; | ||
@@ -182,5 +159,106 @@ } | ||
function shouldSkipValidate(element) { | ||
return isButtonElement(element) || isInputElement(element) ? element.formNoValidate : false; | ||
return isElement(element, 'button') || isElement(element, 'input') ? element.formNoValidate : false; | ||
} | ||
function draftUpdate(name, index) { | ||
return { | ||
name: '__form-validity__', | ||
value: [name].concat(typeof index === 'undefined' ? [] : ["".concat(index)]).join('|') | ||
}; | ||
} | ||
function getDraft(payload) { | ||
var update = payload.get('__form-validity__'); | ||
if (!update) { | ||
return null; | ||
} // We are mutating the payload here | ||
payload.delete('__form-validity__'); | ||
if (update instanceof File) { | ||
throw new Error('What?'); | ||
} | ||
var [name, indexString] = update.split('|'); | ||
var index = typeof indexString !== 'undefined' ? Number(indexString) : null; | ||
return { | ||
name, | ||
index | ||
}; | ||
} | ||
function parse(payload, fieldsetCreator) { | ||
var valueEntries = payload instanceof URLSearchParams || payload instanceof FormData ? payload : new URLSearchParams(payload); | ||
var update = getDraft(valueEntries); | ||
var value = unflatten(valueEntries); | ||
if (update) { | ||
var list = getItem(value, update.name); | ||
if (!Array.isArray(list) || update.index !== null && isNaN(update.index)) { | ||
throw new Error('Oops'); | ||
} | ||
if (update.index !== null) { | ||
list.splice(update.index, 1); | ||
} else { | ||
list.push({}); | ||
} | ||
} | ||
var fieldset = typeof fieldsetCreator === 'function' ? fieldsetCreator(value) : fieldsetCreator; | ||
var valueByName = Object.fromEntries(valueEntries); | ||
var errorEntries = []; | ||
if (!update) { | ||
for (var [name, field] of flatten(fieldset, f => typeof f[symbol] !== 'undefined')) { | ||
var constraint = getConstraint(field); | ||
var _value = valueByName[name]; | ||
var validity = validate(_value, constraint); | ||
var _message = checkCustomValidity(_value, validity, constraint); | ||
if (_message) { | ||
errorEntries.push([name, _message]); | ||
} | ||
} | ||
} | ||
return { | ||
value, | ||
error: errorEntries.length > 0 ? unflatten(errorEntries) : null, | ||
isDraft: update !== null | ||
}; | ||
} | ||
/** | ||
* Helpers | ||
*/ | ||
var pattern = /(\w+)\[(\d+)\]/; | ||
function getPaths(key) { | ||
return key.split('.').flatMap(key => { | ||
var matches = pattern.exec(key); | ||
if (!matches) { | ||
return key; | ||
} | ||
return [matches[1], Number(matches[2])]; | ||
}); | ||
} | ||
function getItem(obj, key, defaultValue) { | ||
var target = obj; | ||
for (var path of getPaths(key)) { | ||
if (typeof target[path] === 'undefined') { | ||
return defaultValue; | ||
} | ||
target = target[path]; | ||
} | ||
return target; | ||
} | ||
function flatten(item, isLeaf) { | ||
@@ -197,4 +275,4 @@ var prefix = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ''; | ||
} else { | ||
for (var [key, _value] of Object.entries(item)) { | ||
entries.push(...flatten(_value, isLeaf, prefix ? "".concat(prefix, ".").concat(key) : key)); | ||
for (var [key, _value2] of Object.entries(item)) { | ||
entries.push(...flatten(_value2, isLeaf, prefix ? "".concat(prefix, ".").concat(key) : key)); | ||
} | ||
@@ -207,15 +285,6 @@ } | ||
function unflatten(entries) { | ||
var pattern = /(\w+)\[(\d+)\]/; | ||
var result = {}; | ||
for (var [key, _value2] of entries) { | ||
var paths = key.split('.').flatMap(key => { | ||
var matches = pattern.exec(key); | ||
if (!matches) { | ||
return key; | ||
} | ||
return [matches[1], Number(matches[2])]; | ||
}); | ||
for (var [key, _value3] of entries) { | ||
var paths = getPaths(key); | ||
var length = paths.length; | ||
@@ -229,3 +298,3 @@ var lastIndex = length - 1; | ||
var next = paths[index + 1]; | ||
var newValue = _value2; | ||
var newValue = _value3; | ||
@@ -247,129 +316,102 @@ if (index != lastIndex) { | ||
function validate(value, constraint) { | ||
var _constraint$pattern2; | ||
var badInput = false; | ||
var customError = false; | ||
var patternMismatch = false; | ||
var rangeOverflow = false; | ||
var rangeUnderflow = false; | ||
var stepMismatch = false; | ||
var tooLong = false; | ||
var tooShort = false; | ||
var typeMismatch = false; | ||
var valueMissing = false; | ||
if (value instanceof File) { | ||
return 'File is not supported yet'; | ||
} | ||
var _constraint$type; | ||
if (constraint.required) { | ||
if (typeof value === 'undefined' || value === '') { | ||
var _constraint$required$; | ||
typeMismatch = ((_constraint$type = constraint.type) === null || _constraint$type === void 0 ? void 0 : _constraint$type.value) !== 'file'; | ||
} else { | ||
var _constraint$pattern$s, _constraint$pattern2, _constraint$type2, _constraint$type3; | ||
return (_constraint$required$ = constraint.required.message) !== null && _constraint$required$ !== void 0 ? _constraint$required$ : 'This field is required'; | ||
} | ||
} | ||
var isURL = value => { | ||
try { | ||
new URL(value); | ||
return true; | ||
} catch (_unused) { | ||
return false; | ||
} | ||
}; | ||
if (constraint.minLength) { | ||
if (typeof value === 'undefined' || value.length < constraint.minLength.value) { | ||
var _constraint$minLength; | ||
return (_constraint$minLength = constraint.minLength.message) !== null && _constraint$minLength !== void 0 ? _constraint$minLength : "This field must be at least ".concat(constraint.minLength.value, " characters"); | ||
} | ||
patternMismatch = (_constraint$pattern$s = (_constraint$pattern2 = constraint.pattern) === null || _constraint$pattern2 === void 0 ? void 0 : _constraint$pattern2.some(pattern => { | ||
var match = value === null || value === void 0 ? void 0 : value.match(pattern.value); | ||
return !match || value !== match[0]; | ||
})) !== null && _constraint$pattern$s !== void 0 ? _constraint$pattern$s : false; | ||
rangeOverflow = constraint.max ? typeof value !== 'undefined' && constraint.max.value instanceof Date && new Date(value) > constraint.max.value || typeof value !== 'undefined' && typeof constraint.max.value === 'number' && Number(value) > constraint.max.value : false; | ||
rangeUnderflow = constraint.min ? constraint.min.value instanceof Date && new Date(value !== null && value !== void 0 ? value : '') < constraint.min.value || typeof constraint.min.value === 'number' && Number(value !== null && value !== void 0 ? value : '') < constraint.min.value : false; | ||
tooLong = constraint.maxLength ? typeof value !== 'undefined' && value.length > constraint.maxLength.value : false; | ||
tooShort = constraint.minLength ? typeof value === 'undefined' || value.length < constraint.minLength.value : false; | ||
typeMismatch = ((_constraint$type2 = constraint.type) === null || _constraint$type2 === void 0 ? void 0 : _constraint$type2.value) === 'email' && !/^\S+@\S+$/.test(value !== null && value !== void 0 ? value : '') || ((_constraint$type3 = constraint.type) === null || _constraint$type3 === void 0 ? void 0 : _constraint$type3.value) === 'url' && !isURL(value !== null && value !== void 0 ? value : ''); | ||
valueMissing = typeof value === 'undefined' || value === ''; | ||
} | ||
if (constraint.maxLength) { | ||
if (typeof value !== 'undefined' && value.length > constraint.maxLength.value) { | ||
var _constraint$maxLength; | ||
return { | ||
badInput, | ||
customError, | ||
patternMismatch, | ||
rangeOverflow, | ||
rangeUnderflow, | ||
stepMismatch, | ||
tooLong, | ||
tooShort, | ||
typeMismatch, | ||
valid: !patternMismatch && !rangeOverflow && !rangeUnderflow && !stepMismatch && !tooLong && !tooShort && !typeMismatch && !valueMissing, | ||
valueMissing | ||
}; | ||
} | ||
return (_constraint$maxLength = constraint.maxLength.message) !== null && _constraint$maxLength !== void 0 ? _constraint$maxLength : "This field must be at most ".concat(constraint.maxLength.value, " characters"); | ||
} | ||
} | ||
function checkCustomValidity(value, validity, constraint) { | ||
if (validity.valueMissing) { | ||
var _constraint$required$, _constraint$required; | ||
if (constraint.min) { | ||
if (constraint.min.value instanceof Date && new Date(value !== null && value !== void 0 ? value : '') < constraint.min.value) { | ||
var _constraint$min$messa; | ||
return (_constraint$required$ = (_constraint$required = constraint.required) === null || _constraint$required === void 0 ? void 0 : _constraint$required.message) !== null && _constraint$required$ !== void 0 ? _constraint$required$ : null; | ||
} else if (validity.tooShort) { | ||
var _constraint$minLength, _constraint$minLength2; | ||
return (_constraint$min$messa = constraint.min.message) !== null && _constraint$min$messa !== void 0 ? _constraint$min$messa : "This field must be later than ".concat(constraint.min.value.toISOString()); | ||
} else if (typeof constraint.min.value === 'number' && Number(value !== null && value !== void 0 ? value : '') < constraint.min.value) { | ||
var _constraint$min$messa2; | ||
return (_constraint$minLength = (_constraint$minLength2 = constraint.minLength) === null || _constraint$minLength2 === void 0 ? void 0 : _constraint$minLength2.message) !== null && _constraint$minLength !== void 0 ? _constraint$minLength : null; | ||
} else if (validity.tooLong) { | ||
var _constraint$maxLength, _constraint$maxLength2; | ||
return (_constraint$min$messa2 = constraint.min.message) !== null && _constraint$min$messa2 !== void 0 ? _constraint$min$messa2 : "This field must be greater than or equal to ".concat(constraint.min.value); | ||
} | ||
} | ||
return (_constraint$maxLength = (_constraint$maxLength2 = constraint.maxLength) === null || _constraint$maxLength2 === void 0 ? void 0 : _constraint$maxLength2.message) !== null && _constraint$maxLength !== void 0 ? _constraint$maxLength : null; | ||
} else if (validity.stepMismatch) { | ||
var _constraint$step$mess, _constraint$step; | ||
if (constraint.max) { | ||
if (typeof value !== 'undefined' && constraint.max.value instanceof Date && new Date(value) > constraint.max.value) { | ||
var _constraint$max$messa; | ||
return (_constraint$step$mess = (_constraint$step = constraint.step) === null || _constraint$step === void 0 ? void 0 : _constraint$step.message) !== null && _constraint$step$mess !== void 0 ? _constraint$step$mess : null; | ||
} else if (validity.rangeUnderflow) { | ||
var _constraint$min$messa, _constraint$min; | ||
return (_constraint$max$messa = constraint.max.message) !== null && _constraint$max$messa !== void 0 ? _constraint$max$messa : "This field must be at earlier than ".concat(constraint.max.value.toISOString()); | ||
} else if (typeof value !== 'undefined' && typeof constraint.max.value === 'number' && Number(value) > constraint.max.value) { | ||
var _constraint$max$messa2; | ||
return (_constraint$min$messa = (_constraint$min = constraint.min) === null || _constraint$min === void 0 ? void 0 : _constraint$min.message) !== null && _constraint$min$messa !== void 0 ? _constraint$min$messa : null; | ||
} else if (validity.rangeOverflow) { | ||
var _constraint$max$messa, _constraint$max; | ||
return (_constraint$max$messa2 = constraint.max.message) !== null && _constraint$max$messa2 !== void 0 ? _constraint$max$messa2 : "This field must be less than or equal to ".concat(constraint.max.value); | ||
} | ||
} | ||
return (_constraint$max$messa = (_constraint$max = constraint.max) === null || _constraint$max === void 0 ? void 0 : _constraint$max.message) !== null && _constraint$max$messa !== void 0 ? _constraint$max$messa : null; | ||
} else if (validity.typeMismatch || validity.badInput) { | ||
var _constraint$type$mess, _constraint$type4; | ||
if (constraint.step) ; | ||
return (_constraint$type$mess = (_constraint$type4 = constraint.type) === null || _constraint$type4 === void 0 ? void 0 : _constraint$type4.message) !== null && _constraint$type$mess !== void 0 ? _constraint$type$mess : null; | ||
} else if (validity.patternMismatch) { | ||
if (!constraint.pattern) { | ||
return null; | ||
} else if (constraint.pattern.length === 1) { | ||
var _constraint$pattern$; | ||
if (constraint.type) { | ||
switch (constraint.type.value) { | ||
case 'email': | ||
if (!/^\S+\@\S+$/.test(value !== null && value !== void 0 ? value : '')) { | ||
var _constraint$type$mess; | ||
return (_constraint$pattern$ = constraint.pattern[0].message) !== null && _constraint$pattern$ !== void 0 ? _constraint$pattern$ : null; | ||
} else { | ||
var _constraint$pattern$f, _constraint$pattern$f2; | ||
return (_constraint$type$mess = constraint.type.message) !== null && _constraint$type$mess !== void 0 ? _constraint$type$mess : "This field must be a valid email"; | ||
} | ||
break; | ||
case 'url': | ||
var isURL = value => { | ||
try { | ||
new URL(value); | ||
return true; | ||
} catch (_unused) { | ||
return false; | ||
} | ||
}; | ||
if (!isURL(value !== null && value !== void 0 ? value : '')) { | ||
var _constraint$type$mess2; | ||
return (_constraint$type$mess2 = constraint.type.message) !== null && _constraint$type$mess2 !== void 0 ? _constraint$type$mess2 : "This field must be a valid URL"; | ||
} | ||
break; | ||
return (_constraint$pattern$f = (_constraint$pattern$f2 = constraint.pattern.find(pattern => pattern.value.test(value))) === null || _constraint$pattern$f2 === void 0 ? void 0 : _constraint$pattern$f2.message) !== null && _constraint$pattern$f !== void 0 ? _constraint$pattern$f : null; | ||
} | ||
} else { | ||
return ''; | ||
} | ||
if ((_constraint$pattern2 = constraint.pattern) !== null && _constraint$pattern2 !== void 0 && _constraint$pattern2.length) { | ||
var _pattern = constraint.pattern.find(pattern => { | ||
var match = value === null || value === void 0 ? void 0 : value.match(pattern.value); | ||
return !match || value !== match[0]; | ||
}); | ||
if (_pattern) { | ||
var _pattern$message; | ||
return (_pattern$message = _pattern.message) !== null && _pattern$message !== void 0 ? _pattern$message : "This field must be a valid format"; | ||
} | ||
} | ||
return null; | ||
} | ||
function parse(payload, fieldsetCreator) { | ||
var valueEntries = payload instanceof URLSearchParams || payload instanceof FormData ? payload : new URLSearchParams(payload); | ||
var value = unflatten(valueEntries); | ||
var fieldset = typeof fieldsetCreator === 'function' ? fieldsetCreator(value) : fieldsetCreator; | ||
var values = Object.fromEntries(valueEntries); | ||
var errorEntries = []; | ||
for (var [name, field] of flatten(fieldset, f => typeof f[symbol] === 'function')) { | ||
var constraint = getConstraint(field); | ||
var _value3 = values[name]; | ||
var _message = validate(_value3, constraint); | ||
if (_message) { | ||
errorEntries.push([name, _message]); | ||
} | ||
} | ||
return { | ||
value, | ||
error: errorEntries.length > 0 ? unflatten(errorEntries) : null | ||
}; | ||
} | ||
export { f, getConstraint, isButtonElement, isDirtyField, isElement, isInputElement, isSelectElement, isTextareaElement, isValidationConstraintSupported, parse, shouldSkipValidate }; | ||
export { checkCustomValidity, draftUpdate, f, getConstraint, getDraft, isDirty, isElement, isValidationConstraintSupported, parse, shouldSkipValidate }; |
@@ -5,3 +5,3 @@ { | ||
"license": "MIT", | ||
"version": "0.0.2", | ||
"version": "0.0.3", | ||
"main": "index.js", | ||
@@ -8,0 +8,0 @@ "module": "module/index.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
32420
796
1