/*
* Copyright 2018-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict'
/**
* Validators:
* this module exports some useful generic functions for the validation of objects.
*/
/**
* Get a reference to Node.js url module.
* @private
*/
const url = require('node:url')
/**
* Generic Validator implementation.
*
* Note that all methods here are static, so no need to instance this class;
* see it as an Utility/Companion class.
*/
class Validator {
/**
* Create a new instance of a Validator object.
* Note that instancing is not allowed for this class because all its methods are static.
*
* @throws {Error} instancing not allowed for this class
* @hideconstructor
*/
constructor () {
throw new Error('Instancing not allowed for this class')
}
/**
* Tell if the given argument is undefined.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if undefined, false otherwise
*/
static isUndefined (arg) {
return (arg === undefined)
}
/**
* Tell if the given argument is null.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if null, false otherwise
*/
static isNull (arg) {
return (arg === null)
}
/**
* Tell if the given argument is undefined or null.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if undefined or null, false otherwise
*/
static isUndefinedOrNull (arg) {
return (arg === undefined || arg === null)
}
/**
* Tell if the given argument is defined and not null.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if defined and not null, false otherwise
*/
static isDefinedAndNotNull (arg) {
return (arg !== undefined && arg !== null)
}
/**
* Tell if the given argument is a string.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if it's a string, false otherwise
*/
static isString (arg) {
// return (Validator.isDefinedAndNotNull(arg) && (typeof arg === 'string'))
// rewritten inline and using new ES features for more performances
return ((arg?.length >= 0) && (typeof arg === 'string'))
}
/**
* Tell if the given argument is a not empty string.
*
* See {@link Validator.isString}.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if it's a not empty string, false otherwise
*/
static isStringNotEmpty (arg) {
// return (Validator.isString(arg) && (arg.length > 0))
// rewritten inline and using new ES features for more performances
return ((arg?.length > 0) && (typeof arg === 'string'))
}
/**
* Tell if the given argument is a date.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if it's a date, false otherwise
*/
static isDate (arg) {
return (Validator.isDefinedAndNotNull(arg) && (typeof arg === 'object' || arg instanceof Date))
}
/**
* Tell if the given argument is a valid date.
*
* See {@link Validator.isDate}.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if it's a valid date, false otherwise
*/
static isDateValid (arg) {
return (Validator.isDate(arg) && !isNaN(arg))
}
/**
* Tell if the given argument is a valid date and in the past or now.
*
* See {@link Validator.isDateValid}.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if it's a valid date in the past (or now), false otherwise
*/
static isDatePast (arg) {
return (Validator.isDateValid(arg) && arg.getTime() <= Date.now())
}
/**
* Tell if the given argument is a valid date and in the future or now.
*
* See {@link Validator.isDateValid}.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if it's a valid date in the future (or now), false otherwise
*/
static isDateFuture (arg) {
return (Validator.isDateValid(arg) && arg.getTime() > Date.now())
}
/**
* Tell if the given argument is a number.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if it's a number, false otherwise
*/
static isNumber (arg) {
return (Validator.isDefinedAndNotNull(arg) && typeof arg === 'number' && !isNaN(arg))
}
/**
* Tell if the given argument is an array.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if it's an array, false otherwise
*/
static isArray (arg) {
return (Validator.isDefinedAndNotNull(arg) && (Array.isArray(arg)))
}
/**
* Tell if the given argument is a normal value
* (string or boolean or number).
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if it's a string or boolean or number, false otherwise
*/
static isValue (arg) {
return (Validator.isDefinedAndNotNull(arg) &&
(Validator.isString(arg) || Validator.isBoolean(arg) || Validator.isNumber(arg))
)
}
/**
* Tell if the given argument is a boolean.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if it's a boolean, false otherwise
*/
static isBoolean (arg) {
return (typeof arg === 'boolean')
}
/**
* Tell if the given argument is an instance of the given class reference.
*
* @static
* @param {?object} arg the object to check
* @param {?object} classReference the class that should be implemented/extended
* @return {boolean} true if it's an instance (or extends) that class, false otherwise
*/
static isClass (arg, classReference) {
return (arg instanceof classReference)
}
/**
* Tell if the given argument is an error.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if it's an error, false otherwise
*/
static isError (arg) {
return (arg instanceof Error && typeof arg.message !== 'undefined')
}
/**
* Tell if the given argument is a function.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if it's a function, false otherwise
*/
static isFunction (arg) {
// return (Validator.isDefinedAndNotNull(arg) && (typeof arg === 'function'))
// rewritten (inline same code here) for more performances
// return ((arg !== undefined && arg !== null) && (typeof arg === 'function'))
// rewritten using new ES features, but same behavior
return ((arg ?? false) && (typeof arg === 'function'))
}
/**
* Tell if the given argument is an object
* and is defined and not null.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if it's an object, false otherwise
*/
static isObject (arg) {
return (Validator.isDefinedAndNotNull(arg) && (typeof arg === 'object'))
}
/**
* Tell if the given argument is a plain object
* and not: undefined, null, Array, Date, Number, String,
* Symbol, Map/WeakMap, Set/WeakSet, etc.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if it's a plain object, false otherwise
*/
static isObjectPlain (arg) {
return (Object.prototype.toString.call(arg) === '[object Object]')
}
/**
* Tell if the given argument is a keyed collection.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if it's a Map|WeakMap or a Set|WeakSet, false otherwise
*/
static isKeyedCollection (arg) {
return (Validator.isDefinedAndNotNull(arg) && (
arg instanceof Map || arg instanceof WeakMap ||
arg instanceof Set || arg instanceof WeakSet
))
}
/**
* Tell if the given argument is a plain object or a keyed collection.
*
* See {@link Validator.isObject}, {@link Validator.isKeyedCollection}.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if it's a plain object or a keyed collection, false otherwise
*/
static isObjectOrCollection (arg) {
return (Validator.isObjectPlain(arg) || Validator.isKeyedCollection(arg))
}
/**
* Tell if the given argument is a plain object or a keyed collection, but not an array.
*
* See {@link Validator.isObjectOrCollection}.
* See {@link Validator.isArray}.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if it's a plain object or a keyed collection but not an array, false otherwise
*/
static isObjectOrCollectionNotArray (arg) {
return (Validator.isObjectOrCollection(arg) && !Validator.isArray(arg))
}
/**
* Tell if the given argument is a plain object or a keyed collection or an array.
*
* See {@link Validator.isObjectOrCollection}.
* See {@link Validator.isArray}.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if it's a plain object or a keyed collection or an array, false otherwise
*/
static isObjectOrCollectionOrArray (arg) {
return (Validator.isObjectOrCollection(arg) || Validator.isArray(arg))
}
/**
* Tell if the given argument is a plain object or a keyed collection, but not a string.
*
* See {@link Validator.isObjectOrCollection}.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if it's a plain object or a keyed collection but not a string, false otherwise
*/
static isObjectOrCollectionNotString (arg) {
return (Validator.isObjectOrCollection(arg) && (typeof arg !== 'string'))
}
/**
* Tell if the given argument is a plain object or a keyed collection or an array,
* but not a value (string or boolean or number).
*
* See {@link Validator.isObjectOrCollection}.
* See {@link Validator.isArray}.
* See {@link Validator.isValue}.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if it's a plain object or a keyed collection or an array but not a value (string or boolean or number), false otherwise
*/
static isObjectOrCollectionOrArrayNotValue (arg) {
return ((Validator.isObjectOrCollection(arg) || Validator.isArray(arg)) && !Validator.isValue(arg))
}
/**
* Tell if the given argument is a plain object or a keyed collection, or a string.
*
* See {@link Validator.isObjectOrCollection}.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if it's a plain object or a keyed collection or a string, false otherwise
*/
static isObjectOrCollectionOrString (arg) {
return (Validator.isObjectOrCollection(arg) || (typeof arg === 'string'))
}
/**
* Tell if the given argument is a plain object or a keyed collection,
* or a value (string or boolean or number).
*
* See {@link Validator.isObjectOrCollection}.
* See {@link Validator.isValuey}.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if it's a plain object or a keyed collection or a value (string or boolean or number), false otherwise
*/
static isObjectOrCollectionOrValue (arg) {
return (Validator.isObjectOrCollection(arg) || Validator.isValue(arg))
}
/**
* Tell if the given argument is a plain object or a keyed collection or an array,
* or a value (string or boolean or number).
*
* See {@link Validator.isObjectOrCollection}.
* See {@link Validator.isArray}.
* See {@link Validator.isValuey}.
*
* @static
* @param {?object} arg the object to check
* @return {boolean} true if it's a plain object or a keyed collection or an array or a value (string or boolean or number), false otherwise
*/
static isObjectOrCollectionOrArrayOrValue (arg) {
return (Validator.isObjectOrCollection(arg) || Validator.isArray(arg) || Validator.isValue(arg))
}
/**
* Tell if the given argument is a string representation of a version number.
*
* Note that the version string could be something like:
* - as minimum a number is needed for an integer version
* - at the beginning I can have an optional char 'v' or 'V'
* - anything after the third number will be considered as a string
* - format updated to handle version output of 'git describe'
*
* @static
* @param {?string} arg the version string to check
* @return {boolean} true if it's a version string, false otherwise
*/
static isVersion (arg) {
// quick check if the given string is in the format 'n.n.n'
const versionRegex = /^(?:v|V?)((\d+)(?:\.?)){1,3}(?:\W|_?)(.*)$/gm
return (Validator.isStringNotEmpty(arg) && versionRegex.test(arg))
}
/**
* Tell if the given argument is an URI or an URL.
*
* @static
* @param {?string} arg the uri/url to check
* @param {?string} base the (optional) base to build the full URL
* @return {boolean} true if it's an URI/URL, false otherwise
*/
static isURI (arg, base) {
// quick check if the given string is an URI or an URL
if (!Validator.isStringNotEmpty(arg)) {
return false
}
// simple check if it's an URL, trying to instancing it
// note that this requires to import related module here (but not in Browsers) ...
if (Validator.isStringNotEmpty(base)) {
try {
const u = new url.URL(arg, base)
return (u !== null)
} catch (e) {
// console.error(e)
return false
}
} else {
// simple check if it's an URI (or better: a relative URL, or a full URI with scheme etc)
const uriRegex = /^(\w+:|\/)/ // or /^(\w+:|\/)(.*)$/ for full match
if (uriRegex.test(arg)) {
return true
}
try {
const u = new url.URL(arg)
return (u !== null)
} catch (e) {
// console.error(e)
return false
}
}
}
/**
* Tell if the given object contains the given property.
*
* @static
* @param {?object} obj the object to check
* @param {?string} propName the name of the property
* @param {boolean} [includeInherited=false] specify if search in nested/inherited properties
* @return {boolean} true if the object contains theat property, otherwise false
*/
static doesObjectContainsProperty (obj, propName, includeInherited = false) {
if (!Validator.isObject(obj)) return false
if (!Validator.isStringNotEmpty(propName)) return false
if (!Validator.isBoolean(includeInherited)) return false
let propFound = false
if (includeInherited === false) {
propFound = Object.prototype.hasOwnProperty.call(obj, propName)
} else {
propFound = propName in obj
}
return propFound
}
/**
* Tell if the given object contains at least one property
* that has a standard (reserved) property name.
*
* @static
* @param {?object} obj the object to check
* @param {?function} isPropStandard the function that tell the given argument (property), if it's standard
* @return {boolean} true if at least one property with a standard name is found, otherwise false
*/
static doesObjectContainsStandardProperty (obj, isPropStandard) {
if (!Validator.isObject(obj)) return false
if (!Validator.isFunction(isPropStandard)) return false
let standardPropFound = false
for (const prop in obj) {
if (isPropStandard(prop) === true) {
standardPropFound = true
break
}
}
return standardPropFound
}
/**
* Tell if the given string has a standard (reserved) property name.
*
* @static
* @param {?string} str the string to check
* @param {?function} isPropStandard the function that tell the given argument (property), if it's standard
* @return {boolean} true if the given string has a standard name, otherwise false
*/
static doesStringIsStandardProperty (str, isPropStandard) {
if (!Validator.isStringNotEmpty(str)) return false
if (!Validator.isFunction(isPropStandard)) return false
let standardPropFound = false
if (isPropStandard(str) === true) {
standardPropFound = true
}
return standardPropFound
}
/**
* Ensure that the given argument is undefined.
*
* See {@link Validator.isUndefined}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {TypeError} if it's not undefined, nothing otherwise
*/
static ensureIsUndefined (arg, name = 'arg') {
if (!Validator.isUndefined(arg)) {
return new TypeError(`The argument '${name}' must be undefined, instead got a '${typeof arg}'`)
}
}
/**
* Ensure that the given argument is null.
*
* See {@link Validator.isNull}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {TypeError} if it's not null, nothing otherwise
*/
static ensureIsNull (arg, name = 'arg') {
if (!Validator.isNull(arg)) {
return new TypeError(`The argument '${name}' must be null, instead got a '${typeof arg}'`)
}
}
/**
* Ensure that the given argument is undefined or null.
*
* See {@link Validator.isUndefinedOrNull}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {TypeError} if it's not undefined or null, nothing otherwise
*/
static ensureIsUndefinedOrNull (arg, name = 'arg') {
if (!Validator.isUndefinedOrNull(arg)) {
return new TypeError(`The argument '${name}' must be undefined or null, instead got a '${typeof arg}'`)
}
}
/**
* Ensure that the given argument is defined and not null.
*
* See {@link Validator.isDefinedAndNotNull}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {TypeError} if it's not undefined or null, nothing otherwise
*/
static ensureIsDefinedAndNotNull (arg, name = 'arg') {
if (!Validator.isDefinedAndNotNull(arg)) {
return new TypeError(`The argument '${name}' must be defined and not null, instead got a '${typeof arg}'`)
}
}
/**
* Ensure that the given argument is an array.
*
* See {@link Validator.isArray}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {TypeError} if it's not an array, nothing otherwise
*/
static ensureIsArray (arg, name = 'arg') {
if (!Validator.isArray(arg)) {
return new TypeError(`The argument '${name}' must be an array, instead got a '${typeof arg}'`)
}
}
/**
* Ensure that the given argument is a value (string or boolean or number).
*
* See {@link Validator.isValue}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {TypeError} if it's not a string or a boolean or a number, nothing otherwise
*/
static ensureIsValue (arg, name = 'arg') {
if (!Validator.isValue(arg)) {
return new TypeError(`The argument '${name}' must be a value (string or boolean or number), instead got a '${typeof arg}'`)
}
}
/**
* Ensure that the given argument is a boolean.
*
* See {@link Validator.isBoolean}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {TypeError} if it's not a boolean, nothing otherwise
*/
static ensureIsBoolean (arg, name = 'arg') {
if (!Validator.isBoolean(arg)) {
return new TypeError(`The argument '${name}' must be a boolean, instead got a '${typeof arg}'`)
}
}
/**
* Ensure that the given argument is an instance of the given class reference.
*
* See {@link Validator.isClass}.
*
* @static
* @param {?object} arg the object to check
* @param {?object} classReference the class that should be implemented/extended
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {TypeError} if it's not an instance (or extends) that class, nothing otherwise
*/
static ensureIsClass (arg, classReference, name = 'arg') {
if (!Validator.isClass(arg, classReference)) {
return new TypeError(`The argument '${name}' must be an instance of the given class reference, instead got a '${typeof arg}'`)
}
}
/**
* Ensure that the given argument is a function.
*
* See {@link Validator.isFunction}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {TypeError} if it's not a function, nothing otherwise
*/
static ensureIsFunction (arg, name = 'arg') {
if (!Validator.isFunction(arg)) {
return new TypeError(`The argument '${name}' must be a function, instead got a '${typeof arg}'`)
}
}
/**
* Ensure that the given argument is a string.
*
* See {@link Validator.isString}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {TypeError} if it's not a string, nothing otherwise
*/
static ensureIsString (arg, name = 'arg') {
if (!Validator.isString(arg)) {
return new TypeError(`The argument '${name}' must be a string, instead got a '${typeof arg}'`)
}
}
/**
* Ensure that the given argument is a not empty string.
*
* See {@link Validator.isStringNotEmpty}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {Error} if it's not a string not empty, nothing otherwise
*/
static ensureIsStringNotEmpty (arg, name = 'arg') {
if (!Validator.isStringNotEmpty(arg)) {
return new Error(`The string '${name}' must be not empty`)
}
}
/**
* Ensure that the given argument is an object.
*
* See {@link Validator.isObject}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {TypeError} if it's not an object, nothing otherwise
*/
static ensureIsObject (arg, name = 'arg') {
if (!Validator.isObject(arg)) {
return new TypeError(`The argument '${name}' must be an object, instead got a '${typeof arg}'`)
}
}
/**
* Ensure that the given argument is a plain object
* and not: undefined, null, Array, Date, Number, String,
* Symbol, Map/WeakMap, Set/WeakSet, etc.
*
* See {@link Validator.isObjectPlain}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {TypeError} if it's not a plain object, nothing otherwise
*/
static ensureIsObjectPlain (arg, name = 'arg') {
if (!Validator.isObjectPlain(arg)) {
return new TypeError(`The argument '${name}' must be a plain object, instead got a '${typeof arg}'`)
}
}
/**
* Ensure that the given argument is a plain object or a collection.
*
* See {@link Validator.isObjectOrCollection}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {TypeError} if it's not a plain object nor a collection, nothing otherwise
*/
static ensureIsObjectOrCollection (arg, name = 'arg') {
if (!Validator.isObjectOrCollection(arg)) {
return new TypeError(`The argument '${name}' must be an object or a collection, instead got a '${typeof arg}'`)
}
}
/**
* Ensure that the given argument is a plain object or a collection, not an array.
*
* See {@link Validator.isObjectOrCollectionNotArray}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {TypeError} if it's not a plain object nor a collection or it's an array, nothing otherwise
*/
static ensureIsObjectOrCollectionNotArray (arg, name = 'arg') {
if (!Validator.isObjectOrCollectionNotArray(arg)) {
return new TypeError(`The argument '${name}' must be an object or a collection and not an array, instead got a '${typeof arg}'`)
}
}
/**
* Ensure that the given argument is a plain object or a collection or an array.
*
* See {@link Validator.isObjectOrCollectionOrArray}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {TypeError} if it's not a plain object nor a collection nor an array, nothing otherwise
*/
static ensureIsObjectOrCollectionOrArray (arg, name = 'arg') {
if (!Validator.isObjectOrCollectionOrArray(arg)) {
return new TypeError(`The argument '${name}' must be an object or a collection and not an array, instead got a '${typeof arg}'`)
}
}
/**
* Ensure that the given argument is a plain object or a collection, not a string.
*
* See {@link Validator.isObjectOrCollectionNotString}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {TypeError} if it's not a plain object nor a collection or it's a string, nothing otherwise
*/
static ensureIsObjectOrCollectionNotString (arg, name = 'arg') {
if (!Validator.isObjectOrCollectionNotString(arg)) {
return new TypeError(`The argument '${name}' must be an object or a collection and not a string, instead got a '${typeof arg}'`)
}
}
/**
* Ensure that the given argument is a plain object or a collection or an array,
* not a value (string or boolean or number).
*
* See {@link Validator.isObjectOrCollectionOrArrayNotValue}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {TypeError} if it's not a plain object nor a collection or it's a value (string or boolean or number), nothing otherwise
*/
static ensureIsObjectOrCollectionOrArrayNotValue (arg, name = 'arg') {
if (!Validator.isObjectOrCollectionOrArrayNotValue(arg)) {
return new TypeError(`The argument '${name}' must be an object or a collection or an array and not a value (string or boolean or number), instead got a '${typeof arg}'`)
}
}
/**
* Ensure that the given argument is a plain object or a collection, or a string.
*
* See {@link Validator.isObjectOrCollectionOrString}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {TypeError} if it's not a plain object nor a collection nor a string, nothing otherwise
*/
static ensureIsObjectOrCollectionOrString (arg, name = 'arg') {
if (!Validator.isObjectOrCollectionOrString(arg)) {
return new TypeError(`The argument '${name}' must be an object or a collection or a string, instead got a '${typeof arg}'`)
}
}
/**
* Ensure that the given argument is a plain object or a collection,
* or a value (string or boolean or number).
*
* See {@link Validator.isObjectOrCollectionOrValue}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {TypeError} if it's not a plain object nor a collection nor a value (string or boolean or number), nothing otherwise
*/
static ensureIsObjectOrCollectionOrValue (arg, name = 'arg') {
if (!Validator.isObjectOrCollectionOrValue(arg)) {
return new TypeError(`The argument '${name}' must be an object or a collection or a value (string or boolean or number), instead got a '${typeof arg}'`)
}
}
/**
* Ensure that the given argument is a plain object or a collection or an array,
* or a value (string or boolean or number).
*
* See {@link Validator.isObjectOrCollectionOrArrayOrValue}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {TypeError} if it's not a plain object nor a collection nor a value (string or boolean or number), nothing otherwise
*/
static ensureIsObjectOrCollectionOrArrayOrValue (arg, name = 'arg') {
if (!Validator.isObjectOrCollectionOrArrayOrValue(arg)) {
return new TypeError(`The argument '${name}' must be an object or a collection or an array or a value (string or boolean or number), instead got a '${typeof arg}'`)
}
}
/**
* Ensure that the given argument is a date.
*
* See {@link Validator.isDate}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {Error} if it's not a date, nothing otherwise
*/
static ensureIsDate (arg, name = 'arg') {
if (!Validator.isDate(arg)) {
return new Error(`The argument '${name}' must be a Date, instead got a '${typeof arg}'`)
}
}
/**
* Ensure that the given argument is a date in the past or now.
*
* See {@link Validator.isDatePast}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {Error} if it's not a date in the past, nothing otherwise
*/
static ensureIsDatePast (arg, name = 'arg') {
if (!Validator.isDatePast(arg)) {
return new Error(`The argument '${name}' must be a Date that belongs to the past`)
}
}
/**
* Ensure that the given argument is a date in the future or now.
*
* See {@link Validator.isDateFuture}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {Error} if it's not a date in the future, nothing otherwise
*/
static ensureIsDateFuture (arg, name = 'arg') {
if (!Validator.isDateFuture(arg)) {
return new Error(`The argument '${name}' must be a Date that belongs to the future`)
}
}
/**
* Ensure that the given argument is a number.
*
* See {@link Validator.isNumber}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {Error} if it's not a number, nothing otherwise
*/
static ensureIsNumber (arg, name = 'arg') {
if (!Validator.isNumber(arg)) {
return new Error(`The argument '${name}' must be a Number, instead got a '${typeof arg}'`)
}
}
/**
* Ensure that the given argument is an error instance or its subclass.
*
* See {@link Validator.isError}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {Error} if it's not an error or its subclass, nothing otherwise
*/
static ensureIsError (arg, name = 'arg') {
if (!Validator.isError(arg)) {
return new Error(`The argument '${name}' must be an Error or a subclass of it, instead got a '${typeof arg}'`)
}
}
/**
* Ensure that the given argument is a string version.
*
* See {@link Validator.isVersion}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {Error} if it's not a string version, nothing otherwise
*/
static ensureIsVersion (arg, name = 'arg') {
if (!Validator.isVersion(arg)) {
return new Error(`The argument '${name}' must be a string in the format 'n.n.n', and not '${arg}'`)
}
}
/**
* Ensure that the given argument is an URI/URL.
*
* See {@link Validator.isURI}.
*
* @static
* @param {?object} arg the object to check
* @param {?string} base the (optional) base to build the full URL
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @return {Error} if it's not an URI/URL, nothing otherwise
*/
static ensureIsURI (arg, base, name = 'arg') {
if (!Validator.isURI(arg, base)) {
return new Error(`The argument '${name}' must be an URI or URL string and not ('${arg}', '${base}')`)
}
}
/**
* Ensure that the given object contains the given property.
*
* See {@link Validator.doesObjectContainsProperty}.
*
* @static
* @param {?object} obj the object to check
* @param {?string} propName the name of the property
* @param {boolean} [includeInherited=false] specify if search in nested/inherited properties
* @param {string} [name='arg'] the name to use in generated error (for the first argument)
* @return {boolean} true if the object contains theat property, otherwise false
*/
static ensureObjectContainsProperty (obj, propName, includeInherited = false, name = 'arg') {
if (!Validator.doesObjectContainsProperty(obj, propName, includeInherited)) {
return new Error(`The object with name '${name}' does not contains the property '${propName}' with search in inherited: ${includeInherited}`)
}
}
/**
* Ensure that the given object does not contain any property
* that has a standard (reserved) property name.
*
* See {@link Validator.doesObjectContainsStandardProperty}.
*
* @static
* @param {?object} arg the object to check
* @param {?function} isPropStandard the function that tell the given argument (property), if it's standard
* @param {string} [name='arg'] the name to use in generated error (for the first argument)
* @return {Error} if at least one property with a standard name is found, nothing otherwise
*/
static ensureObjectDoesNotContainsStandardProperty (arg, isPropStandard, name = 'arg') {
if (Validator.doesObjectContainsStandardProperty(arg, isPropStandard)) {
return new Error(`The object with name '${name}' contains at least one property with a standard name`)
}
}
/**
* Tell the size of the given object
*
* @static
* @param {?object} arg the object to check
* @return {number} the size if it's an array|Map|Set|object|string, nothing otherwise
* @throws {TypeError} if it's not an array nor a collection nor object nor a string
*/
static getSize (arg) {
if ((arg === undefined || arg === null)) {
return
}
if (Array.isArray(arg)) {
return arg.length
} else if (arg instanceof Map || arg instanceof Set) {
return arg.size
} else if (typeof arg === 'object') {
return Object.keys(arg).length
} else if (typeof arg === 'string') {
return arg.length
}
// else
throw new TypeError(`Unable to calculate the size of the argument '${arg}'.`)
}
/**
* Tell the size in bytes of the given string.
*
* @static
* @param {?string} str the string to check
* @return {number} the size if it's a string, nothing otherwise
* @throws {TypeError} if it's not a string
*/
static getSizeInBytes (str) {
if ((str === undefined || str === null)) {
return
}
if (typeof str === 'string') {
return Buffer.from(str).length
}
// else
throw new TypeError(`Unable to calculate the size in bytes of the argument '${str}'.`)
}
/**
* Return the value of the variable given as argument.
*
* Note that this could have been written (in a shorter way)
* as an arrow function.
*
* @static
* @param {?object} arg the argument
* @return {string} the value of the variable (if defined and not null), nothing otherwise
*/
static getArgumentValue (arg) {
if ((arg === undefined || arg === null)) {
return arg
}
// else
return arguments[0]
}
/**
* Return the name of the variable given as argument.
*
* To use it, must be called using the trick to wrap argument
* inside an object literal, so for example use it inside a template string with:
* `${getArgumentName({x})}`
* with nested objects (like with options with a property x inside)
* you need to use with:
* `${getArgumentName({options})}.${getArgumentName({x})}`.
* Note that this could have been written (in a shorter way)
* as an arrow function.
*
* @static
* @param {?object} arg the argument
* @return {string} the name of the variable (if defined and not null), nothing otherwise
*/
static getArgumentName (arg) {
if ((arg === undefined || arg === null)) {
return
}
// else
return Object.keys(arg)[0]
}
/**
* Return the argument if it's defined and not null,
* otherwise the given default value is returned.
*
* @static
* @param {?object} arg the argument to return
* @param {?object} def the default value to return
* @return {object} the argument (if defined and not null), otherwise the default value
*/
static getOrElse (arg, def) {
if (typeof arg !== 'undefined' && arg !== null) {
return arg
}
// else
return def
}
/**
* Return a copy of the given ibject,
* with all properties filtered by the given function (predicate).
*
* @static
* @param {?object} obj the base object
* @param {?function} propFilter the function (predicate) for filtering properties
* @return {object} a new object containing only filtered properties
* @throws {TypeError} if obj is not a plain object, or propFilter is not a function
*/
static getObjectFilteredProperties (obj, propFilter) {
if (!Validator.isObjectPlain(obj)) throw new TypeError(`The argument 'obj' must be a plain object, instead got a '${typeof obj}'`)
if (!Validator.isFunction(propFilter)) throw new TypeError(`The argument 'propFilter' must be a function, instead got a '${typeof propFilter}'`)
const objFiltered = {}
for (const [key, value] of Object.entries(obj)) {
if (propFilter(key) === true) {
objFiltered[key] = value
}
}
return objFiltered
}
/**
* Throw if the given argument is an error instance or its subclass.
*
* See {@link Validator.isError}.
*
* @static
* @param {?object} arg the object to check
* @throws {Error} the given error
*/
static throwOnError (arg) {
if (Validator.isError(arg)) {
throw arg
}
}
/**
* Throw if the given argument is false.
* Note that this is similar to assertions.
*
* See {@link Validator.isError}.
*
* @static
* @param {?object} arg the object to check
* @param {string} [name='arg'] the name to use in generated error (or the value of first argument if not given)
* @throws {Error} if the given argument is not a boolean, or if it's false
*/
static throwOnFalse (arg, name = 'arg') {
if (!Validator.isBoolean(arg) || arg === false) {
return new Error(`The argument '${name}' is false`)
}
}
}
module.exports = Validator