UNPKG

rambdax

Version:

Extended version of Rambda - a lightweight, faster alternative to Ramda

2,117 lines (1,694 loc) 83.3 kB
const _isArray = Array.isArray; function type(input) { const typeOf = typeof input; if (input === null) { return 'Null'; } else if (input === undefined) { return 'Undefined'; } else if (typeOf === 'boolean') { return 'Boolean'; } else if (typeOf === 'number') { return Number.isNaN(input) ? 'NaN' : 'Number'; } else if (typeOf === 'string') { return 'String'; } else if (_isArray(input)) { return 'Array'; } else if (typeOf === 'symbol') { return 'Symbol'; } else if (input instanceof RegExp) { return 'RegExp'; } const asStr = input && input.toString ? input.toString() : ''; if (['true', 'false'].includes(asStr)) return 'Boolean'; if (!Number.isNaN(Number(asStr))) return 'Number'; if (asStr.startsWith('async')) return 'Async'; if (asStr === '[object Promise]') return 'Promise'; if (typeOf === 'function') return 'Function'; if (input instanceof String) return 'String'; return 'Object'; } function isTruthy(x) { if (_isArray(x)) { return x.length > 0; } if (type(x) === 'Object') { return Object.keys(x).length > 0; } return Boolean(x); } function allFalse(...inputs) { let counter = 0; while (counter < inputs.length) { const x = inputs[counter]; if (type(x) === 'Function') { if (isTruthy(x())) { return false; } } else if (isTruthy(x)) { return false; } counter++; } return true; } function isFalsy(x) { if (_isArray(x)) { return x.length === 0; } if (type(x) === 'Object') { return Object.keys(x).length === 0; } return !x; } function allTrue(...inputs) { let counter = 0; while (counter < inputs.length) { const x = inputs[counter]; if (type(x) === 'Function') { if (isFalsy(x())) { return false; } } else if (isFalsy(x)) { return false; } counter++; } return true; } function allType(targetType) { return (...inputs) => { let counter = 0; while (counter < inputs.length) { if (type(inputs[counter]) !== targetType) { return false; } counter++; } return true; }; } function anyFalse(...inputs) { let counter = 0; while (counter < inputs.length) { const x = inputs[counter]; if (type(x) === 'Function') { if (isFalsy(x())) { return true; } } else if (isFalsy(x)) { return true; } counter++; } return false; } function anyTrue(...inputs) { let counter = 0; while (counter < inputs.length) { const x = inputs[counter]; if (type(x) === 'Function') { if (isTruthy(x())) { return true; } } else if (isTruthy(x)) { return true; } counter++; } return false; } function anyType(targetType) { return (...inputs) => { let counter = 0; while (counter < inputs.length) { if (type(inputs[counter]) === targetType) { return true; } counter++; } return false; }; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _isInteger(n) { return n << 0 === n; } var _isInteger$1 = Number.isInteger || _isInteger; function curry(fn, args = []) { return (..._args) => (rest => rest.length >= fn.length ? fn(...rest) : curry(fn, rest))([...args, ..._args]); } function assocFn(prop, newValue, obj) { return Object.assign({}, obj, { [prop]: newValue }); } const assoc = curry(assocFn); function assocPathFn(path, newValue, input) { const pathArrValue = typeof path === 'string' ? path.split('.').map(x => _isInteger(Number(x)) ? Number(x) : x) : path; if (pathArrValue.length === 0) { return newValue; } const index = pathArrValue[0]; if (pathArrValue.length > 1) { const condition = typeof input !== 'object' || input === null || !input.hasOwnProperty(index); const nextinput = condition ? _isInteger(pathArrValue[1]) ? [] : {} : input[index]; newValue = assocPathFn(Array.prototype.slice.call(pathArrValue, 1), newValue, nextinput); } if (_isInteger(index) && _isArray(input)) { const arr = input.slice(); arr[index] = newValue; return arr; } return assoc(index, newValue, input); } const assocPath = curry(assocPathFn); function path(pathInput, obj) { if (arguments.length === 1) return _obj => path(pathInput, _obj); if (obj === null || obj === undefined) { return undefined; } let willReturn = obj; let counter = 0; const pathArrValue = typeof pathInput === 'string' ? pathInput.split('.') : pathInput; while (counter < pathArrValue.length) { if (willReturn === null || willReturn === undefined) { return undefined; } willReturn = willReturn[pathArrValue[counter]]; counter++; } return willReturn; } const ALLOWED_OPERATIONS = ['remove', 'add', 'update']; function removeAtPath(path, obj) { const p = typeof path === 'string' ? path.split('.') : path; const len = p.length; if (len === 0) return; if (len === 1) return delete obj[p[0]]; if (len === 2) return delete obj[p[0]][p[1]]; if (len === 3) return delete obj[p[0]][p[1]][p[2]]; if (len === 4) return delete obj[p[0]][p[1]][p[2]][p[3]]; if (len === 5) return delete obj[p[0]][p[1]][p[2]][p[3]][p[4]]; if (len === 6) { return delete obj[p[0]][p[1]][p[2]][p[3]][p[4]][p[5]]; } if (len === 7) { return delete obj[p[0]][p[1]][p[2]][p[3]][p[4]][p[5]][p[6]]; } if (len === 8) { return delete obj[p[0]][p[1]][p[2]][p[3]][p[4]][p[5]][p[6]][p[7]]; } if (len === 9) { return delete obj[p[0]][p[1]][p[2]][p[3]][p[4]][p[5]][p[6]][p[7]][p[8]]; } if (len === 10) { return delete obj[p[0]][p[1]][p[2]][p[3]][p[4]][p[5]][p[6]][p[7]][p[8]][p[9]]; } } function applyDiff(rules, obj) { if (arguments.length === 1) return _obj => applyDiff(rules, _obj); let clone = _objectSpread2({}, obj); rules.forEach(({ op, path: path$1, value }) => { if (!ALLOWED_OPERATIONS.includes(op)) return; if (op === 'add' && path$1 && value !== undefined) { if (path(path$1, obj)) return; return clone = assocPath(path$1, value, clone); } if (op === 'remove') { if (path(path$1, obj) === undefined) return; return removeAtPath(path$1, clone); } if (op === 'update' && path$1 && value !== undefined) { if (path(path$1, obj) === undefined) return; return clone = assocPath(path$1, value, clone); } }); return clone; } function composeAsync(...inputArguments) { return async function (startArgument) { let argumentsToPass = startArgument; while (inputArguments.length !== 0) { const fn = inputArguments.pop(); const typeFn = type(fn); if (typeFn === 'Async') { argumentsToPass = await fn(argumentsToPass); } else { argumentsToPass = fn(argumentsToPass); if (type(argumentsToPass) === 'Promise') { argumentsToPass = await argumentsToPass; } } } return argumentsToPass; }; } function parseError(maybeError) { const typeofError = maybeError.__proto__.toString(); if (!['Error', 'TypeError'].includes(typeofError)) return []; return [typeofError, maybeError.message]; } function parseDate(maybeDate) { if (!maybeDate.toDateString) return [false]; return [true, maybeDate.getTime()]; } function parseRegex(maybeRegex) { if (maybeRegex.constructor !== RegExp) return [false]; return [true, maybeRegex.toString()]; } function equals(a, b) { if (arguments.length === 1) return _b => equals(a, _b); const aType = type(a); if (aType !== type(b)) return false; if (aType === 'Function') { return a.name === undefined ? false : a.name === b.name; } if (['NaN', 'Undefined', 'Null'].includes(aType)) return true; if (aType === 'Number') { if (Object.is(-0, a) !== Object.is(-0, b)) return false; return a.toString() === b.toString(); } if (['String', 'Boolean'].includes(aType)) { return a.toString() === b.toString(); } if (aType === 'Array') { const aClone = Array.from(a); const bClone = Array.from(b); if (aClone.toString() !== bClone.toString()) { return false; } let loopArrayFlag = true; aClone.forEach((aCloneInstance, aCloneIndex) => { if (loopArrayFlag) { if (aCloneInstance !== bClone[aCloneIndex] && !equals(aCloneInstance, bClone[aCloneIndex])) { loopArrayFlag = false; } } }); return loopArrayFlag; } const aRegex = parseRegex(a); const bRegex = parseRegex(b); if (aRegex[0]) { return bRegex[0] ? aRegex[1] === bRegex[1] : false; } else if (bRegex[0]) return false; const aDate = parseDate(a); const bDate = parseDate(b); if (aDate[0]) { return bDate[0] ? aDate[1] === bDate[1] : false; } else if (bDate[0]) return false; const aError = parseError(a); const bError = parseError(b); if (aError[0]) { return bError[0] ? aError[0] === bError[0] && aError[1] === bError[1] : false; } if (aType === 'Object') { const aKeys = Object.keys(a); if (aKeys.length !== Object.keys(b).length) { return false; } let loopObjectFlag = true; aKeys.forEach(aKeyInstance => { if (loopObjectFlag) { const aValue = a[aKeyInstance]; const bValue = b[aKeyInstance]; if (aValue !== bValue && !equals(aValue, bValue)) { loopObjectFlag = false; } } }); return loopObjectFlag; } return false; } function count(searchFor, list) { if (arguments.length === 1) { return _list => count(searchFor, _list); } if (!_isArray(list)) return 0; return list.filter(x => equals(x, searchFor)).length; } function debounce(func, ms, immediate = false) { let timeout; return function (...input) { const later = function () { timeout = null; if (!immediate) { func.apply(null, input); } }; const callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, ms); if (callNow) { func.apply(null, input); } }; } const DELAY = 'RAMBDAX_DELAY'; function delay(ms) { return new Promise(resolve => { setTimeout(() => { resolve(DELAY); }, ms); }); } function includes(valueToFind, input) { if (arguments.length === 1) return _input => includes(valueToFind, _input); if (typeof input === 'string') { return input.includes(valueToFind); } if (!input) { throw new TypeError(`Cannot read property \'indexOf\' of ${input}`); } if (!_isArray(input)) return false; let index = -1; while (++index < input.length) { if (equals(input[index], valueToFind)) { return true; } } return false; } function excludes(valueToFind, input) { if (arguments.length === 1) return _input => excludes(valueToFind, _input); return includes(valueToFind, input) === false; } function filterObject(fn, obj) { const willReturn = {}; for (const prop in obj) { if (fn(obj[prop], prop, obj)) { willReturn[prop] = obj[prop]; } } return willReturn; } function filterArray(predicate, list, indexed = false) { let index = 0; const len = list.length; const willReturn = []; while (index < len) { const predicateResult = indexed ? predicate(list[index], index) : predicate(list[index]); if (predicateResult) { willReturn.push(list[index]); } index++; } return willReturn; } function filter(predicate, iterable) { if (arguments.length === 1) { return _iterable => filter(predicate, _iterable); } if (!iterable) return []; if (_isArray(iterable)) return filterArray(predicate, iterable); return filterObject(predicate, iterable); } async function mapAsyncFn(fn, listOrObject) { if (_isArray(listOrObject)) { const willReturn = []; let i = 0; for (const a of listOrObject) { willReturn.push(await fn(a, i++)); } return willReturn; } const willReturn = {}; for (const prop in listOrObject) { willReturn[prop] = await fn(listOrObject[prop], prop); } return willReturn; } function mapAsync(fn, listOrObject) { if (arguments.length === 1) { return async _listOrObject => mapAsyncFn(fn, _listOrObject); } return new Promise((resolve, reject) => { mapAsyncFn(fn, listOrObject).then(resolve).catch(reject); }); } function filterAsyncFn(predicate, listOrObject) { return new Promise((resolve, reject) => { mapAsync(predicate, listOrObject).then(predicateResult => { if (_isArray(predicateResult)) { const filtered = listOrObject.filter((_, i) => predicateResult[i]); return resolve(filtered); } const filtered = filter((_, prop) => predicateResult[prop], listOrObject); return resolve(filtered); }).catch(reject); }); } function filterAsync(predicate, listOrObject) { if (arguments.length === 1) { return async _listOrObject => filterAsyncFn(predicate, _listOrObject); } return new Promise((resolve, reject) => { filterAsyncFn(predicate, listOrObject).then(resolve).catch(reject); }); } function filterIndexed(predicate, iterable) { if (arguments.length === 1) return _iterable => filterIndexed(predicate, _iterable); if (!iterable) return []; if (_isArray(iterable)) return filterArray(predicate, iterable, true); return filterObject(predicate, iterable); } const _keys = Object.keys; function mapArray(fn, list, isIndexed = false) { let index = 0; const willReturn = Array(list.length); while (index < list.length) { willReturn[index] = isIndexed ? fn(list[index], index) : fn(list[index]); index++; } return willReturn; } function mapObject(fn, obj) { let index = 0; const keys = _keys(obj); const len = keys.length; const willReturn = {}; while (index < len) { const key = keys[index]; willReturn[key] = fn(obj[key], key, obj); index++; } return willReturn; } function map(fn, list) { if (arguments.length === 1) return _list => map(fn, _list); if (list === undefined) return []; if (_isArray(list)) return mapArray(fn, list); return mapObject(fn, list); } function mapIndexed(fn, iterable) { if (arguments.length === 1) { return _iterable => mapIndexed(fn, _iterable); } if (iterable === undefined) return []; if (_isArray(iterable)) return mapArray(fn, iterable, true); return mapObject(fn, iterable); } function forEachIndexed(fn, iterable) { if (arguments.length === 1) { return _iterable => forEachIndexed(fn, _iterable); } mapIndexed(fn, iterable); return iterable; } function merge(target, newProps) { if (arguments.length === 1) return _newProps => merge(target, _newProps); return Object.assign({}, target || {}, newProps || {}); } function pick(propsToPick, input) { if (arguments.length === 1) return _input => pick(propsToPick, _input); if (input === null || input === undefined) { return undefined; } const keys = typeof propsToPick === 'string' ? propsToPick.split(',') : propsToPick; const willReturn = {}; let counter = 0; while (counter < keys.length) { if (keys[counter] in input) { willReturn[keys[counter]] = input[keys[counter]]; } counter++; } return willReturn; } let holder = {}; function getter(key) { const typeKey = type(key); if (typeKey === 'String') return holder[key]; if (typeKey === 'Array') return pick(key, holder); return holder; } function setter(maybeKey, maybeValue) { const typeKey = type(maybeKey); const typeValue = type(maybeValue); if (typeKey === 'String') { if (typeValue === 'Function') { return holder[maybeKey] = maybeValue(holder[maybeKey]); } return holder[maybeKey] = maybeValue; } if (typeKey !== 'Object') return; holder = merge(holder, maybeKey); } function reset() { holder = {}; } function glue(input, glueChar) { return input.split('\n').filter(x => x.trim().length > 0).map(x => x.trim()).join(glueChar === undefined ? ' ' : glueChar); } function createThenable(fn) { return async function (...input) { return fn(...input); }; } function ifElseAsync(condition, ifFn, elseFn) { return (...inputs) => new Promise((resolve, reject) => { const conditionPromise = createThenable(condition); const ifFnPromise = createThenable(ifFn); const elseFnPromise = createThenable(elseFn); conditionPromise(...inputs).then(conditionResult => { const promised = conditionResult === true ? ifFnPromise : elseFnPromise; promised(...inputs).then(resolve).catch(reject); }).catch(reject); }); } const getOccurances = input => input.match(/{{\s*.+?\s*}}/g); const getOccuranceProp = occurance => occurance.replace(/{{\s*|\s*}}/g, ''); const replace = ({ inputHolder, prop, replacer }) => { const regexBase = `{{${prop}}}`; const regex = new RegExp(regexBase, 'g'); return inputHolder.replace(regex, replacer); }; function interpolate(input, templateInput) { if (arguments.length === 1) { return _templateInput => interpolate(input, _templateInput); } const occurances = getOccurances(input); if (occurances === null) return input; let inputHolder = input; for (const occurance of occurances) { const prop = getOccuranceProp(occurance); inputHolder = replace({ inputHolder, prop, replacer: templateInput[prop] }); } return inputHolder; } function isFunction(fn) { return ['Async', 'Function'].includes(type(fn)); } function isPromise(x) { return ['Async', 'Promise'].includes(type(x)); } function isType(xType, x) { if (arguments.length === 1) { return xHolder => isType(xType, xHolder); } return type(x) === xType; } function all(predicate, list) { if (arguments.length === 1) return _list => all(predicate, _list); for (let i = 0; i < list.length; i++) { if (!predicate(list[i])) return false; } return true; } function any(predicate, list) { if (arguments.length === 1) return _list => any(predicate, _list); let counter = 0; while (counter < list.length) { if (predicate(list[counter], counter)) { return true; } counter++; } return false; } function baseSlice(array, start, end) { let index = -1; let { length } = array; end = end > length ? length : end; if (end < 0) { end += length; } length = start > end ? 0 : end - start >>> 0; start >>>= 0; const result = Array(length); while (++index < length) { result[index] = array[index + start]; } return result; } function init(listOrString) { if (typeof listOrString === 'string') return listOrString.slice(0, -1); return listOrString.length ? baseSlice(listOrString, 0, -1) : []; } function test(pattern, str) { if (arguments.length === 1) return _str => test(pattern, _str); if (typeof pattern === 'string') { throw new TypeError(`‘test’ requires a value of type RegExp as its first argument; received "${pattern}"`); } return str.search(pattern) !== -1; } function toLower(str) { return str.toLowerCase(); } function isPrototype(input) { const currentPrototype = input.prototype; const list = [Number, String, Boolean, Promise]; let toReturn = false; let counter = -1; while (++counter < list.length && !toReturn) { if (currentPrototype === list[counter].prototype) toReturn = true; } return toReturn; } function prototypeToString(input) { const currentPrototype = input.prototype; const list = [Number, String, Boolean, Promise]; const translatedList = ['Number', 'String', 'Boolean', 'Promise']; let found; let counter = -1; while (++counter < list.length) { if (currentPrototype === list[counter].prototype) found = counter; } return translatedList[found]; } const typesWithoutPrototype = ['any', 'promise', 'async', 'function']; function fromPrototypeToString(rule) { if (_isArray(rule) || rule === undefined || rule === null || rule.prototype === undefined || typesWithoutPrototype.includes(rule)) { return { rule, parsed: false }; } if (String.prototype === rule.prototype) { return { rule: 'string', parsed: true }; } if (Boolean.prototype === rule.prototype) { return { rule: 'boolean', parsed: true }; } if (Number.prototype === rule.prototype) { return { rule: 'number', parsed: true }; } return { rule: type(rule.prototype).toLowerCase(), parsed: true }; } function getRuleAndType(schema, requirementRaw) { const ruleRaw = schema[requirementRaw]; const typeIs = type(ruleRaw); const { rule, parsed } = fromPrototypeToString(ruleRaw); return { rule: rule, ruleType: parsed ? 'String' : typeIs }; } function isValid({ input, schema }) { if (input === undefined || schema === undefined) return false; let flag = true; const boom = boomFlag => { if (!boomFlag) { flag = false; } }; for (const requirementRaw in schema) { if (flag) { const isOptional = requirementRaw.endsWith('?'); const requirement = isOptional ? init(requirementRaw) : requirementRaw; const { rule, ruleType } = getRuleAndType(schema, requirementRaw); const inputProp = input[requirement]; const inputPropType = type(input[requirement]); const ok = isOptional && inputProp !== undefined || !isOptional; if (!ok || rule === 'any' && inputProp != null || rule === inputProp) continue; if (ruleType === 'Object') { const isValidResult = isValid({ input: inputProp, schema: rule }); boom(isValidResult); } else if (ruleType === 'String') { boom(toLower(inputPropType) === rule); } else if (typeof rule === 'function') { boom(rule(inputProp)); } else if (ruleType === 'Array' && inputPropType === 'String') { boom(includes(inputProp, rule)); } else if (ruleType === 'Array' && rule.length === 1 && inputPropType === 'Array') { const [currentRule] = rule; const currentRuleType = type(currentRule); boom(currentRuleType === 'String' || currentRuleType === 'Object' || isPrototype(currentRule)); if (currentRuleType === 'Object' && flag) { const isValidResult = all(inputPropInstance => isValid({ input: inputPropInstance, schema: currentRule }), inputProp); boom(isValidResult); } else if (flag) { const actualRule = currentRuleType === 'String' ? currentRule : prototypeToString(currentRule); const isInvalidResult = any(inputPropInstance => type(inputPropInstance).toLowerCase() !== actualRule.toLowerCase(), inputProp); boom(!isInvalidResult); } } else if (ruleType === 'RegExp' && inputPropType === 'String') { boom(test(rule, inputProp)); } else { boom(false); } } } return flag; } function forEach(fn, list) { if (arguments.length === 1) return _list => forEach(fn, _list); if (list === undefined) { return; } if (_isArray(list)) { let index = 0; const len = list.length; while (index < len) { fn(list[index]); index++; } } else { let index = 0; const keys = _keys(list); const len = keys.length; while (index < len) { const key = keys[index]; fn(list[key], key, list); index++; } } return list; } async function isValidAsync({ schema, input }) { const asyncSchema = {}; const simpleSchema = {}; forEach((rule, prop) => { if (isPromise(rule)) { asyncSchema[prop] = rule; } else { simpleSchema[prop] = rule; } }, schema); if (Object.keys(asyncSchema).length === 0) return isValid({ input, schema }); if (!isValid({ input, schema: simpleSchema })) return false; let toReturn = true; for (const singleRuleProp in asyncSchema) { if (toReturn) { const validated = await asyncSchema[singleRuleProp](input[singleRuleProp]); if (!validated) toReturn = false; } } return toReturn; } const Const = x => ({ x, map: fn => Const(x) }); function view(lens, target) { if (arguments.length === 1) return _target => view(lens, _target); return lens(Const)(target).x; } function lensEqFn(lens, target, input) { return equals(view(lens, input), target); } const lensEq = curry(lensEqFn); function lensSatisfiesFn(predicate, lens, input) { return Boolean(predicate(view(lens, input))); } const lensSatisfies = curry(lensSatisfiesFn); async function mapFastAsyncFn(fn, arr) { const promised = arr.map((a, i) => fn(a, i)); return Promise.all(promised); } function mapFastAsync(fn, arr) { if (arguments.length === 1) { return async holder => mapFastAsyncFn(fn, holder); } return new Promise((resolve, reject) => { mapFastAsyncFn(fn, arr).then(resolve).catch(reject); }); } function splitEvery(sliceLength, listOrString) { if (arguments.length === 1) { return _listOrString => splitEvery(sliceLength, _listOrString); } if (sliceLength < 1) { throw new Error('First argument to splitEvery must be a positive integer'); } const willReturn = []; let counter = 0; while (counter < listOrString.length) { willReturn.push(listOrString.slice(counter, counter += sliceLength)); } return willReturn; } async function mapAsyncLimitFn(iterable, limit, list) { if (list.length < limit) return mapFastAsync(iterable, list); const slices = splitEvery(limit, list); let toReturn = []; for (const slice of slices) { const iterableResult = await mapFastAsyncFn(iterable, slice); toReturn = [...toReturn, ...iterableResult]; } return toReturn; } function mapAsyncLimit(iterable, limit, list) { if (arguments.length === 2) { return async _list => mapAsyncLimitFn(iterable, limit, _list); } return new Promise((resolve, reject) => { mapAsyncLimitFn(iterable, limit, list).then(resolve).catch(reject); }); } function mapKeys(changeKeyFn, obj) { if (arguments.length === 1) return _obj => mapKeys(changeKeyFn, _obj); const toReturn = {}; Object.keys(obj).forEach(prop => toReturn[changeKeyFn(prop)] = obj[prop]); return toReturn; } function mergeAll(arr) { let willReturn = {}; map(val => { willReturn = merge(willReturn, val); }, arr); return willReturn; } function schemaToString(schema) { if (type(schema) !== 'Object') { return fromPrototypeToString(schema).rule; } return map(x => { const { rule, parsed } = fromPrototypeToString(x); const xType = type(x); if (xType === 'Function' && !parsed) return 'Function'; return parsed ? rule : xType; }, schema); } function check(singleInput, schema) { return isValid({ input: { singleInput }, schema: { singleInput: schema } }); } function ok(...inputs) { return (...schemas) => { let failedSchema; const anyError = any((singleInput, i) => { const schema = schemas[i] === undefined ? schemas[0] : schemas[i]; const checked = check(singleInput, schema); if (!checked) { failedSchema = JSON.stringify({ input: singleInput, schema: schemaToString(schema) }); } return !checked; }, inputs); if (anyError) { const errorMessage = inputs.length > 1 ? glue(` Failed R.ok - reason: ${failedSchema} all inputs: ${JSON.stringify(inputs)} all schemas: ${JSON.stringify(schemas.map(schemaToString))} `, '\n') : `Failed R.ok - ${failedSchema}`; throw new Error(errorMessage); } }; } function mapToObject(fn, list) { if (arguments.length === 1) { return listHolder => mapToObject(fn, listHolder); } ok(type(fn), type(list))('Function', 'Array'); return mergeAll(map(fn, list)); } async function mapToObjectAsyncFn(fn, list) { let toReturn = {}; const innerIterable = async x => { const intermediateResult = await fn(x); if (intermediateResult === false) return; toReturn = _objectSpread2(_objectSpread2({}, toReturn), intermediateResult); }; await mapAsync(innerIterable, list); return toReturn; } function mapToObjectAsync(fn, list) { if (arguments.length === 1) { return async _list => mapToObjectAsyncFn(fn, _list); } return new Promise((resolve, reject) => { mapToObjectAsyncFn(fn, list).then(resolve).catch(reject); }); } function maybe(ifRule, whenIf, whenElse) { const whenIfInput = ifRule && type(whenIf) === 'Function' ? whenIf() : whenIf; const whenElseInput = !ifRule && type(whenElse) === 'Function' ? whenElse() : whenElse; return ifRule ? whenIfInput : whenElseInput; } function compose(...fns) { if (fns.length === 0) { throw new Error('compose requires at least one argument'); } return (...args) => { const list = fns.slice(); if (list.length > 0) { const fn = list.pop(); let result = fn(...args); while (list.length > 0) { result = list.pop()(result); } return result; } }; } function replaceFn(pattern, replacer, str) { return str.replace(pattern, replacer); } const replace$1 = curry(replaceFn); function sort(sortFn, list) { if (arguments.length === 1) return _list => sort(sortFn, _list); const clone = list.slice(); return clone.sort(sortFn); } function take(howMany, listOrString) { if (arguments.length === 1) return _listOrString => take(howMany, _listOrString); if (howMany < 0) return listOrString.slice(); if (typeof listOrString === 'string') return listOrString.slice(0, howMany); return baseSlice(listOrString, 0, howMany); } const cache = {}; const normalizeObject = obj => { const sortFn = (a, b) => a > b ? 1 : -1; const willReturn = {}; compose(map(prop => willReturn[prop] = obj[prop]), sort(sortFn))(Object.keys(obj)); return willReturn; }; const stringify = a => { if (type(a) === 'String') { return a; } else if (['Function', 'Async'].includes(type(a))) { const compacted = replace$1(/\s{1,}/g, ' ', a.toString()); return replace$1(/\s/g, '_', take(15, compacted)); } else if (type(a) === 'Object') { return JSON.stringify(normalizeObject(a)); } return JSON.stringify(a); }; const generateProp = (fn, ...inputArguments) => { let propString = ''; inputArguments.forEach(inputArgument => { propString += `${stringify(inputArgument)}_`; }); return `${propString}${stringify(fn)}`; }; function memoize(fn, ...inputArguments) { if (arguments.length === 1) { return (...inputArgumentsHolder) => memoize(fn, ...inputArgumentsHolder); } const prop = generateProp(fn, ...inputArguments); if (prop in cache) return cache[prop]; if (type(fn) === 'Async') { return new Promise(resolve => { fn(...inputArguments).then(result => { cache[prop] = result; resolve(result); }); }); } const result = fn(...inputArguments); cache[prop] = result; return result; } function nextIndex(index, list) { return index >= list.length - 1 ? 0 : index + 1; } function partialCurry(fn, input) { return rest => { if (type(fn) === 'Async') { return new Promise((resolve, reject) => { fn(merge(rest, input)).then(resolve).catch(reject); }); } return fn(merge(rest, input)); }; } async function whenObject(predicate, input) { const yes = {}; const no = {}; Object.entries(input).forEach(([prop, value]) => { if (predicate(value, prop)) { yes[prop] = value; } else { no[prop] = value; } }); return [yes, no]; } async function partitionAsyncFn(predicate, input) { if (!_isArray(input)) return whenObject(predicate, input); const yes = []; const no = []; for (const i in input) { const predicateResult = await predicate(input[i], Number(i)); if (predicateResult) { yes.push(input[i]); } else { no.push(input[i]); } } return [yes, no]; } function partitionAsync(predicate, list) { if (arguments.length === 1) { return async _list => partitionAsyncFn(predicate, _list); } return new Promise((resolve, reject) => { partitionAsyncFn(predicate, list).then(resolve).catch(reject); }); } function pass(...inputs) { return (...schemas) => any((x, i) => { const schema = schemas[i] === undefined ? schemas[0] : schemas[i]; return !check(x, schema); }, inputs) === false; } function pipeAsync(...inputArguments) { return async function (startArgument) { let argumentsToPass = startArgument; while (inputArguments.length !== 0) { const fn = inputArguments.shift(); const typeFn = type(fn); if (typeFn === 'Async') { argumentsToPass = await fn(argumentsToPass); } else { argumentsToPass = fn(argumentsToPass); if (type(argumentsToPass) === 'Promise') { argumentsToPass = await argumentsToPass; } } } return argumentsToPass; }; } function pipe(...fns) { if (fns.length === 0) throw new Error('pipe requires at least one argument'); return (...args) => { const list = fns.slice(); if (list.length > 0) { const fn = list.shift(); let result = fn(...args); while (list.length > 0) { result = list.shift()(result); } return result; } }; } function piped(...inputs) { const [input, ...fnList] = inputs; return pipe(...fnList)(input); } async function pipedAsync(...inputs) { const [input, ...fnList] = inputs; let argumentsToPass = input; while (fnList.length !== 0) { const fn = fnList.shift(); const typeFn = type(fn); if (typeFn === 'Async') { argumentsToPass = await fn(argumentsToPass); } else { argumentsToPass = fn(argumentsToPass); } } return argumentsToPass; } function prevIndex(index, list) { return index === 0 ? list.length - 1 : index - 1; } function produce(rules, input) { if (arguments.length === 1) { return _input => produce(rules, _input); } return map(singleRule => type(singleRule) === 'Object' ? produce(singleRule, input) : singleRule(input), rules); } function promisify({ condition, input, prop }) { return new Promise((resolve, reject) => { if (type(condition) !== 'Async') { return resolve({ type: prop, payload: condition(input) }); } condition(input).then(result => { resolve({ type: prop, payload: result }); }).catch(err => reject(err)); }); } function produceFn(conditions, input) { let asyncConditionsFlag = false; for (const prop in conditions) { if (asyncConditionsFlag === false && type(conditions[prop]) === 'Async') { asyncConditionsFlag = true; } } if (asyncConditionsFlag === false) { const willReturn = {}; for (const prop in conditions) { willReturn[prop] = conditions[prop](input); } return Promise.resolve(willReturn); } const promised = []; for (const prop in conditions) { const condition = conditions[prop]; promised.push(promisify({ input, condition, prop })); } return new Promise((resolve, reject) => { Promise.all(promised).then(results => { const willReturn = {}; map(result => willReturn[result.type] = result.payload, results); resolve(willReturn); }).catch(err => reject(err)); }); } function produceAsync(conditions, input) { if (arguments.length === 1) { return async _input => produceFn(conditions, _input); } return new Promise((resolve, reject) => { produceFn(conditions, input).then(resolve).catch(reject); }); } function random(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } function remove(inputs, text) { if (arguments.length === 1) { return textHolder => remove(inputs, textHolder); } if (type(text) !== 'String') { throw new Error(`R.remove requires string not ${type(text)}`); } if (type(inputs) !== 'Array') { return replace$1(inputs, '', text); } let textCopy = text; inputs.forEach(singleInput => { textCopy = replace$1(singleInput, '', textCopy).trim(); }); return textCopy; } function removeIndex(list, index) { if (arguments.length === 1) return _index => removeIndex(list, _index); if (index <= 0) return list.slice(1); if (index >= list.length - 1) return list.slice(0, list.length - 1); return [...list.slice(0, index), ...list.slice(index + 1)]; } function omit(propsToOmit, obj) { if (arguments.length === 1) return _obj => omit(propsToOmit, _obj); if (obj === null || obj === undefined) { return undefined; } const propsToOmitValue = typeof propsToOmit === 'string' ? propsToOmit.split(',') : propsToOmit; const willReturn = {}; for (const key in obj) { if (!propsToOmitValue.includes(key)) { willReturn[key] = obj[key]; } } return willReturn; } function renameProps(conditions, inputObject) { if (arguments.length === 1) { return inputObjectHolder => renameProps(conditions, inputObjectHolder); } const renamed = {}; Object.keys(conditions).forEach(condition => { if (Object.keys(inputObject).includes(condition)) { renamed[conditions[condition]] = inputObject[condition]; } }); return merge(renamed, omit(Object.keys(conditions), inputObject)); } function replaceAllFn(patterns, replacer, input) { ok(patterns, replacer, input)(Array, String, String); let text = input; patterns.forEach(singlePattern => { text = text.replace(singlePattern, replacer); }); return text; } const replaceAll = curry(replaceAllFn); function shuffle(arrayRaw) { const array = arrayRaw.concat(); let counter = array.length; while (counter > 0) { const index = Math.floor(Math.random() * counter); counter--; const temp = array[counter]; array[counter] = array[index]; array[index] = temp; } return array; } function sortBy(sortFn, list) { if (arguments.length === 1) return _list => sortBy(sortFn, _list); const clone = list.slice(); return clone.sort((a, b) => { const aSortResult = sortFn(a); const bSortResult = sortFn(b); if (aSortResult === bSortResult) return 0; return aSortResult < bSortResult ? -1 : 1; }); } function sortByPath(sortPath, list) { if (arguments.length === 1) return _list => sortByPath(sortPath, _list); return sortBy(path(sortPath), list); } function singleSort(a, b, sortPaths) { let toReturn = 0; sortPaths.forEach(singlePath => { if (toReturn !== 0) return; const aResult = path(singlePath, a); const bResult = path(singlePath, b); if ([aResult, bResult].includes(undefined)) return; if (aResult === bResult) return; toReturn = aResult > bResult ? 1 : -1; }); return toReturn; } function sortByProps(sortPaths, list) { if (arguments.length === 1) return _list => sortByProps(sortPaths, _list); const clone = list.slice(); clone.sort((a, b) => singleSort(a, b, sortPaths)); return clone; } function sortObject(predicate, obj) { if (arguments.length === 1) { return _obj => sortObject(predicate, _obj); } const keys = Object.keys(obj); const sortedKeys = sort((a, b) => predicate(a, b, obj[a], obj[b]), keys); const toReturn = {}; sortedKeys.forEach(singleKey => { toReturn[singleKey] = obj[singleKey]; }); return toReturn; } const NO_MATCH_FOUND = Symbol ? Symbol('NO_MATCH_FOUND') : undefined; const getMatchingKeyValuePair = (cases, testValue, defaultValue) => { let iterationValue; for (let index = 0; index < cases.length; index++) { iterationValue = cases[index].test(testValue); if (iterationValue !== NO_MATCH_FOUND) { return iterationValue; } } return defaultValue; }; const isEqual = (testValue, matchValue) => { const willReturn = typeof testValue === 'function' ? testValue(matchValue) : equals(testValue, matchValue); return willReturn; }; const is = (testValue, matchResult = true) => ({ key: testValue, test: matchValue => isEqual(testValue, matchValue) ? matchResult : NO_MATCH_FOUND }); class Switchem { constructor(defaultValue, cases, willMatch) { if (cases === undefined && willMatch === undefined) { this.cases = []; this.defaultValue = undefined; this.willMatch = defaultValue; } else { this.cases = cases; this.defaultValue = defaultValue; this.willMatch = willMatch; } return this; } default(defaultValue) { const holder = new Switchem(defaultValue, this.cases, this.willMatch); return holder.match(this.willMatch); } is(testValue, matchResult) { return new Switchem(this.defaultValue, [...this.cases, is(testValue, matchResult)], this.willMatch); } match(matchValue) { return getMatchingKeyValuePair(this.cases, matchValue, this.defaultValue); } } function switcher(input) { return new Switchem(input); } function takeUntil(predicate, list) { const toReturn = []; let stopFlag = false; let counter = -1; while (stopFlag === false && counter++ < list.length - 1) { if (predicate(list[counter])) { stopFlag = true; } else { toReturn.push(list[counter]); } } return toReturn; } async function tapAsyncFn(fn, input) { await fn(input); return input; } function tapAsync(fn, input) { if (arguments.length === 1) { return async _input => tapAsyncFn(fn, _input); } return new Promise((resolve, reject) => { tapAsyncFn(fn, input).then(resolve).catch(reject); }); } function throttle(fn, ms) { let wait = false; return function (...input) { if (!wait) { fn.apply(null, input); wait = true; setTimeout(() => { wait = false; }, ms); } }; } function toDecimal(number, charsAfterDecimalPoint = 2) { return Number(parseFloat(String(number)).toFixed(charsAfterDecimalPoint)); } function tryCatchAsync(fn, fallback) { return (...inputs) => new Promise(resolve => { fn(...inputs).then(resolve).catch(err => { if (!isFunction(fallback)) { return resolve(fallback); } if (!isPromise(fallback)) { return resolve(fallback(err, ...inputs)); } fallback(err, ...inputs).then(resolve).catch(resolve); }); }); } function updateObject(rules, obj) { if (arguments.length === 1) return _obj => updateObject(rules, _obj); let clone = _objectSpread2({}, obj); rules.forEach(([objectPath, newValue]) => { clone = assocPath(objectPath, newValue, clone); }); return clone; } function isFalsy$1(input) { return input === undefined || input === null || Number.isNaN(input) === true; } function defaultTo(defaultArgument, input) { if (arguments.length === 1) { return _input => defaultTo(defaultArgument, _input); } return isFalsy$1(input) ? defaultArgument : input; } function viewOrFn(fallback, lens, input) { return defaultTo(fallback, view(lens, input)); } const viewOr = curry(viewOrFn); function wait(fn) { return new Promise(resolve => { fn.then(result => resolve([result, undefined])).catch(e => resolve([undefined, e])); }); } function range(start, end) { if (arguments.length === 1) return _end => range(start, _end); if (Number.isNaN(Number(start)) || Number.isNaN(Number(end))) { throw new TypeError('Both arguments to range must be numbers'); } if (end < start) return []; const len = end - start; const willReturn = Array(len); for (let i = 0; i < len; i++) { willReturn[i] = start + i; } return willReturn; } function waitFor(condition, howLong, loops = 10) { const typeCondition = type(condition); const passPromise = typeCondition === 'Async'; const passFunction = typeCondition === 'Function'; const interval = Math.floor(howLong / loops); if (!(passPromise || passFunction)) { throw new Error('R.waitFor'); } return async (...inputs) => { for (const _ of range(0, loops)) { const resultCondition = await condition(...inputs); if (resultCondition === false) { await delay(interval); } else { return resultCondition; } } return false; }; } function xnor(x, y) { if (arguments.length === 1) { return _y => xnor(x, _y); } return Boolean(x && y || !x && !y); } function add(a, b) { if (arguments.length === 1) return _b => add(a, _b); return Number(a) + Number(b); } function adjustFn(index, replaceFn, list) { const actualIndex = index < 0 ? list.length + index : index; if (index >= list.length || actualIndex < 0) return list; const clone = list.slice(); clone[actualIndex] = replaceFn(clone[actualIndex]); return clone; } const adjust = curry(adjustFn); function allPass(predicates) { return input => { let counter = 0; while (counter < predicates.length) { if (!predicates[counter](input)) { return false; } counter++; } return true; }; } function always(x) { return () => x; } function and(a, b) { if (arguments.length === 1) return _b => and(a, _b); return a && b; } function or(a, b) { if (arguments.length === 1) return _b => or(a, _b); return a || b; } function anyPass(predicates) { return input => { let counter = 0; while (counter < predicates.length) { if (predicates[counter](input)) { return true; } counter++; } return false; }; } function append(x, input) { if (arguments.length === 1) return _input => append(x, _input); if (typeof input === 'string') return input.split('').concat(x); const clone = input.slice(); clone.push(x); return clone; } function __findHighestArity(spec, max = 0) { for (const key in spec) { if (spec.hasOwnProperty(key) === false || key === 'constructor') continue; if (typeof spec[key] === 'object') { max = Math.max(max, __findHighestArity(spec[key])); } if (typeof spec[key] === 'function') { max = Math.max(max, spec[key].length); } } return max; } function __filterUndefined() { const defined = []; let i = 0; const l = arguments.length; while (i < l) { if (typeof arguments[i] === 'undefined') break; defined[i] = arguments[i]; i++; } return defined; } function __applySpecWithArity(spec, arity, cache) { const remaining = arity - cache.length; if (remaining === 1) return x => __applySpecWithArity(spec, arity, __filterUndefined(...cache, x)); if (remaining === 2) return (x, y) => __applySpecWithArity(spec, arity, __filterUndefined(...cache, x, y)); if (remaining === 3) return (x, y, z) => __applySpecWithArity(spec, arity, __filterUndefined(...cache, x, y, z)); if (remaining === 4) return (x, y, z, a) => __applySpecWithArity(spec, arity, __filterUndefined(...cache, x, y, z, a)); if (remaining > 4) return (...args) => __applySpecWithArity(spec, arity, __filterUndefined(...cache, ...args)); if (_isArray(spec)) { const ret = []; let i = 0; const l = spec.length; for (; i < l; i++) { if (typeof spec[i] === 'object' || _isArray(spec[i])) { ret[i] = __applySpecWithArity(spec[i], arity, cache); } if (typeof spec[i] === 'function') { ret[i] = spec[i](...cache); } } return ret; } const ret = {}; for (const key in spec) { if (spec.hasOwnProperty(key) === false || key === 'constructor') continue; if (typeof spec[key] === 'object') { ret[key] = __applySpecWithArity(spec[key], arity, cache); continue; } if (typeof spec[key] === 'function') { ret[key] = spec[key](...cache); } } return ret; } function applySpec(spec, ...args) { const arity = __findHighestArity(spec); if (arity === 0) { return () => ({}); } const toReturn = __applySpecWithArity(spec, arity, args); return toReturn; } function both(f, g) { if (arguments.length === 1) return _g => both(f, _g); return (...input) => f(...input) && g(...input); } function chain(fn, list) { if (arguments.length === 1) { return _list => chain(fn, _list); } return [].concat(...list.map(fn)); } function clampFn(min, max, input) { if (min > max) { throw new Error('min must not be greater than max in clamp(min, max, value)'); } if (input >= min && input <= max) return input; if (input > max) return max; if (input < min) return min; } const clamp = curry(clampFn); function clone(input) { const out = _isArray(input) ? Array(input.length) : {}; if (input && input.getTime) return new Date(input.getTime()); for (const key in input) { const v = input[key]; out[key] = typeof v === 'object' && v !== null ? v.getTime ? new Date(v.getTime()) : clone(v) : v; } return out; } funct