convert to JSDoc comments
This commit is contained in:
151
index.ts
151
index.ts
@@ -1,60 +1,70 @@
|
|||||||
import type { Action } from 'svelte/action';
|
import type { Action } from 'svelte/action';
|
||||||
|
|
||||||
// InputElement is a union of all input types that can be validated.
|
/** InputElement is a union of all input types that can be validated. */
|
||||||
export type InputElement = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;
|
export type InputElement = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;
|
||||||
// InputNodeList is a union of all node lists that can be validated.
|
/** InputNodeList is a union of all node lists that can be validated. */
|
||||||
export type InputNodeList = NodeListOf<HTMLInputElement> | NodeListOf<HTMLTextAreaElement> | [];
|
export type InputNodeList = NodeListOf<HTMLInputElement> | NodeListOf<HTMLTextAreaElement> | [];
|
||||||
|
|
||||||
// ValidatorOptions configures the behavior of a validator.
|
/** ValidatorOptions configures the behavior of a validator. */
|
||||||
export type ValidatorOptions = {
|
export type ValidatorOptions = {
|
||||||
required?: boolean; // required is a flag that indicates whether the input is required.
|
/** required is a flag that indicates whether the input is required. */
|
||||||
pattern?: RegExp; // pattern is a regex pattern that the input value must match.
|
required?: boolean;
|
||||||
minlength?: number; // minlength is the minimum length of the input value.
|
/** pattern is a regex pattern that the input value must match. */
|
||||||
maxlength?: number; // maxlength is the maximum length of the input value.
|
pattern?: RegExp;
|
||||||
length?: number; // length is the exact length of the input value.
|
/** minlength is the minimum length of the input value. */
|
||||||
type?: 'email' | 'phone' | 'score'; // NOT IMPLEMENTED. type is a predefined validation type.
|
minlength?: number;
|
||||||
baseval?: string; // baseval is a value that the input value must not match (an alternate zero-value).
|
/** maxlength is the maximum length of the input value. */
|
||||||
autovalOnInvalid?: boolean; // autovalOnInvalid is a flag that automatically adds a keyup listener to the input on invalid.
|
maxlength?: number;
|
||||||
|
/** length is the exact length of the input value. */
|
||||||
|
length?: number;
|
||||||
|
/** NOT IMPLEMENTED. type is a predefined validation type. */
|
||||||
|
type?: 'email' | 'phone' | 'score';
|
||||||
|
/** baseval is a value that the input value must not match (an alternate zero-value). */
|
||||||
|
baseval?: string;
|
||||||
|
/** autovalOnInvalid is a flag that automatically adds a keyup listener to the input on invalid. */
|
||||||
|
autovalOnInvalid?: boolean;
|
||||||
func?: (node: InputElement) => boolean | Promise<boolean>;
|
func?: (node: InputElement) => boolean | Promise<boolean>;
|
||||||
valfunc?: (val: string) => boolean | Promise<boolean>;
|
valfunc?: (val: string) => boolean | Promise<boolean>;
|
||||||
};
|
};
|
||||||
|
|
||||||
// InputValidatorPayload carries the current value of an input element when it is validated.
|
/** InputValidatorPayload carries the current value of an input element when it is validated. */
|
||||||
export type InputValidatorPayload = { value: string; valid: boolean };
|
export type InputValidatorPayload = { value: string; valid: boolean };
|
||||||
// InputValidatorEvent is a custom event that is dispatched when an input is validated.
|
/** InputValidatorEvent is a custom event that is dispatched when an input is validated. */
|
||||||
export class InputValidatorEvent extends CustomEvent<InputValidatorPayload> {}
|
export class InputValidatorEvent extends CustomEvent<InputValidatorPayload> {}
|
||||||
// FormValidatorPayload carries a list of invalid and valid inputs when a form is validated.
|
/** FormValidatorPayload carries a list of invalid and valid inputs when a form is validated. */
|
||||||
export type FormValidatorPayload = {
|
export type FormValidatorPayload = {
|
||||||
invalidInputs: InputElement[];
|
invalidInputs: InputElement[];
|
||||||
validInputs: InputElement[];
|
validInputs: InputElement[];
|
||||||
valid: boolean;
|
valid: boolean;
|
||||||
};
|
};
|
||||||
// FormValidatorEvent is a custom event that is dispatched when a form is validated.
|
/** FormValidatorEvent is a custom event that is dispatched when a form is validated. */
|
||||||
export class FormValidatorEvent extends CustomEvent<FormValidatorPayload> {}
|
export class FormValidatorEvent extends CustomEvent<FormValidatorPayload> {}
|
||||||
|
|
||||||
// ValidatorState is the state of a validator.
|
/** ValidatorState is the state of a validator. */
|
||||||
export type ValidatorState = 'unknown' | 'valid' | 'invalid';
|
export type ValidatorState = 'unknown' | 'valid' | 'invalid';
|
||||||
const VALIDATOR_VALID: ValidatorState = 'valid';
|
const VALIDATOR_VALID: ValidatorState = 'valid';
|
||||||
const VALIDATOR_INVALID: ValidatorState = 'invalid';
|
const VALIDATOR_INVALID: ValidatorState = 'invalid';
|
||||||
const VALIDATOR_UNKNOWN: ValidatorState = 'unknown';
|
const VALIDATOR_UNKNOWN: ValidatorState = 'unknown';
|
||||||
|
|
||||||
// QUERY_INPUTS is the query string for all input elements that can be validated.
|
/** QUERY_INPUTS is the query string for all input elements that can be validated. */
|
||||||
const QUERY_INPUTS = 'input[data-validate-identifier], textarea[data-validate-identifier]';
|
const QUERY_INPUTS = 'input[data-validate-identifier], textarea[data-validate-identifier]';
|
||||||
|
|
||||||
// DATA_ID is the key for the validator index in the input element's dataset.
|
/** DATA_ID is the key for the validator index in the input element's dataset. */
|
||||||
const DATA_ID = 'validateIdentifier';
|
const DATA_ID = 'validateIdentifier';
|
||||||
// DATA_STATE is the key for the validation state in the input element's dataset.
|
/** DATA_STATE is the key for the validation state in the input element's dataset. */
|
||||||
const DATA_STATE = 'validateState';
|
const DATA_STATE = 'validateState';
|
||||||
|
|
||||||
// email is a regex pattern for validating email addresses.
|
/** email is a regex pattern for validating email addresses. */
|
||||||
export const email: RegExp = new RegExp(String.raw`^[^@\s]+@[^@\s]+\.[^@\s]+$`);
|
export const email: RegExp = new RegExp(String.raw`^[^@\s]+@[^@\s]+\.[^@\s]+$`);
|
||||||
// phone is a regex pattern for validating phone numbers.
|
/** phone is a regex pattern for validating phone numbers. */
|
||||||
export const phone: RegExp = new RegExp(String.raw`^(\+)?(\(?\d+\)?)(([\s-]+)?(\d+)){0,}$`);
|
export const phone: RegExp = new RegExp(String.raw`^(\+)?(\(?\d+\)?)(([\s-]+)?(\d+)){0,}$`);
|
||||||
// score is a regex pattern for validating lesson grades.
|
/** score is a regex pattern for validating lesson grades. */
|
||||||
export const score: RegExp = new RegExp(String.raw`^(-?\d{0,2}|100)$`);
|
export const score: RegExp = new RegExp(String.raw`^(-?\d{0,2}|100)$`);
|
||||||
|
|
||||||
// InputState is some historical state of an input element, tracking its value,
|
/**
|
||||||
// selectionStart and selectionEnd.
|
* InputState is some historical state of an input element, tracking its value,
|
||||||
|
* selectionStart and selectionEnd.
|
||||||
|
*/
|
||||||
export type InputState = {
|
export type InputState = {
|
||||||
value: string;
|
value: string;
|
||||||
selectionStart: number;
|
selectionStart: number;
|
||||||
@@ -65,8 +75,10 @@ let nextValidatorID = 0;
|
|||||||
const validators: Record<number, ValidatorOptions> = {};
|
const validators: Record<number, ValidatorOptions> = {};
|
||||||
const lastState: Record<number, InputState> = {};
|
const lastState: Record<number, InputState> = {};
|
||||||
|
|
||||||
// validate attaches rules to an input element that can be used to validate the input.
|
/**
|
||||||
// If opts is undefined, no validation rules will be attached.
|
* validate attaches rules to an input element that can be used to validate the input.
|
||||||
|
* If opts is undefined, no validation rules will be attached.
|
||||||
|
*/
|
||||||
export const validate: Action<
|
export const validate: Action<
|
||||||
InputElement,
|
InputElement,
|
||||||
ValidatorOptions | undefined,
|
ValidatorOptions | undefined,
|
||||||
@@ -105,10 +117,12 @@ export const validate: Action<
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// keydownValidator attaches a keydown event listener to an input element that will
|
/**
|
||||||
// process the input value according to any attached validation rules, triggering
|
* keydownValidator attaches a keydown event listener to an input element that will
|
||||||
// valid or invalid depending on validation success. If opts.constrain is true,
|
* process the input value according to any attached validation rules, triggering
|
||||||
// the input value will be constrained to valid characters.
|
* valid or invalid depending on validation success. If opts.constrain is true,
|
||||||
|
* the input value will be constrained to valid characters.
|
||||||
|
*/
|
||||||
export const keydownValidator: Action<
|
export const keydownValidator: Action<
|
||||||
InputElement,
|
InputElement,
|
||||||
{
|
{
|
||||||
@@ -131,9 +145,11 @@ export const keydownValidator: Action<
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// keyupValidator attaches a keydown event listener to an input element that will
|
/**
|
||||||
// process the input value according to any attached validation rules, triggering
|
* keyupValidator attaches a keydown event listener to an input element that will
|
||||||
// the `validate` event with the input value and validation state.
|
* process the input value according to any attached validation rules, triggering
|
||||||
|
* the `validate` event with the input value and validation state.
|
||||||
|
*/
|
||||||
export const keyupValidator: Action<InputElement> = (el) => {
|
export const keyupValidator: Action<InputElement> = (el) => {
|
||||||
const node = el as HTMLInputElement;
|
const node = el as HTMLInputElement;
|
||||||
|
|
||||||
@@ -147,9 +163,11 @@ export const keyupValidator: Action<InputElement> = (el) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// inputValidator attaches an oninput event listener to an input element that will
|
/**
|
||||||
// process the input value according to any attached validation rules, triggering
|
* inputValidator attaches an oninput event listener to an input element that will
|
||||||
// the `validate` event with the input value and validation state.
|
* process the input value according to any attached validation rules, triggering
|
||||||
|
* the `validate` event with the input value and validation state.
|
||||||
|
*/
|
||||||
export const inputValidator: Action<InputElement> = (el) => {
|
export const inputValidator: Action<InputElement> = (el) => {
|
||||||
const node = el as HTMLInputElement;
|
const node = el as HTMLInputElement;
|
||||||
|
|
||||||
@@ -162,10 +180,12 @@ export const inputValidator: Action<InputElement> = (el) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// liveValidator attaches multiple event listeners to an input element that will
|
/**
|
||||||
// process the input value according to any attached validation rules, triggering
|
* liveValidator attaches multiple event listeners to an input element that will
|
||||||
// the `validate` event with the input value and validation state. liveValidator
|
* process the input value according to any attached validation rules, triggering
|
||||||
// supports the constrain option without introducing edge cases with text selection.
|
* the `validate` event with the input value and validation state. liveValidator
|
||||||
|
* supports the constrain option without introducing edge cases with text selection.
|
||||||
|
*/
|
||||||
export const liveValidator: Action<
|
export const liveValidator: Action<
|
||||||
InputElement,
|
InputElement,
|
||||||
{
|
{
|
||||||
@@ -227,11 +247,13 @@ export const liveValidator: Action<
|
|||||||
node.addEventListener('input', inputHandler);
|
node.addEventListener('input', inputHandler);
|
||||||
};
|
};
|
||||||
|
|
||||||
// submitValidator attaches a submit event listener to a form element that will
|
/**
|
||||||
// process the input values of all children according to any attached validation
|
* submitValidator attaches a submit event listener to a form element that will
|
||||||
// rules, triggering the validate event for individual input elements
|
* process the input values of all children according to any attached validation
|
||||||
// depending on validation success. Similarly, the validate event
|
* rules, triggering the validate event for individual input elements
|
||||||
// event will be triggered on the form element itself.
|
* depending on validation success. Similarly, the validate event
|
||||||
|
* event will be triggered on the form element itself.
|
||||||
|
*/
|
||||||
export const submitValidator: Action<
|
export const submitValidator: Action<
|
||||||
HTMLFormElement,
|
HTMLFormElement,
|
||||||
undefined,
|
undefined,
|
||||||
@@ -254,8 +276,7 @@ export const submitValidator: Action<
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// disableFormDefault helper action prevents the default form submission behavior
|
/** disableFormDefault helper action prevents the default form submission behavior and disables all browser validation. */
|
||||||
// and disables all browser validation.
|
|
||||||
export const disableFormDefault: Action<HTMLFormElement> = (form) => {
|
export const disableFormDefault: Action<HTMLFormElement> = (form) => {
|
||||||
form.setAttribute('novalidate', 'true');
|
form.setAttribute('novalidate', 'true');
|
||||||
form.addEventListener('submit', (event) => {
|
form.addEventListener('submit', (event) => {
|
||||||
@@ -263,10 +284,12 @@ export const disableFormDefault: Action<HTMLFormElement> = (form) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// validateInput checks an input element's value against its validation rules, triggering
|
/**
|
||||||
// the validate events with the current value and validation state, updating the input's
|
* validateInput checks an input element's value against its validation rules, triggering
|
||||||
// dataset accordingly. If opts.autovalOnInvalid is true, the input will be revalidated on
|
* the validate events with the current value and validation state, updating the input's
|
||||||
// on keyup automatically from now on.
|
* dataset accordingly. If opts.autovalOnInvalid is true, the input will be revalidated on
|
||||||
|
* on keyup automatically from now on.
|
||||||
|
*/
|
||||||
export const validateInput = async (
|
export const validateInput = async (
|
||||||
input: InputElement,
|
input: InputElement,
|
||||||
valueOverride?: string
|
valueOverride?: string
|
||||||
@@ -289,9 +312,11 @@ export const validateInput = async (
|
|||||||
return valid;
|
return valid;
|
||||||
};
|
};
|
||||||
|
|
||||||
// validateForm checks all input elements in a form element against their validation rules,
|
/**
|
||||||
// triggering valid or invalid events for individual input elements depending on validation
|
* validateForm checks all input elements in a form element against their validation rules,
|
||||||
// success. Similarly, valid and invalid events will be triggered on the form element.
|
* triggering valid or invalid events for individual input elements depending on validation
|
||||||
|
* success. Similarly, valid and invalid events will be triggered on the form element.
|
||||||
|
*/
|
||||||
export const validateForm = async (form: HTMLFormElement): Promise<boolean> => {
|
export const validateForm = async (form: HTMLFormElement): Promise<boolean> => {
|
||||||
const inputs = form.querySelectorAll(QUERY_INPUTS);
|
const inputs = form.querySelectorAll(QUERY_INPUTS);
|
||||||
|
|
||||||
@@ -321,7 +346,7 @@ export const validateForm = async (form: HTMLFormElement): Promise<boolean> => {
|
|||||||
return valid;
|
return valid;
|
||||||
};
|
};
|
||||||
|
|
||||||
// isInputValid checks an input element's value against its validation rules.
|
/** isInputValid checks an input element's value against its validation rules. */
|
||||||
export const isInputValid = async (
|
export const isInputValid = async (
|
||||||
input: InputElement,
|
input: InputElement,
|
||||||
valueOverride?: string
|
valueOverride?: string
|
||||||
@@ -360,7 +385,7 @@ export const isInputValid = async (
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
// isFormValid checks all input elements in a form element against their validation rules.
|
/** isFormValid checks all input elements in a form element against their validation rules. */
|
||||||
export const isFormValid = async (form: HTMLFormElement): Promise<boolean> => {
|
export const isFormValid = async (form: HTMLFormElement): Promise<boolean> => {
|
||||||
const inputs = form.querySelectorAll(QUERY_INPUTS);
|
const inputs = form.querySelectorAll(QUERY_INPUTS);
|
||||||
|
|
||||||
@@ -375,8 +400,10 @@ export const isFormValid = async (form: HTMLFormElement): Promise<boolean> => {
|
|||||||
return valid;
|
return valid;
|
||||||
};
|
};
|
||||||
|
|
||||||
// isValueValid checks a value against a set of validation rules. Note: node-based
|
/**
|
||||||
// custom validator functions are not supported by this function.
|
* isValueValid checks a value against a set of validation rules. Note: node-based
|
||||||
|
* custom validator functions are not supported by this function.
|
||||||
|
*/
|
||||||
export const isValueValid = async (val: string, opts: ValidatorOptions): Promise<boolean> => {
|
export const isValueValid = async (val: string, opts: ValidatorOptions): Promise<boolean> => {
|
||||||
console.debug('isValueValid', `val="${val}"`, 'opts:', opts);
|
console.debug('isValueValid', `val="${val}"`, 'opts:', opts);
|
||||||
// if input is required and empty, return false
|
// if input is required and empty, return false
|
||||||
@@ -424,15 +451,17 @@ export const isValueValid = async (val: string, opts: ValidatorOptions): Promise
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
// getid returns the validator ID attached to an input element. Returns -1 if
|
/**
|
||||||
// no ID is attached.
|
* getid returns the validator ID attached to an input element. Returns -1 if
|
||||||
|
* no ID is attached.
|
||||||
|
*/
|
||||||
export const getid = (input: InputElement): number => {
|
export const getid = (input: InputElement): number => {
|
||||||
const idstr = input.dataset[DATA_ID] || '-1';
|
const idstr = input.dataset[DATA_ID] || '-1';
|
||||||
const id = parseInt(idstr);
|
const id = parseInt(idstr);
|
||||||
return id;
|
return id;
|
||||||
};
|
};
|
||||||
|
|
||||||
// getopts returns the validation rules attached to an input element.
|
/** getopts returns the validation rules attached to an input element. */
|
||||||
export const getopts = (input: InputElement): ValidatorOptions | undefined => {
|
export const getopts = (input: InputElement): ValidatorOptions | undefined => {
|
||||||
const id = getid(input);
|
const id = getid(input);
|
||||||
return validators[id];
|
return validators[id];
|
||||||
|
|||||||
10
sanitize.ts
10
sanitize.ts
@@ -1,3 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* Sanitizes a FormData value by key, returning a trimmed string.
|
||||||
|
* If the key is not present, it throws an error or returns a fallback value.
|
||||||
|
* @param data - The FormData object to sanitize.
|
||||||
|
* @param key - The key to look for in the FormData.
|
||||||
|
* @param fallback - Optional fallback value to return if the key is not found.
|
||||||
|
* @returns The sanitized string value or the fallback value.
|
||||||
|
* @throws Error if the key is required and not found.
|
||||||
|
* @template Fallback - The type of the fallback value.
|
||||||
|
*/
|
||||||
export function sanitize(data: FormData, key: string): string;
|
export function sanitize(data: FormData, key: string): string;
|
||||||
export function sanitize<Fallback>(
|
export function sanitize<Fallback>(
|
||||||
data: FormData,
|
data: FormData,
|
||||||
|
|||||||
Reference in New Issue
Block a user