@tdb/util
Version:
Shared helpers and utilities.
159 lines (143 loc) • 3.93 kB
text/typescript
import { R } from './libs';
import { compact } from './value.array';
/**
* Determines whether the value is a simple object (ie. not a class instance).
* @param value: The value to examine.
* @return {Boolean}.
*/
export function isPlainObject(value: any): boolean {
if (R.is(Object, value) === false) {
return false;
}
// Not plain if it has a modified constructor.
const ctr = value.constructor;
if (typeof ctr !== 'function') {
return false;
}
// If has modified prototype.
const prot = ctr.prototype;
if (R.is(Object, prot) === false) {
return false;
}
// If the constructor does not have an object-specific method.
if (prot.hasOwnProperty('isPrototypeOf') === false) {
return false;
}
// Finish up.
return true;
}
/**
* Determines if the given value is a boolean.
*/
export function isBoolString(value?: string) {
const asString = (value || '')
.toString()
.trim()
.toLowerCase();
return asString === 'true' || asString === 'false';
}
/**
* A safe way to test any value as to wheather is is 'blank'
* meaning it can be either:
* - null
* - undefined
* - empty-string ('')
* - empty-array ([]).
*/
export function isBlank(value: any): boolean {
if (value === null || value === undefined) {
return true;
}
if (R.is(Array, value) && compact(value).length === 0) {
return true;
}
if (R.is(String, value) && value.trim() === '') {
return true;
}
return false;
}
/**
* Determines whether the given value is a number, or can be
* parsed into a number.
*
* NOTE: Examines string values to see if they are numeric.
*
* @param value: The value to examine.
* @returns true if the value is a number.
*/
export function isNumeric(value: any) {
if (isBlank(value)) {
return false;
}
const num = parseFloat(value);
if (num === undefined) {
return false;
}
if (num.toString().length !== value.toString().length) {
return false;
}
return !Number.isNaN(num);
}
/**
* Determines whether the given value is a single alphabetic letter.
*/
export function isLetter(value: any) {
return (
isAlpha(value) && R.is(String, value) && (value as string).length === 1
);
}
/**
* Determines whether the given value is a alphabet letter.
*/
export function isAlpha(value: any) {
if (isBlank(value) || !R.is(String, value)) {
return false;
}
const text = value as string;
if (text.length === 0) {
return false;
}
return Boolean(text.match(/^[a-zA-Z]+$/g));
}
/**
* Determines whether the given string contains whitespace.
*/
export function hasWhitespace(text: string) {
return Boolean(text.match(/\s/g));
}
/**
* Determines whether the given value is a Promise.
*/
export function isPromise(value?: any) {
return R.is(Object, value) && R.is(Function, value.then);
}
/**
* Determines whether the given value is a JSON string.
*/
export function isJson(value?: any) {
if (!R.is(String, value)) {
return false;
}
const text = (value as string).trim();
return R.startsWith('{', text) || R.startsWith('[', text);
}
/**
* Determines if a value is an ISO date.
* See:
* https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime
*/
export function isIsoDate(value?: string) {
return value ? isoDateRegEx.test(value) : false;
}
const isoDateRegEx = new RegExp(
/(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/,
);
/**
* Determines whether a string is a valid email address.
*/
export function isEmail(value?: string) {
return value ? emailRegEx.test(value) : false;
}
const emailRegEx = new RegExp(
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
);