Setup eslint and enforce rules
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import {Container, Injectable, InjectParam} from '../di'
|
||||
import {Request} from "../http/lifecycle/Request";
|
||||
import {Request} from '../http/lifecycle/Request'
|
||||
import {Valid, ValidationRules} from './rules/types'
|
||||
import {Validator} from './Validator'
|
||||
import {AppClass} from "../lifecycle/AppClass";
|
||||
import {DataContainer} from "../http/lifecycle/Request";
|
||||
import {AppClass} from '../lifecycle/AppClass'
|
||||
import {DataContainer} from '../http/lifecycle/Request'
|
||||
|
||||
/**
|
||||
* Base class for defining reusable validators for request routes.
|
||||
@@ -30,10 +30,12 @@ export abstract class FormRequest<T> extends AppClass {
|
||||
|
||||
constructor(
|
||||
@InjectParam(Request)
|
||||
protected readonly data: DataContainer
|
||||
) { super() }
|
||||
protected readonly data: DataContainer,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
protected container() {
|
||||
protected container(): Container {
|
||||
return (this.data as unknown) as Container
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Valid, ValidationResult, ValidationRules, ValidatorFunction, ValidatorFunctionParams} from "./rules/types";
|
||||
import {Messages, ErrorWithContext, dataWalkUnsafe, dataSetUnsafe} from "../util";
|
||||
import {Valid, ValidationResult, ValidationRules, ValidatorFunction, ValidatorFunctionParams} from './rules/types'
|
||||
import {Messages, ErrorWithContext, dataWalkUnsafe, dataSetUnsafe} from '../util'
|
||||
|
||||
/**
|
||||
* An error thrown thrown when an object fails its validation.
|
||||
@@ -7,15 +7,16 @@ import {Messages, ErrorWithContext, dataWalkUnsafe, dataSetUnsafe} from "../util
|
||||
export class ValidationError<T> extends ErrorWithContext {
|
||||
constructor(
|
||||
/** The original input data. */
|
||||
public readonly data: any,
|
||||
public readonly data: unknown,
|
||||
|
||||
/** The validator instance used. */
|
||||
public readonly validator: Validator<T>,
|
||||
|
||||
/** Validation error messages, by field. */
|
||||
public readonly errors: Messages
|
||||
public readonly errors: Messages,
|
||||
) {
|
||||
super('One or more fields were invalid.', { data, messages: errors.all() });
|
||||
super('One or more fields were invalid.', { data,
|
||||
messages: errors.all() })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +26,7 @@ export class ValidationError<T> extends ErrorWithContext {
|
||||
export class Validator<T> {
|
||||
constructor(
|
||||
/** The rules used to validate input objects. */
|
||||
protected readonly rules: ValidationRules
|
||||
protected readonly rules: ValidationRules,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -47,7 +48,7 @@ export class Validator<T> {
|
||||
* Returns true if the given data is valid and type aliases it as Valid<T>.
|
||||
* @param data
|
||||
*/
|
||||
public async isValid(data: any): Promise<boolean> {
|
||||
public async isValid(data: unknown): Promise<boolean> {
|
||||
return !(await this.validateAndGetErrors(data)).any()
|
||||
}
|
||||
|
||||
@@ -56,18 +57,20 @@ export class Validator<T> {
|
||||
* @param data
|
||||
* @protected
|
||||
*/
|
||||
protected async validateAndGetErrors(data: any): Promise<Messages> {
|
||||
protected async validateAndGetErrors(data: unknown): Promise<Messages> {
|
||||
const messages = new Messages()
|
||||
const params: ValidatorFunctionParams = { data }
|
||||
|
||||
for ( const key in this.rules ) {
|
||||
if ( !this.rules.hasOwnProperty(key) ) continue;
|
||||
if ( !Object.prototype.hasOwnProperty.call(this.rules, key) ) {
|
||||
continue
|
||||
}
|
||||
|
||||
// This walks over all of the values in the data structure using the nested
|
||||
// key notation. It's not type-safe, but neither is the original input object
|
||||
// yet, so it's useful here.
|
||||
for ( const walkEntry of dataWalkUnsafe<any>(data, key) ) {
|
||||
let [entry, dataKey] = walkEntry
|
||||
for ( const walkEntry of dataWalkUnsafe<any>(data as any, key) ) {
|
||||
let [entry, dataKey] = walkEntry // eslint-disable-line prefer-const
|
||||
const rules = (Array.isArray(this.rules[key]) ? this.rules[key] : [this.rules[key]]) as ValidatorFunction[]
|
||||
|
||||
for ( const rule of rules ) {
|
||||
@@ -83,13 +86,15 @@ export class Validator<T> {
|
||||
}
|
||||
|
||||
for ( const error of errors ) {
|
||||
if ( !messages.has(dataKey, error) ) messages.put(dataKey, error)
|
||||
if ( !messages.has(dataKey, error) ) {
|
||||
messages.put(dataKey, error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( result.valid && result.castValue ) {
|
||||
entry = result.castValue
|
||||
data = dataSetUnsafe(dataKey, entry, data)
|
||||
data = dataSetUnsafe(dataKey, entry, data as any)
|
||||
}
|
||||
|
||||
if ( result.stopValidation ) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import {Instantiable} from '../di'
|
||||
import {FormRequest} from './FormRequest'
|
||||
import {ValidationError} from './Validator'
|
||||
import {ResponseObject, RouteHandler} from "../http/routing/Route";
|
||||
import {Request} from "../http/lifecycle/Request";
|
||||
import {ResponseObject, RouteHandler} from '../http/routing/Route'
|
||||
import {Request} from '../http/lifecycle/Request'
|
||||
|
||||
/**
|
||||
* Builds a middleware function that validates a request's input against
|
||||
|
||||
@@ -1,130 +1,150 @@
|
||||
import {ValidationResult, ValidatorFunction} from "./types";
|
||||
import {ValidationResult, ValidatorFunction} from './types'
|
||||
|
||||
export namespace Arr {
|
||||
/** Requires the input value to be an array. */
|
||||
export function is(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( Array.isArray(inputValue) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must be an array'
|
||||
}
|
||||
/** Requires the input value to be an array. */
|
||||
function is(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
if ( Array.isArray(inputValue) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
/** Requires the values in the input value array to be distinct. */
|
||||
export function distinct(fieldName: string, inputValue: any): ValidationResult {
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must be an array',
|
||||
}
|
||||
}
|
||||
|
||||
/** Requires the values in the input value array to be distinct. */
|
||||
function distinct(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
const arr = is(fieldName, inputValue)
|
||||
if ( !arr.valid ) {
|
||||
return arr
|
||||
}
|
||||
|
||||
if ( Array.isArray(inputValue) && (new Set(inputValue)).size === inputValue.length ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must not contain duplicate values',
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input array to contain the given value.
|
||||
* @param value
|
||||
*/
|
||||
function includes(value: unknown): ValidatorFunction {
|
||||
return (fieldName: string, inputValue: unknown): ValidationResult => {
|
||||
const arr = is(fieldName, inputValue)
|
||||
if ( !arr.valid ) return arr
|
||||
if ( !arr.valid ) {
|
||||
return arr
|
||||
}
|
||||
|
||||
if ( (new Set(inputValue)).size === inputValue.length ) {
|
||||
if ( Array.isArray(inputValue) && inputValue.includes(value) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must not contain duplicate values'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input array to contain the given value.
|
||||
* @param value
|
||||
*/
|
||||
export function includes(value: any): ValidatorFunction {
|
||||
return function includes(fieldName: string, inputValue: any): ValidationResult {
|
||||
const arr = is(fieldName, inputValue)
|
||||
if ( !arr.valid ) return arr
|
||||
|
||||
if ( inputValue.includes(value) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must include ${value}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input array NOT to contain the given value.
|
||||
* @param value
|
||||
*/
|
||||
export function excludes(value: any): ValidatorFunction {
|
||||
return function excludes(fieldName: string, inputValue: any): ValidationResult {
|
||||
const arr = is(fieldName, inputValue)
|
||||
if ( !arr.valid ) return arr
|
||||
|
||||
if ( !inputValue.includes(value) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must not include ${value}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input array to have exactly `len` many entries.
|
||||
* @param len
|
||||
*/
|
||||
export function length(len: number): ValidatorFunction {
|
||||
return function length(fieldName: string, inputValue: any): ValidationResult {
|
||||
const arr = is(fieldName, inputValue)
|
||||
if ( !arr.valid ) return arr
|
||||
|
||||
if ( inputValue.length === len ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be exactly of length ${len}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input array to have at least `len` many entries.
|
||||
* @param len
|
||||
*/
|
||||
export function lengthMin(len: number): ValidatorFunction {
|
||||
return function lengthMin(fieldName: string, inputValue: any): ValidationResult {
|
||||
const arr = is(fieldName, inputValue)
|
||||
if ( !arr.valid ) return arr
|
||||
|
||||
if ( inputValue.length >= len ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be at least length ${len}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input array to have at most `len` many entries.
|
||||
* @param len
|
||||
*/
|
||||
export function lengthMax(len: number): ValidatorFunction {
|
||||
return function lengthMax(fieldName: string, inputValue: any): ValidationResult {
|
||||
const arr = is(fieldName, inputValue)
|
||||
if ( !arr.valid ) return arr
|
||||
|
||||
if ( inputValue.length <= len ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be at most length ${len}`
|
||||
}
|
||||
message: `must include ${value}`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input array NOT to contain the given value.
|
||||
* @param value
|
||||
*/
|
||||
function excludes(value: unknown): ValidatorFunction {
|
||||
return (fieldName: string, inputValue: unknown): ValidationResult => {
|
||||
const arr = is(fieldName, inputValue)
|
||||
if ( !arr.valid ) {
|
||||
return arr
|
||||
}
|
||||
|
||||
if ( Array.isArray(inputValue) && !inputValue.includes(value) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must not include ${value}`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input array to have exactly `len` many entries.
|
||||
* @param len
|
||||
*/
|
||||
function length(len: number): ValidatorFunction {
|
||||
return (fieldName: string, inputValue: unknown): ValidationResult => {
|
||||
const arr = is(fieldName, inputValue)
|
||||
if ( !arr.valid ) {
|
||||
return arr
|
||||
}
|
||||
|
||||
if ( Array.isArray(inputValue) && inputValue.length === len ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be exactly of length ${len}`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input array to have at least `len` many entries.
|
||||
* @param len
|
||||
*/
|
||||
function lengthMin(len: number): ValidatorFunction {
|
||||
return (fieldName: string, inputValue: unknown): ValidationResult => {
|
||||
const arr = is(fieldName, inputValue)
|
||||
if ( !arr.valid ) {
|
||||
return arr
|
||||
}
|
||||
|
||||
if ( Array.isArray(inputValue) && inputValue.length >= len ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be at least length ${len}`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input array to have at most `len` many entries.
|
||||
* @param len
|
||||
*/
|
||||
function lengthMax(len: number): ValidatorFunction {
|
||||
return (fieldName: string, inputValue: unknown): ValidationResult => {
|
||||
const arr = is(fieldName, inputValue)
|
||||
if ( !arr.valid ) {
|
||||
return arr
|
||||
}
|
||||
|
||||
if ( Array.isArray(inputValue) && inputValue.length <= len ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be at most length ${len}`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const Arr = {
|
||||
is,
|
||||
distinct,
|
||||
includes,
|
||||
excludes,
|
||||
length,
|
||||
lengthMin,
|
||||
lengthMax,
|
||||
}
|
||||
|
||||
@@ -1,70 +1,80 @@
|
||||
import {infer as inferUtil} from '../../util'
|
||||
import {ValidationResult} from "./types";
|
||||
import {ValidationResult} from './types'
|
||||
|
||||
export namespace Cast {
|
||||
/** Attempt to infer the native type of a string value. */
|
||||
export function infer(fieldName: string, inputValue: any): ValidationResult {
|
||||
return {
|
||||
valid: true,
|
||||
castValue: typeof inputValue === 'string' ? inferUtil(inputValue) : inputValue,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts the input value to a boolean.
|
||||
* Note that this assumes the value may be boolish. The strings "true", "True",
|
||||
* "TRUE", and "1" evaluate to `true`, while "false", "False", "FALSE", and "0"
|
||||
* evaluate to `false`.
|
||||
* @param fieldName
|
||||
* @param inputValue
|
||||
*/
|
||||
export function boolean(fieldName: string, inputValue: any): ValidationResult {
|
||||
let castValue = !!inputValue
|
||||
|
||||
if ( ['true', 'True', 'TRUE', '1'].includes(inputValue) ) castValue = true
|
||||
if ( ['false', 'False', 'FALSE', '0'].includes(inputValue) ) castValue = false
|
||||
|
||||
return {
|
||||
valid: true,
|
||||
castValue,
|
||||
}
|
||||
}
|
||||
|
||||
/** Casts the input value to a string. */
|
||||
export function string(fieldName: string, inputValue: any): ValidationResult {
|
||||
return {
|
||||
valid: true,
|
||||
castValue: String(inputValue),
|
||||
}
|
||||
}
|
||||
|
||||
/** Casts the input value to a number, if it is numerical. Fails otherwise. */
|
||||
export function numeric(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( !isNaN(parseFloat(inputValue)) ) {
|
||||
return {
|
||||
valid: true,
|
||||
castValue: parseFloat(inputValue)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must be numeric',
|
||||
}
|
||||
}
|
||||
|
||||
/** Casts the input value to an integer. Fails otherwise. */
|
||||
export function integer(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( !isNaN(parseInt(inputValue)) ) {
|
||||
return {
|
||||
valid: true,
|
||||
castValue: parseInt(inputValue)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must be an integer',
|
||||
}
|
||||
/** Attempt to infer the native type of a string value. */
|
||||
function infer(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
return {
|
||||
valid: true,
|
||||
castValue: typeof inputValue === 'string' ? inferUtil(inputValue) : inputValue,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts the input value to a boolean.
|
||||
* Note that this assumes the value may be boolish. The strings "true", "True",
|
||||
* "TRUE", and "1" evaluate to `true`, while "false", "False", "FALSE", and "0"
|
||||
* evaluate to `false`.
|
||||
* @param fieldName
|
||||
* @param inputValue
|
||||
*/
|
||||
function boolean(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
let castValue = Boolean(inputValue)
|
||||
|
||||
if ( ['true', 'True', 'TRUE', '1'].includes(String(inputValue)) ) {
|
||||
castValue = true
|
||||
}
|
||||
if ( ['false', 'False', 'FALSE', '0'].includes(String(inputValue)) ) {
|
||||
castValue = false
|
||||
}
|
||||
|
||||
return {
|
||||
valid: true,
|
||||
castValue,
|
||||
}
|
||||
}
|
||||
|
||||
/** Casts the input value to a string. */
|
||||
function string(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
return {
|
||||
valid: true,
|
||||
castValue: String(inputValue),
|
||||
}
|
||||
}
|
||||
|
||||
/** Casts the input value to a number, if it is numerical. Fails otherwise. */
|
||||
function numeric(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
if ( !isNaN(parseFloat(String(inputValue))) ) {
|
||||
return {
|
||||
valid: true,
|
||||
castValue: parseFloat(String(inputValue)),
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must be numeric',
|
||||
}
|
||||
}
|
||||
|
||||
/** Casts the input value to an integer. Fails otherwise. */
|
||||
function integer(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
if ( !isNaN(parseInt(String(inputValue), 10)) ) {
|
||||
return {
|
||||
valid: true,
|
||||
castValue: parseInt(String(inputValue), 10),
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must be an integer',
|
||||
}
|
||||
}
|
||||
|
||||
export const Cast = {
|
||||
infer,
|
||||
boolean,
|
||||
string,
|
||||
numeric,
|
||||
integer,
|
||||
}
|
||||
|
||||
@@ -1,197 +1,210 @@
|
||||
import {ValidationResult, ValidatorFunction} from "./types";
|
||||
import {ValidationResult, ValidatorFunction} from './types'
|
||||
|
||||
export namespace Num {
|
||||
/**
|
||||
* Builds a validator function that requires the input value to be greater than some value.
|
||||
* @param value
|
||||
*/
|
||||
export function greaterThan(value: number): ValidatorFunction {
|
||||
return function greaterThan(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( inputValue > value ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be greater than ${value}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input value to be at least some value.
|
||||
* @param value
|
||||
*/
|
||||
export function atLeast(value: number): ValidatorFunction {
|
||||
return function atLeast(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( inputValue >= value ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be at least ${value}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input value to be less than some value.
|
||||
* @param value
|
||||
*/
|
||||
export function lessThan(value: number): ValidatorFunction {
|
||||
return function lessThan(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( inputValue < value ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be less than ${value}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input value to be at most some value.
|
||||
* @param value
|
||||
*/
|
||||
export function atMost(value: number): ValidatorFunction {
|
||||
return function atMost(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( inputValue <= value ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be at most ${value}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input value to have exactly `num` many digits.
|
||||
* @param num
|
||||
*/
|
||||
export function digits(num: number): ValidatorFunction {
|
||||
return function digits(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( String(inputValue).replace('.', '').length === num ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must have exactly ${num} digits`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input value to have at least `num` many digits.
|
||||
* @param num
|
||||
*/
|
||||
export function digitsMin(num: number): ValidatorFunction {
|
||||
return function digitsMin(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( String(inputValue).replace('.', '').length >= num ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must have at least ${num} digits`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input value to have at most `num` many digits.
|
||||
* @param num
|
||||
*/
|
||||
export function digitsMax(num: number): ValidatorFunction {
|
||||
return function digitsMax(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( String(inputValue).replace('.', '').length <= num ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must have at most ${num} digits`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input value to end with the given number sequence.
|
||||
* @param num
|
||||
*/
|
||||
export function ends(num: number): ValidatorFunction {
|
||||
return function ends(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( String(inputValue).endsWith(String(num)) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must end with "${num}"`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input value to begin with the given number sequence.
|
||||
* @param num
|
||||
*/
|
||||
export function begins(num: number): ValidatorFunction {
|
||||
return function begins(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( String(inputValue).startsWith(String(num)) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must begin with "${num}"`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input value to be a multiple of the given number.
|
||||
* @param num
|
||||
*/
|
||||
export function multipleOf(num: number): ValidatorFunction {
|
||||
return function multipleOf(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( inputValue % num === 0 ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be a multiple of ${num}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Requires the input value to be even. */
|
||||
export function even(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( inputValue % 2 === 0 ) {
|
||||
/**
|
||||
* Builds a validator function that requires the input value to be greater than some value.
|
||||
* @param value
|
||||
*/
|
||||
function greaterThan(value: number): ValidatorFunction {
|
||||
return (fieldName: string, inputValue: unknown): ValidationResult => {
|
||||
if ( Number(inputValue) > value ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must be even',
|
||||
}
|
||||
}
|
||||
|
||||
/** Requires the input value to be odd. */
|
||||
export function odd(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( inputValue % 2 === 0 ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must be odd',
|
||||
message: `must be greater than ${value}`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input value to be at least some value.
|
||||
* @param value
|
||||
*/
|
||||
function atLeast(value: number): ValidatorFunction {
|
||||
return (fieldName: string, inputValue: unknown): ValidationResult => {
|
||||
if ( Number(inputValue) >= value ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be at least ${value}`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input value to be less than some value.
|
||||
* @param value
|
||||
*/
|
||||
function lessThan(value: number): ValidatorFunction {
|
||||
return (fieldName: string, inputValue: unknown): ValidationResult => {
|
||||
if ( Number(inputValue) < value ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be less than ${value}`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input value to be at most some value.
|
||||
* @param value
|
||||
*/
|
||||
function atMost(value: number): ValidatorFunction {
|
||||
return (fieldName: string, inputValue: unknown): ValidationResult => {
|
||||
if ( Number(inputValue) <= value ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be at most ${value}`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input value to have exactly `num` many digits.
|
||||
* @param num
|
||||
*/
|
||||
function digits(num: number): ValidatorFunction {
|
||||
return (fieldName: string, inputValue: unknown): ValidationResult => {
|
||||
if ( String(inputValue).replace('.', '').length === num ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must have exactly ${num} digits`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input value to have at least `num` many digits.
|
||||
* @param num
|
||||
*/
|
||||
function digitsMin(num: number): ValidatorFunction {
|
||||
return (fieldName: string, inputValue: unknown): ValidationResult => {
|
||||
if ( String(inputValue).replace('.', '').length >= num ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must have at least ${num} digits`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input value to have at most `num` many digits.
|
||||
* @param num
|
||||
*/
|
||||
function digitsMax(num: number): ValidatorFunction {
|
||||
return (fieldName: string, inputValue: unknown): ValidationResult => {
|
||||
if ( String(inputValue).replace('.', '').length <= num ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must have at most ${num} digits`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input value to end with the given number sequence.
|
||||
* @param num
|
||||
*/
|
||||
function ends(num: number): ValidatorFunction {
|
||||
return (fieldName: string, inputValue: unknown): ValidationResult => {
|
||||
if ( String(inputValue).endsWith(String(num)) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must end with "${num}"`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input value to begin with the given number sequence.
|
||||
* @param num
|
||||
*/
|
||||
function begins(num: number): ValidatorFunction {
|
||||
return (fieldName: string, inputValue: unknown): ValidationResult => {
|
||||
if ( String(inputValue).startsWith(String(num)) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must begin with "${num}"`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input value to be a multiple of the given number.
|
||||
* @param num
|
||||
*/
|
||||
function multipleOf(num: number): ValidatorFunction {
|
||||
return (fieldName: string, inputValue: unknown): ValidationResult => {
|
||||
if ( parseFloat(String(inputValue)) % num === 0 ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be a multiple of ${num}`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Requires the input value to be even. */
|
||||
function even(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
if ( parseFloat(String(inputValue)) % 2 === 0 ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must be even',
|
||||
}
|
||||
}
|
||||
|
||||
/** Requires the input value to be odd. */
|
||||
function odd(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
if ( parseFloat(String(inputValue)) % 2 === 0 ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must be odd',
|
||||
}
|
||||
}
|
||||
|
||||
export const Num = {
|
||||
greaterThan,
|
||||
atLeast,
|
||||
lessThan,
|
||||
atMost,
|
||||
digits,
|
||||
digitsMin,
|
||||
digitsMax,
|
||||
ends,
|
||||
begins,
|
||||
multipleOf,
|
||||
even,
|
||||
odd,
|
||||
}
|
||||
|
||||
@@ -1,175 +1,191 @@
|
||||
import {ValidationResult, ValidatorFunction} from "./types";
|
||||
import {ValidationResult, ValidatorFunction} from './types'
|
||||
import {UniversalPath} from '../../util'
|
||||
|
||||
export namespace Is {
|
||||
/** Requires the given input value to be some form of affirmative boolean. */
|
||||
export function accepted(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( ['yes', 'Yes', 'YES', 1, true, 'true', 'True', 'TRUE'].includes(inputValue) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must be accepted'
|
||||
}
|
||||
}
|
||||
|
||||
/** Requires the given input value to be some form of boolean. */
|
||||
export function boolean(fieldName: string, inputValue: any): ValidationResult {
|
||||
const boolish = ['true', 'True', 'TRUE', '1', 'false', 'False', 'FALSE', '0', true, false, 1, 0]
|
||||
if ( boolish.includes(inputValue) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must be true or false'
|
||||
}
|
||||
}
|
||||
|
||||
/** Requires the input value to be of type string. */
|
||||
export function string(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( typeof inputValue === 'string' ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must be a string'
|
||||
}
|
||||
}
|
||||
|
||||
/** Requires the given input value to be present and non-nullish. */
|
||||
export function required(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( typeof inputValue !== 'undefined' && inputValue !== null && inputValue !== '' ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'is required',
|
||||
stopValidation: true,
|
||||
}
|
||||
}
|
||||
|
||||
/** Alias of required(). */
|
||||
export function present(fieldName: string, inputValue: any): ValidationResult {
|
||||
return required(fieldName, inputValue)
|
||||
}
|
||||
|
||||
/** Alias of required(). */
|
||||
export function filled(fieldName: string, inputValue: any): ValidationResult {
|
||||
return required(fieldName, inputValue)
|
||||
}
|
||||
|
||||
/** Requires the given input value to be absent or nullish. */
|
||||
export function prohibited(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( typeof inputValue === 'undefined' || inputValue === null || inputValue === '' ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'is not allowed',
|
||||
stopValidation: true,
|
||||
}
|
||||
}
|
||||
|
||||
/** Alias of prohibited(). */
|
||||
export function absent(fieldName: string, inputValue: any): ValidationResult {
|
||||
return prohibited(fieldName, inputValue)
|
||||
}
|
||||
|
||||
/** Alias of prohibited(). */
|
||||
export function empty(fieldName: string, inputValue: any): ValidationResult {
|
||||
return prohibited(fieldName, inputValue)
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the given input to be found in an array of values.
|
||||
* @param values
|
||||
*/
|
||||
export function foundIn(values: any[]): ValidatorFunction {
|
||||
return function foundIn(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( values.includes(inputValue) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be one of: ${values.join(', ')}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the given input NOT to be found in an array of values.
|
||||
* @param values
|
||||
*/
|
||||
export function notFoundIn(values: any[]): ValidatorFunction {
|
||||
return function foundIn(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( values.includes(inputValue) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be one of: ${values.join(', ')}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Requires the input value to be number-like. */
|
||||
export function numeric(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( !isNaN(parseFloat(inputValue)) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must be numeric',
|
||||
}
|
||||
}
|
||||
|
||||
/** Requires the given input value to be integer-like. */
|
||||
export function integer(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( !isNaN(parseInt(inputValue)) && parseInt(inputValue) === parseFloat(inputValue) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must be an integer',
|
||||
}
|
||||
}
|
||||
|
||||
/** Requires the given input value to be a UniversalPath. */
|
||||
export function file(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( inputValue instanceof UniversalPath ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must be a file'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A special validator function that marks a field as optional.
|
||||
* If the value of the field is nullish, no further validation rules will be applied.
|
||||
* If it is non-nullish, validation will continue.
|
||||
* @param fieldName
|
||||
* @param inputValue
|
||||
*/
|
||||
export function optional(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( inputValue ?? true ) {
|
||||
return {
|
||||
valid: true,
|
||||
stopValidation: true,
|
||||
}
|
||||
}
|
||||
|
||||
/** Requires the given input value to be some form of affirmative boolean. */
|
||||
function accepted(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
if ( ['yes', 'Yes', 'YES', 1, true, 'true', 'True', 'TRUE'].includes(String(inputValue)) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must be accepted',
|
||||
}
|
||||
}
|
||||
|
||||
/** Requires the given input value to be some form of boolean. */
|
||||
function boolean(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
const boolish = ['true', 'True', 'TRUE', '1', 'false', 'False', 'FALSE', '0', true, false, 1, 0]
|
||||
if ( boolish.includes(String(inputValue)) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must be true or false',
|
||||
}
|
||||
}
|
||||
|
||||
/** Requires the input value to be of type string. */
|
||||
function string(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
if ( typeof inputValue === 'string' ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must be a string',
|
||||
}
|
||||
}
|
||||
|
||||
/** Requires the given input value to be present and non-nullish. */
|
||||
function required(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
if ( typeof inputValue !== 'undefined' && inputValue !== null && inputValue !== '' ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'is required',
|
||||
stopValidation: true,
|
||||
}
|
||||
}
|
||||
|
||||
/** Alias of required(). */
|
||||
function present(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
return required(fieldName, inputValue)
|
||||
}
|
||||
|
||||
/** Alias of required(). */
|
||||
function filled(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
return required(fieldName, inputValue)
|
||||
}
|
||||
|
||||
/** Requires the given input value to be absent or nullish. */
|
||||
function prohibited(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
if ( typeof inputValue === 'undefined' || inputValue === null || inputValue === '' ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'is not allowed',
|
||||
stopValidation: true,
|
||||
}
|
||||
}
|
||||
|
||||
/** Alias of prohibited(). */
|
||||
function absent(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
return prohibited(fieldName, inputValue)
|
||||
}
|
||||
|
||||
/** Alias of prohibited(). */
|
||||
function empty(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
return prohibited(fieldName, inputValue)
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the given input to be found in an array of values.
|
||||
* @param values
|
||||
*/
|
||||
function foundIn(values: any[]): ValidatorFunction {
|
||||
return (fieldName: string, inputValue: unknown): ValidationResult => {
|
||||
if ( values.includes(inputValue) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be one of: ${values.join(', ')}`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the given input NOT to be found in an array of values.
|
||||
* @param values
|
||||
*/
|
||||
function notFoundIn(values: any[]): ValidatorFunction {
|
||||
return (fieldName: string, inputValue: unknown): ValidationResult => {
|
||||
if ( values.includes(inputValue) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be one of: ${values.join(', ')}`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Requires the input value to be number-like. */
|
||||
function numeric(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
if ( !isNaN(parseFloat(String(inputValue))) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must be numeric',
|
||||
}
|
||||
}
|
||||
|
||||
/** Requires the given input value to be integer-like. */
|
||||
function integer(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
if ( !isNaN(parseInt(String(inputValue), 10)) && parseInt(String(inputValue), 10) === parseFloat(String(inputValue)) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must be an integer',
|
||||
}
|
||||
}
|
||||
|
||||
/** Requires the given input value to be a UniversalPath. */
|
||||
function file(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
if ( inputValue instanceof UniversalPath ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must be a file',
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A special validator function that marks a field as optional.
|
||||
* If the value of the field is nullish, no further validation rules will be applied.
|
||||
* If it is non-nullish, validation will continue.
|
||||
* @param fieldName
|
||||
* @param inputValue
|
||||
*/
|
||||
function optional(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
if ( inputValue ?? true ) {
|
||||
return {
|
||||
valid: true,
|
||||
stopValidation: true,
|
||||
}
|
||||
}
|
||||
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
export const Is = {
|
||||
accepted,
|
||||
boolean,
|
||||
string,
|
||||
required,
|
||||
present,
|
||||
filled,
|
||||
prohibited,
|
||||
absent,
|
||||
empty,
|
||||
foundIn,
|
||||
notFoundIn,
|
||||
numeric,
|
||||
integer,
|
||||
file,
|
||||
optional,
|
||||
}
|
||||
|
||||
@@ -1,224 +1,245 @@
|
||||
import {ValidationResult, ValidatorFunction} from "./types";
|
||||
import {ValidationResult, ValidatorFunction} from './types'
|
||||
import {isJSON} from '../../util'
|
||||
|
||||
/**
|
||||
* String-related validation rules.
|
||||
*/
|
||||
export namespace Str {
|
||||
const regexes: {[key: string]: RegExp} = {
|
||||
'string.is.alpha': /[a-zA-Z]*/,
|
||||
'string.is.alpha_num': /[a-zA-Z0-9]*/,
|
||||
'string.is.alpha_dash': /[a-zA-Z\-]*/,
|
||||
'string.is.alpha_score': /[a-zA-Z_]*/,
|
||||
'string.is.alpha_num_dash_score': /[a-zA-Z\-_0-9]*/,
|
||||
'string.is.email': /(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)])/,
|
||||
'string.is.ip': /((^\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\s*$)|(^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$))/,
|
||||
'string.is.ip.v4': /(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}/,
|
||||
'string.is.ip.v6': /(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]+|::(ffff(:0{1,4})?:)?((25[0-5]|(2[0-4]|1?[0-9])?[0-9])\.){3}(25[0-5]|(2[0-4]|1?[0-9])?[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1?[0-9])?[0-9])\.){3}(25[0-5]|(2[0-4]|1?[0-9])?[0-9]))/,
|
||||
'string.is.mime': /^(?=[-a-z]{1,127}\/[-.a-z0-9]{1,127}$)[a-z]+(-[a-z]+)*\/[a-z0-9]+([-.][a-z0-9]+)*$/,
|
||||
'string.is.url': /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=+$,\w]+@)?[A-Za-z0-9.\-]+|(?:www\.|[\-;:&=+$,\w]+@)[A-Za-z0-9.\-]+)((?:\/[+~%\/.\w\-_]*)?\??(?:[\-+=&;%@.\w_]*)#?(?:[.!\/\\\w]*))?)/,
|
||||
'string.is.uuid': /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/,
|
||||
const regexes: {[key: string]: RegExp} = {
|
||||
'string.is.alpha': /[a-zA-Z]*/,
|
||||
'string.is.alpha_num': /[a-zA-Z0-9]*/,
|
||||
'string.is.alpha_dash': /[a-zA-Z-]*/,
|
||||
'string.is.alpha_score': /[a-zA-Z_]*/,
|
||||
'string.is.alpha_num_dash_score': /[a-zA-Z\-_0-9]*/,
|
||||
'string.is.email': /(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)])/, // eslint-disable-line no-control-regex
|
||||
'string.is.ip': /((^\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\s*$)|(^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$))/,
|
||||
'string.is.ip.v4': /(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}/,
|
||||
'string.is.ip.v6': /(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]+|::(ffff(:0{1,4})?:)?((25[0-5]|(2[0-4]|1?[0-9])?[0-9])\.){3}(25[0-5]|(2[0-4]|1?[0-9])?[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1?[0-9])?[0-9])\.){3}(25[0-5]|(2[0-4]|1?[0-9])?[0-9]))/,
|
||||
'string.is.mime': /^(?=[-a-z]{1,127}\/[-.a-z0-9]{1,127}$)[a-z]+(-[a-z]+)*\/[a-z0-9]+([-.][a-z0-9]+)*$/,
|
||||
'string.is.url': /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:www\.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w\-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[.!/\\\w]*))?)/,
|
||||
'string.is.uuid': /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/,
|
||||
}
|
||||
|
||||
function validateRex(key: string, inputValue: unknown, message: string): ValidationResult {
|
||||
if ( regexes[key].test(String(inputValue)) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
function validateRex(key: string, inputValue: any, message: string): ValidationResult {
|
||||
if ( regexes[key].test(inputValue) ) {
|
||||
return {
|
||||
valid: false,
|
||||
message,
|
||||
}
|
||||
}
|
||||
|
||||
/** Requires the input value to be alphabetical characters only. */
|
||||
function alpha(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
return validateRex('string.is.alpha', inputValue, 'must be alphabetical only')
|
||||
}
|
||||
|
||||
/** Requires the input value to be alphanumeric characters only. */
|
||||
function alphaNum(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
return validateRex('string.is.alpha_num', inputValue, 'must be alphanumeric only')
|
||||
}
|
||||
|
||||
/** Requires the input value to be alphabetical characters or the "-" character only. */
|
||||
function alphaDash(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
return validateRex('string.is.alpha_dash', inputValue, 'must be alphabetical and dashes only')
|
||||
}
|
||||
|
||||
/** Requires the input value to be alphabetical characters or the "_" character only. */
|
||||
function alphaScore(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
return validateRex('string.is.alpha_score', inputValue, 'must be alphabetical and underscores only')
|
||||
}
|
||||
|
||||
/** Requires the input value to be alphabetical characters, numeric characters, "-", or "_" only. */
|
||||
function alphaNumDashScore(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
return validateRex('string.is.alpha_num_dash_score', inputValue, 'must be alphanumeric, dashes, and underscores only')
|
||||
}
|
||||
|
||||
/** Requires the input value to be a valid RFC email address format. */
|
||||
function email(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
return validateRex('string.is.email', inputValue, 'must be an email address')
|
||||
}
|
||||
|
||||
/** Requires the input value to be a valid IPv4 or IPv6 address. */
|
||||
function ip(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
return validateRex('string.is.ip', inputValue, 'must be a valid IP address')
|
||||
}
|
||||
|
||||
/** Requires the input value to be a valid IPv4 address. */
|
||||
function ipv4(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
return validateRex('string.is.ip.v4', inputValue, 'must be a valid IP version 4 address')
|
||||
}
|
||||
|
||||
/** Requires the input value to be a valid IPv6 address. */
|
||||
function ipv6(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
return validateRex('string.is.ip.v6', inputValue, 'must be a valid IP version 6 address')
|
||||
}
|
||||
|
||||
/** Requires the input value to be a valid file MIME type. */
|
||||
function mime(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
return validateRex('string.is.mime', inputValue, 'must be a valid MIME-type')
|
||||
}
|
||||
|
||||
/** Requires the input value to be a valid RFC URL format. */
|
||||
function url(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
return validateRex('string.is.url', inputValue, 'must be a valid URL')
|
||||
}
|
||||
|
||||
/** Requires the input value to be a valid RFC UUID format. */
|
||||
function uuid(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
return validateRex('string.is.uuid', inputValue, 'must be a valid UUID')
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validation function that requires the input value to match the given regex.
|
||||
* @param rex
|
||||
*/
|
||||
function regex(rex: RegExp): ValidatorFunction {
|
||||
return (fieldName: string, inputValue: unknown): ValidationResult => {
|
||||
if ( rex.test(String(inputValue)) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message
|
||||
}
|
||||
}
|
||||
|
||||
/** Requires the input value to be alphabetical characters only. */
|
||||
export function alpha(fieldName: string, inputValue: any): ValidationResult {
|
||||
return validateRex('string.is.alpha', inputValue, 'must be alphabetical only')
|
||||
}
|
||||
|
||||
/** Requires the input value to be alphanumeric characters only. */
|
||||
export function alphaNum(fieldName: string, inputValue: any): ValidationResult {
|
||||
return validateRex('string.is.alpha_num', inputValue, 'must be alphanumeric only')
|
||||
}
|
||||
|
||||
/** Requires the input value to be alphabetical characters or the "-" character only. */
|
||||
export function alphaDash(fieldName: string, inputValue: any): ValidationResult {
|
||||
return validateRex('string.is.alpha_dash', inputValue, 'must be alphabetical and dashes only')
|
||||
}
|
||||
|
||||
/** Requires the input value to be alphabetical characters or the "_" character only. */
|
||||
export function alphaScore(fieldName: string, inputValue: any): ValidationResult {
|
||||
return validateRex('string.is.alpha_score', inputValue, 'must be alphabetical and underscores only')
|
||||
}
|
||||
|
||||
/** Requires the input value to be alphabetical characters, numeric characters, "-", or "_" only. */
|
||||
export function alphaNumDashScore(fieldName: string, inputValue: any): ValidationResult {
|
||||
return validateRex('string.is.alpha_num_dash_score', inputValue, 'must be alphanumeric, dashes, and underscores only')
|
||||
}
|
||||
|
||||
/** Requires the input value to be a valid RFC email address format. */
|
||||
export function email(fieldName: string, inputValue: any): ValidationResult {
|
||||
return validateRex('string.is.email', inputValue, 'must be an email address')
|
||||
}
|
||||
|
||||
/** Requires the input value to be a valid IPv4 or IPv6 address. */
|
||||
export function ip(fieldName: string, inputValue: any): ValidationResult {
|
||||
return validateRex('string.is.ip', inputValue, 'must be a valid IP address')
|
||||
}
|
||||
|
||||
/** Requires the input value to be a valid IPv4 address. */
|
||||
export function ipv4(fieldName: string, inputValue: any): ValidationResult {
|
||||
return validateRex('string.is.ip.v4', inputValue, 'must be a valid IP version 4 address')
|
||||
}
|
||||
|
||||
/** Requires the input value to be a valid IPv6 address. */
|
||||
export function ipv6(fieldName: string, inputValue: any): ValidationResult {
|
||||
return validateRex('string.is.ip.v6', inputValue, 'must be a valid IP version 6 address')
|
||||
}
|
||||
|
||||
/** Requires the input value to be a valid file MIME type. */
|
||||
export function mime(fieldName: string, inputValue: any): ValidationResult {
|
||||
return validateRex('string.is.mime', inputValue, 'must be a valid MIME-type')
|
||||
}
|
||||
|
||||
/** Requires the input value to be a valid RFC URL format. */
|
||||
export function url(fieldName: string, inputValue: any): ValidationResult {
|
||||
return validateRex('string.is.url', inputValue, 'must be a valid URL')
|
||||
}
|
||||
|
||||
/** Requires the input value to be a valid RFC UUID format. */
|
||||
export function uuid(fieldName: string, inputValue: any): ValidationResult {
|
||||
return validateRex('string.is.uuid', inputValue, 'must be a valid UUID')
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validation function that requires the input value to match the given regex.
|
||||
* @param rex
|
||||
*/
|
||||
export function regex(rex: RegExp): ValidatorFunction {
|
||||
return function regex(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( rex.test(inputValue) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'is not valid'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validation function that requires the input to NOT match the given regex.
|
||||
* @param rex
|
||||
*/
|
||||
export function notRegex(rex: RegExp): ValidatorFunction {
|
||||
return function notRegex(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( !rex.test(inputValue) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'is not valid'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validation function that requires the given input to end with the substring.
|
||||
* @param substr
|
||||
*/
|
||||
export function ends(substr: string): ValidatorFunction {
|
||||
return function ends(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( String(inputValue).endsWith(substr) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must end with "${substr}"`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validation function that requires the given input to begin with the substring.
|
||||
* @param substr
|
||||
*/
|
||||
export function begins(substr: string): ValidatorFunction {
|
||||
return function begins(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( String(inputValue).startsWith(substr) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must begin with "${substr}"`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Requires the input value to be a valid JSON string. */
|
||||
export function json(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( isJSON(inputValue) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must be valid JSON'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input value to have exactly len many characters.
|
||||
* @param len
|
||||
*/
|
||||
export function length(len: number): ValidatorFunction {
|
||||
return function length(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( inputValue.length === len ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be exactly of length ${len}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input value to have at least len many characters.
|
||||
* @param len
|
||||
*/
|
||||
export function lengthMin(len: number): ValidatorFunction {
|
||||
return function lengthMin(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( inputValue.length >= len ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be at least length ${len}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input value to have at most len many characters.
|
||||
* @param len
|
||||
*/
|
||||
export function lengthMax(len: number): ValidatorFunction {
|
||||
return function lengthMax(fieldName: string, inputValue: any): ValidationResult {
|
||||
if ( inputValue.length <= len ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be at most length ${len}`
|
||||
}
|
||||
message: 'is not valid',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validation function that requires the input to NOT match the given regex.
|
||||
* @param rex
|
||||
*/
|
||||
function notRegex(rex: RegExp): ValidatorFunction {
|
||||
return (fieldName: string, inputValue: unknown): ValidationResult => {
|
||||
if ( !rex.test(String(inputValue)) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'is not valid',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validation function that requires the given input to end with the substring.
|
||||
* @param substr
|
||||
*/
|
||||
function ends(substr: string): ValidatorFunction {
|
||||
return (fieldName: string, inputValue: unknown): ValidationResult => {
|
||||
if ( String(inputValue).endsWith(substr) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must end with "${substr}"`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validation function that requires the given input to begin with the substring.
|
||||
* @param substr
|
||||
*/
|
||||
function begins(substr: string): ValidatorFunction {
|
||||
return (fieldName: string, inputValue: unknown): ValidationResult => {
|
||||
if ( String(inputValue).startsWith(substr) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must begin with "${substr}"`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Requires the input value to be a valid JSON string. */
|
||||
function json(fieldName: string, inputValue: unknown): ValidationResult {
|
||||
if ( isJSON(String(inputValue)) ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: 'must be valid JSON',
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input value to have exactly len many characters.
|
||||
* @param len
|
||||
*/
|
||||
function length(len: number): ValidatorFunction {
|
||||
return (fieldName: string, inputValue: unknown): ValidationResult => {
|
||||
if ( String(inputValue).length === len ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be exactly of length ${len}`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input value to have at least len many characters.
|
||||
* @param len
|
||||
*/
|
||||
function lengthMin(len: number): ValidatorFunction {
|
||||
return (fieldName: string, inputValue: unknown): ValidationResult => {
|
||||
if ( String(inputValue).length >= len ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be at least length ${len}`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a validator function that requires the input value to have at most len many characters.
|
||||
* @param len
|
||||
*/
|
||||
function lengthMax(len: number): ValidatorFunction {
|
||||
return (fieldName: string, inputValue: unknown): ValidationResult => {
|
||||
if ( String(inputValue).length <= len ) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `must be at most length ${len}`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const Str = {
|
||||
alpha,
|
||||
alphaNum,
|
||||
alphaDash,
|
||||
alphaScore,
|
||||
alphaNumDashScore,
|
||||
email,
|
||||
ip,
|
||||
ipv4,
|
||||
ipv6,
|
||||
mime,
|
||||
url,
|
||||
uuid,
|
||||
regex,
|
||||
notRegex,
|
||||
ends,
|
||||
begins,
|
||||
json,
|
||||
length,
|
||||
lengthMin,
|
||||
lengthMax,
|
||||
}
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import {UniversalPath} from '../../util'
|
||||
import {Template} from '../../cli'
|
||||
|
||||
const form_template: Template = {
|
||||
const templateForm: Template = {
|
||||
name: 'form',
|
||||
fileSuffix: '.form.ts',
|
||||
description: 'Create a new form request validator',
|
||||
baseAppPath: ['http', 'forms'],
|
||||
render(name: string, fullCanonicalName: string, targetFilePath: UniversalPath) {
|
||||
return `import {FormRequest, ValidationRules, Rule} from '@extollo/forms'
|
||||
import {Injectable} from '@extollo/di'
|
||||
render(name: string) {
|
||||
return `import {Injectable, FormRequest, ValidationRules, Rule} from '@extollo/lib'
|
||||
|
||||
/**
|
||||
* ${name} object
|
||||
@@ -40,7 +38,7 @@ export class ${name}FormRequest extends FormRequest<${name}Form> {
|
||||
}
|
||||
}
|
||||
`
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export { form_template }
|
||||
export { templateForm }
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import {Singleton, Inject} from '../../di'
|
||||
import {CommandLine} from '../../cli'
|
||||
import {form_template} from '../templates/form'
|
||||
import {Unit} from "../../lifecycle/Unit";
|
||||
import {Logging} from "../../service/Logging";
|
||||
import {templateForm} from '../templates/form'
|
||||
import {Unit} from '../../lifecycle/Unit'
|
||||
import {Logging} from '../../service/Logging'
|
||||
|
||||
@Singleton()
|
||||
export class Forms extends Unit {
|
||||
@@ -13,6 +13,6 @@ export class Forms extends Unit {
|
||||
protected readonly logging!: Logging
|
||||
|
||||
public async up(): Promise<void> {
|
||||
this.cli.registerTemplate(form_template)
|
||||
this.cli.registerTemplate(templateForm)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user