Created
September 8, 2020 14:09
-
-
Save saaage/142adc7fddb4769e734208461632141e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import get from 'lodash.get' | |
import isEqual from 'lodash.isequal' | |
import v from 'voca' | |
export const titleCase = s => v.titleCase(s, ["'", /[A-Z]/]) | |
export const isArray = val => Array.isArray(val) | |
// returns collection that is unique on the provided key | |
// eg: uniqueOn([{ id: 1, name: "stefan"}, { id: 1, name: "john" }], "id") => [{ id: 1, name "stefan"}] | |
export const uniqueOn = (coll, path) => { | |
return coll.reduce((newColl, item) => { | |
return newColl.find(i => isEqual(get(i, path), get(item, path))) | |
? newColl | |
: [...newColl, item] | |
}, []) | |
} | |
// takes a collection of objects and returns a string containing the error value of each | |
export const combineMessages = coll => { | |
const clone = Array.from(coll).map(obj => get(obj, 'message', '')) | |
return clone.join(' - ') | |
} | |
export const asyncForEach = async (array, callback) => { | |
const errors = [] | |
const resolutions = [] | |
for (let index = 0; index < array.length; index++) { | |
await callback(array[index]) | |
.then(resolution => resolutions.push(resolution)) | |
.catch(err => errors.push(err)) | |
} | |
if (errors.length > 0) return Promise.reject(errors) | |
return Promise.resolve(resolutions) | |
} | |
export const isObject = arg => | |
Object.prototype.toString.call(arg) === '[object Object]' | |
// is a thing null/undefined? | |
export const isNil = arg => arg === null || arg === undefined | |
// is a thing NOT null and NOT undefined | |
export const notNil = arg => !isNil(arg) | |
export const isEmptyString = arg => arg === '' | |
export const renderFallback = (arg, fallback) => { | |
if (isNil(arg) || isEmptyString(arg)) { | |
return fallback | |
} else return arg | |
} | |
// returns a new object containing only the keys selected | |
export const selectKeys = (obj, keys) => { | |
const map = {} | |
keys.forEach(k => (map[k] = obj[k])) | |
return map | |
} | |
// returns a new object with keys removed | |
export const removeKeys = (obj, keys) => { | |
const clone = { ...obj } | |
keys.forEach(k => delete clone[k]) | |
return clone | |
} | |
// if arg is null or undefined, returns value | |
export const ifNil = (arg, fallback) => { | |
if (isNil(arg)) { | |
return fallback | |
} else return arg | |
} | |
export const ifNotNil = (arg, fallback) => { | |
if (notNil(arg)) { | |
return fallback | |
} else return arg | |
} | |
// mock some fn that takes a specific amount of time | |
export const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)) | |
// does every member of a collection satisfy the given predicate | |
export const allTrue = (pred, coll) => { | |
const failure = coll.find(m => pred(m) === false) | |
return isNil(failure) | |
} | |
// does the collection contain the value? (using f to derive comparison value as it iterates over collection) | |
// if derive fn is not provided, checks collection for value itself | |
export const contains = (coll, value, derive) => { | |
if (derive) { | |
let result = false | |
coll.forEach(i => { | |
if (derive(i) === value) result = true | |
}) | |
return result | |
} | |
return coll.indexOf(value) > -1 ? true : false | |
} | |
// takes a key value pair and returns true if value is an empty string | |
export const objectValueIsEmptyString = (k, v) => v === '' | |
// remove all members of an enumerable object where fn(i) returns true (where i is an iterable value of coll) | |
export const remove = (obj, fn) => { | |
if (Array.isArray(obj)) { | |
const clone = Array.from(obj) | |
return clone.filter(m => fn(m) === false) | |
} | |
if (isObject(obj)) { | |
const clone = { ...obj } | |
for (const key in clone) { | |
if (fn(key, clone[key]) === true) delete clone[key] | |
} | |
return clone | |
} else return obj | |
} | |
// removes the first instance of value from the collection | |
export const removeValue = (coll, val) => { | |
const result = Array.from(coll) | |
const index = result.indexOf(val) | |
if (index !== -1) result.splice(index, 1) | |
return result | |
} | |
// mutates obj[key] using fn and returns obj | |
export const update = (obj, key, fn) => { | |
obj[key] = fn(obj[key]) | |
return obj | |
} | |
// mutates obj[key] using fn and returns obj | |
export const updateAsync = async (obj, key, fn) => { | |
try { | |
obj[key] = fn(obj[key]) | |
return obj | |
} catch (err) { | |
throw new Error(err) | |
} | |
} | |
export const compareNums = (a, b) => { | |
if (isNaN(parseInt(a, 10)) || isNaN(parseInt(b, 10))) | |
throw new Error( | |
'compareNums called with one or more non-parseable number values' | |
) | |
const A = parseInt(a, 10) | |
const B = parseInt(b, 10) | |
if (A < B) return -1 | |
if (A > B) return 1 | |
return 0 | |
} | |
// compares two strings returns a value to be passed to Array.sort() | |
export const compareStrings = (a, b) => { | |
if (typeof a !== 'string' || typeof b !== 'string') | |
throw new Error('compareStrings called with one or more non-string values') | |
if (a.toLowerCase() < b.toLowerCase()) return -1 | |
if (a.toLowerCase() > b.toLowerCase()) return 1 | |
return 0 | |
} | |
// compares two objects using their value at `key`, returns a value to be passed to Array.sort() | |
export const compareUsingKey = (a, b, key) => { | |
if (typeof a[key] === 'string' && typeof b[key] === 'string') { | |
if (get(a, key).toLowerCase() < get(b, key).toLowerCase()) return -1 | |
if (get(a, key).toLowerCase() > get(b, key).toLowerCase()) return 1 | |
return 0 | |
} | |
if (get(a, key) < get(b, key)) return -1 | |
if (get(a, key) > get(b, key)) return 1 | |
return 0 | |
} | |
// if string, array, or object is empty returns true. if arg is null/undefined, returns true. | |
export const isEmpty = arg => { | |
if (isNil(arg)) return true | |
if (typeof arg === 'object' || typeof arg === 'string') | |
return Object.entries(arg).length === 0 | |
else return false | |
} | |
export const some = v => !isEmpty(v) | |
// if arg is empty, returns fallback, otherwise returns arg | |
export const ifEmpty = (arg, fallback) => { | |
if (isEmpty(arg)) return fallback | |
else return arg | |
} | |
// takes an object, location, value x - returns new object with value inserted at location | |
export const assoc = (obj, location, x) => { | |
let clone | |
if (isArray(obj)) { | |
clone = Array.from(obj) | |
return clone | |
} else if (isObject(obj)) { | |
clone = { ...obj } | |
clone[location] = x | |
return clone | |
} else | |
return new Error( | |
`argument passed to assoc should be an array or object. received ${typeof obj}: ${obj}` | |
) | |
} | |
export const keyOn = (coll, path) => { | |
const newObj = {} | |
coll.forEach(i => newObj[get(i, path)] = i) | |
return newObj | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment