import { isFunction, isMap, isSet, Json, JsonArray, JsonObject, JsonPrimitive } from '@typed/common' import { Is, IsNot, pipe2 } from '@typed/lambda' import { all } from './all' import { complement } from './complement' import { equals } from './equals' import { not } from './not' import { or } from './or' export { isFunction, isMap, isSet } export const is = (value: A): Is => equals(value) as any export const isNot = (a: A): IsNot => pipe2(is(a), not) as any export const isAndIsNot = (value: A): readonly [Is, IsNot] => [is(value), isNot(value)] as const export const isNotFunction: IsNot = complement(isFunction) export const isNotMap: IsNot> = complement(isMap) export const isNotSet: IsNot> = complement(isSet) export const [isUndefined, isNotUndefined] = isAndIsNot(undefined) export const [isNull, isNotNull] = isAndIsNot(null) export function isArray(x: unknown): x is unknown[] { return Array.isArray(x) } export const isNotArray = pipe2(isArray, not) as IsNot> export function isIterator(x: unknown): x is Iterator { return x && isFunction((x as Iterator).next) } export const isNotIterator: IsNot> = complement(isIterable) export function isIterable(x: unknown): x is Iterable { return x && isFunction((x as Iterable)[Symbol.iterator]) } export const isNotIterable: IsNot> = complement(isIterable) export const isGenerator: Is> = ( x: unknown, ): x is Generator => { return ( isIterable(x) && isFunction((x as Generator).next) && isFunction((x as Generator).return) && isFunction((x as Generator).throw) ) } export const isNotGenerator = complement(isGenerator) export const isArrayLike: Is> = (x): x is ArrayLike => { if (isArray(x)) { return true } if (!x || !isObject(x) || !isString(x)) { return false } const asObj: { length: number } = x if (asObj.length === 0) { return true } if (asObj.length > 0) { return ( Object.prototype.hasOwnProperty.call(x, 0) && Object.prototype.hasOwnProperty.call(x, asObj.length - 1) ) } return false } export const isNotArrayLike = complement(isArrayLike) export const isNumber: Is = (u): u is number => typeof u === 'number' && !Number.isNaN(u) export const isNotNumber: IsNot = complement(isNumber) export const isString: Is = (u): u is string => typeof u === 'string' export const isNotString: IsNot = complement(isString) export const isObject: Is = (u): u is object => typeof u === 'object' export const isNotObject: IsNot = complement(isObject) export const isRecord: Is>> = ( u, ): u is Readonly> => u && isObject(u) && isNotArrayLike(u) && isNotMap(u) && isNotSet(u) export const isNotRecord: IsNot>> = complement(isRecord) export const isPromiseLike: Is> = (x: unknown): x is PromiseLike => x && isObject(x) && isFunction((x as PromiseLike).then) export const isNotPromiseLie: IsNot> = complement(isPromiseLike) export const [isTrue, isNotTrue] = isAndIsNot(true) export const [isFalse, isNotFalse] = isAndIsNot(false) export const isBoolean: Is = or(isTrue, isFalse) export const isNotBoolean: IsNot = complement(isBoolean) export const isJsonArray: Is = function isJsonArray(x: unknown): x is JsonArray { return isArray(x) && all(isJson, x) } export const isNotJsonArray: IsNot = complement(isJsonArray) export const isJsonObject: Is = function isJsonObject(x: unknown): x is JsonObject { return ( !isArray(x) && isObject(x) && all(isString, Object.keys(x)) && all(isJson, Object.values(x)) ) } export const isNotJsonObject: IsNot = complement(isJsonObject) export const isJsonPrimitive: Is = or(isString, or(isNumber, or(isBoolean, isNull))) export const isNotJsonPrimitive: IsNot = complement(isJsonPrimitive) export const isJson: Is = or(isJsonPrimitive, or(isJsonArray, isJsonObject)) export const isNotJson: IsNot = complement(isJson) export const isDate: Is = (u): u is Date => u instanceof Date export const isNotDate: IsNot = complement(isDate)