Last active
February 13, 2020 23:14
-
-
Save samueleaton/aa96663f536bf3942630 to your computer and use it in GitHub Desktop.
Some basic functionality you would find with lodash
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
/* eslint-disable id-blacklist */ | |
/* eslint-disable id-length */ | |
/* eslint-disable no-param-reassign */ | |
/* eslint-disable no-implicit-coercion */ | |
/* eslint-disable no-undefined */ | |
/* eslint-disable no-empty-function */ | |
/* eslint-disable semi */ | |
/* eslint-disable quotes */ | |
/* eslint-disable no-eq-nullg */ | |
/* depends on: forEach, forOwn */ | |
export function assign(...args) { | |
forEach(args, (obj, i) => { | |
if (i === 0) | |
return | |
forOwn(obj, (val, key) => { | |
args[0][key] = val | |
}) | |
}) | |
return args[0] | |
} | |
export function reduce(list, func, accum) { | |
if (!list || !list.length) | |
return accum; | |
if (typeof accum === "undefined") { | |
if (list.length <= 1) | |
return list[0]; | |
else { | |
const newAccum = list[0]; | |
return reduce(list.slice(1), func, newAccum); | |
} | |
} | |
else { | |
const n = list[0]; | |
const newAccum = func(accum, n); | |
return reduce(list.slice(1), func, newAccum); | |
} | |
} | |
export function toArray(obj) { | |
const arr = []; | |
for (let i = 0, ii = obj.length; i < ii; i++) | |
arr.push(obj[i]); | |
return arr; | |
} | |
export function toUpper(str) { | |
if (!str || typeof str !== "string") | |
return ""; | |
if (str && typeof str.toUpperCase === "function") | |
return str.toUpperCase(); | |
else | |
return str; | |
} | |
export function upperFirst(str) { | |
if (!str || typeof str !== "string") | |
return ""; | |
return str.charAt(0).toUpperCase() + str.slice(1); | |
} | |
export function toLower(str) { | |
if (!str || typeof str !== "string") | |
return ""; | |
if (str && typeof str.toLowerCase === "function") | |
return str.toLowerCase(); | |
else | |
return str; | |
} | |
export function snakeCase(str) { | |
if (!str || typeof str !== "string") | |
return ""; | |
const strArr = []; | |
for (let i = 0, ii = str.length; i < ii; i++) { | |
const char = str[i]; | |
if (/^\w$/.test(char)) { | |
if (i !== 0 && !(/^[A-Z]$/).test(str[i - 1]) && (/^[A-Z]$/).test(char)) | |
strArr.push("_"); | |
strArr.push(char.toLowerCase()); | |
} | |
} | |
return strArr.join("").replace(/_+/g, "_"); | |
} | |
/* depends on: upperFirst */ | |
export function startCase(str) { | |
if (!str || typeof str !== "string") | |
return ""; | |
const string = str.replace(/(_|-)/g, " "); | |
const strArr = []; | |
for (let i = 0, ii = string.length; i < ii; i++) { | |
const char = string[i]; | |
if (/^(\w| )$/.test(char)) { | |
if (i !== 0 && !(/^[A-Z]$/).test(string[i - 1]) && (/^[A-Z]$/).test(char)) | |
strArr.push(" "); | |
if (strArr[strArr.length - 1] === " ") | |
strArr.push(char.toUpperCase()); | |
else | |
strArr.push(char); | |
} | |
} | |
return upperFirst(strArr.join("").replace(/ +/g, " ").trim()); | |
} | |
export function escape(str) { | |
if (!str || typeof str !== "string") | |
return ""; | |
return str.replace(/&/g, "&") | |
.replace(/"/g, """) | |
.replace(/'/g, "'") | |
.replace(/</g, "<") | |
.replace(/>/g, ">"); | |
} | |
export function unescape(str) { | |
if (!str || typeof str !== "string") | |
return ""; | |
return str.replace(/&/g, "&") | |
.replace(/"/g, "\"") | |
.replace(/'/g, "'") | |
.replace(/</g, "<") | |
.replace(/>/g, ">"); | |
} | |
export function truncate(str, length = 30, sub = "...") { | |
if (!str || typeof str !== "string") | |
return ""; | |
const size = parseInt(length) || 30; | |
if (str.length > size) { | |
const truncated = str.slice(0, size); | |
if (sub.length) | |
return truncated.slice(0, 0 - sub.length) + sub; | |
else | |
return truncated; | |
} | |
else | |
return str; | |
} | |
export function split(string, dilimiter) { | |
if (string && string.split) | |
return string.split(dilimiter); | |
else | |
return []; | |
} | |
export function replace(arg, regex, string = "") { | |
if (typeof string !== "string") | |
return console.error("3rd params must be strings"); | |
if (arg && arg.replace) | |
return arg.replace(regex, string); | |
else | |
return arg; | |
} | |
export function trim(string) { | |
if (!string || typeof string !== "string") | |
return ""; | |
if (string && string.trim) | |
return string.trim(); | |
else | |
return string; | |
} | |
// compresses consecutuve spaces into a single space | |
export function compress(string) { | |
if (!string || typeof string !== "string") { | |
return ""; | |
} | |
return string.replace(/\s+/g, " ").trim(); | |
} | |
export function isUndefined(arg) { | |
return typeof arg === "undefined"; | |
} | |
export function isString(arg) { | |
return typeof arg === "string"; | |
} | |
export function isBoolean(arg) { | |
return typeof arg === "boolean" || arg === true || arg === false || false; | |
} | |
export function isFunction(func) { | |
return typeof func === "function"; | |
} | |
export function isObject(value) { | |
const type = typeof value; | |
return !!value && (type === "object" || type === "function"); | |
} | |
export function isEmpty(value) { | |
if (value === null || typeof value === "undefined") | |
return true | |
if (typeof value.length === "number") | |
return !value.length | |
for (const key in value) { | |
if (hasOwnProperty.call(value, key)) | |
return false | |
} | |
return true | |
} | |
export function isNil(value) { | |
if (value) { | |
return false | |
} | |
if (typeof value === "undefined" || value === null) { | |
return true | |
} | |
return false | |
} | |
export function includes(arg, elm) { | |
if (!arg || !arg.indexOf) | |
return false; | |
else if (arg.indexOf(elm) > -1) | |
return true; | |
else | |
return false; | |
} | |
export function getProto(arg) { | |
return Object.getPrototypeOf(Object(arg)); | |
} | |
/* depends on: forEach, isArray */ | |
export function flatten(arr) { | |
const result = []; | |
forEach(arr, elm => { | |
if (isArray(elm)) | |
forEach(elm, elm2 => result.push(elm2)); | |
else | |
result.push(elm); | |
}); | |
return result; | |
} | |
export function forOwn(arg, func) { | |
for (const key in arg) { | |
if (arg.hasOwnProperty(key)) { | |
if (typeof func === "function") | |
func(arg[key], key); | |
} | |
} | |
} | |
export function invert(arg, func) { | |
const newObj = {}; | |
for (const key in arg) { | |
if (arg.hasOwnProperty(key)) | |
newObj[arg[key]] = key; | |
} | |
return newObj; | |
} | |
/* depends on: forEach, get, set */ | |
export function pick(obj, paths) { | |
const result = {}; | |
forEach(paths, path => { | |
const value = get(obj, path) | |
if (typeof value !== "undefined") | |
set(result, path, value) | |
}) | |
return result; | |
} | |
export function pickBy(obj, func) { | |
const result = {}; | |
for (const key in obj) { | |
if (obj.hasOwnProperty(key)) { | |
if (typeof func === "function") { | |
if (func(obj[key], key)) | |
result[key] = obj[key]; | |
} | |
else if (obj[key]) | |
result[key] = obj[key]; | |
} | |
} | |
return result; | |
} | |
/* depends on: isArray, forEach */ | |
export function keyBy(arr, func = element => element) { | |
if (!isArray(arr)) | |
return console.error("keyBy takes an array"); | |
if (typeof func !== "function") | |
return {}; | |
const result = {}; | |
forEach(arr, elm => { | |
result[func(elm)] = elm; | |
}); | |
return result; | |
} | |
/* depends on: isArray, getProto */ | |
export function isPlainObject(obj) { | |
if (!obj) | |
return false; | |
if (typeof obj !== "object") | |
return false; | |
if (isArray(obj)) | |
return false; | |
const proto = getProto(obj); | |
if (proto === null) | |
return true; | |
const cnstcr = Object.prototype.hasOwnProperty.call(proto, "constructor") && proto.constructor; | |
const funcToString = Function.prototype.toString; | |
return ( | |
typeof cnstcr === "function" && | |
cnstcr instanceof cnstcr && | |
funcToString.call(cnstcr) === funcToString.call(Object)); | |
} | |
export function keys(obj) { | |
const arr = []; | |
for (const key in obj) { | |
if (hasOwnProperty.call(obj, key) && key !== "constructor") | |
arr.push(key); | |
} | |
return arr; | |
} | |
export function isArray(obj) { | |
if (!obj) | |
return false; | |
return ( | |
typeof obj === "object" && | |
( | |
(Array.isArray && Array.isArray(obj)) || | |
obj.constructor === Array || | |
obj instanceof Array | |
) | |
); | |
} | |
export function forEach(list, func) { | |
if (!list || !list.length) | |
return null; | |
if (typeof func !== "function") | |
return console.error("2nd param to forEach must be function"); | |
for (let i = 0, ii = list.length; i < ii; i++) | |
func(list[i], i); | |
} | |
export function forEachRight(list, func) { | |
if (!list || !list.length) | |
return null; | |
if (typeof func !== "function") | |
return console.error("2nd param to forEach must be function"); | |
for (let i = list.length - 1, ii = 0; i >= ii; i--) | |
func(list[i], i); | |
} | |
export function find(list, func) { | |
if (!list || !list.length || typeof func !== "function") | |
return null; | |
for (let i = 0, ii = list.length; i < ii; i++) { | |
if (func(list[i], i)) | |
return list[i]; | |
} | |
return null; | |
} | |
export function findFromIndex(list, startIndex, func) { | |
if (!list || !list.length || typeof func !== "function") | |
return null; | |
if (startIndex >= list.length) | |
return null; | |
for (let i = startIndex, ii = list.length; i < ii; i++) { | |
if (func(list[i], i)) | |
return list[i]; | |
} | |
return null; | |
} | |
export function findIndex(list, func) { | |
if (!list || !list.length || typeof func !== "function") | |
return null; | |
for (let i = 0, ii = list.length; i < ii; i++) { | |
if (func(list[i], i)) | |
return i; | |
} | |
return null; | |
} | |
export function findIndexFromIndex(list, startIndex, func) { | |
if (!list || !list.length || typeof func !== "function") | |
return null; | |
if (startIndex >= list.length) | |
return null; | |
for (let i = startIndex, ii = list.length; i < ii; i++) { | |
if (func(list[i], i)) | |
return i; | |
} | |
return null; | |
} | |
export function some(list, func) { | |
if (!list || !list.length || typeof func !== "function") | |
return false; | |
for (let i = 0, ii = list.length; i < ii; i++) { | |
if (func(list[i], i)) | |
return true; | |
} | |
return false; | |
} | |
export function every(list, func) { | |
if (!list || !list.length || typeof func !== "function") | |
return true; | |
for (let i = 0, ii = list.length; i < ii; i++) { | |
if (!func(list[i], i)) | |
return false; | |
} | |
return true; | |
} | |
export function map(list, func) { | |
if (!list || !list.length) | |
return []; | |
if (typeof func !== "function") | |
func = x => x; | |
const arr = []; | |
for (let i = 0, ii = list.length; i < ii; i++) | |
arr.push(func(list[i], i)); | |
return arr; | |
} | |
export function mapValues(obj, func) { | |
const result = {}; | |
for (const key in obj) { | |
if (obj.hasOwnProperty(key)) { | |
if (typeof func === "function") { | |
result[key] = func(obj[key], key); | |
} | |
else | |
result[key] = obj[key]; | |
} | |
} | |
return result; | |
} | |
export function compactMap(list, func) { | |
if (!list || !list.length) | |
return []; | |
if (typeof func !== "function") | |
func = x => x; | |
const arr = []; | |
for (let i = 0, ii = list.length; i < ii; i++) { | |
const result = func(list[i], i) | |
if (result !== null && typeof result !== "undefined") | |
arr.push(result); | |
} | |
return arr; | |
} | |
export function filter(list, func) { | |
if (!list || !list.length) | |
return []; | |
if (typeof func !== "function") | |
return []; | |
const arr = []; | |
for (let i = 0, ii = list.length; i < ii; i++) { | |
if (func(list[i])) | |
arr.push(list[i]); | |
} | |
return arr; | |
} | |
/* depends on: forEachRight */ | |
/* mutates array */ | |
export function remove(list, func) { | |
if (!list || !list.length) | |
return list | |
forEachRight(list, (elm, i) => { | |
if (typeof func !== "function") { | |
if (elm === func) { | |
list.splice(i, 1) | |
} | |
} | |
else if (func(elm, i)) { | |
list.splice(i, 1) | |
} | |
}) | |
return list | |
} | |
export function compact(list) { | |
if (!list || !list.length) | |
return []; | |
const arr = []; | |
for (let i = 0, ii = list.length; i < ii; i++) { | |
if (list[i]) | |
arr.push(list[i]); | |
} | |
return arr; | |
} | |
/* depends on: isArray, split */ | |
export function has(obj, path) { | |
if (typeof obj === "undefined" || obj === null) { | |
return false; | |
} | |
if (typeof path === "undefined" || path === null || path === "") { | |
return true; | |
} | |
let pathArr; | |
if (isArray(path)) { | |
pathArr = path | |
} | |
else if (typeof path === "number") { | |
pathArr = [ path ] | |
} | |
else { | |
pathArr = split(path, ".") | |
} | |
if (!pathArr.length) { | |
return true; | |
} | |
if (obj.hasOwnProperty(pathArr[0])) { | |
const sliced = pathArr.slice(1); | |
if (sliced.length === 0) { | |
return true; | |
} | |
return has(obj[pathArr[0]], sliced); | |
} | |
return false; | |
} | |
/* depends on: isArray, split */ | |
export function get(obj, path, defaultVal = null) { | |
if (typeof obj === "undefined" || obj === null) | |
return defaultVal; | |
if (typeof path === "undefined" || path === null || path === "") | |
return defaultVal || obj; | |
const pathArr = isArray(path) ? path : split(path, "."); | |
if (!pathArr.length) | |
return defaultVal || obj; | |
if (obj[pathArr[0]]) { | |
const sliced = pathArr.slice(1); | |
if (sliced.length === 0) | |
return obj[pathArr[0]]; | |
return get(obj[pathArr[0]], sliced); | |
} | |
return defaultVal; | |
} | |
/* depends on: isArray, split */ | |
export function set(obj, path, value) { | |
if (typeof obj === "undefined" || obj === null) | |
return null; | |
if (typeof path === "undefined" || path === null || path === "") | |
return obj; | |
const uIntRegex = /^(?:0|[1-9]\d*)$/ | |
const pathArr = isArray(path) ? path : split(path, "."); | |
for (let i = 0, object = obj; i < pathArr.length; i++) { | |
if (typeof object[pathArr[i]] !== "object") { | |
if (i >= pathArr.length - 1) | |
object[pathArr[i]] = value | |
else if (typeof pathArr[i + 1] === "number" || uIntRegex.test(pathArr[i + 1])) | |
object[pathArr[i]] = [] | |
else | |
object[pathArr[i]] = {} | |
} | |
else if (i >= pathArr.length - 1) | |
object[pathArr[i]] = value | |
object = object[pathArr[i]] | |
} | |
return obj; | |
} | |
/* depends on: includes */ | |
export function removeDuplicates(arr) { | |
const newArr = []; | |
for (let i = 0, ii = arr.length; i < ii; i++) { | |
if (!includes(newArr, arr[i])) | |
newArr.push(arr[i]); | |
} | |
return newArr; | |
} | |
/* depends on: isArray */ | |
export function chunk(arr, size, chunks = []) { | |
if (!isArray(arr) || !arr.length) | |
return chunks; | |
const chunked = arr.splice(0, size); | |
chunks.push(chunked); | |
return chunk(arr, size, chunks); | |
} | |
/* depends on: isArray */ | |
export function chunkRight(arr, size, chunks = []) { | |
if (!isArray(arr) || !arr.length) | |
return chunks; | |
const chunked = arr.splice(0 - size); | |
chunks.unshift(chunked); | |
return chunkRight(arr, size, chunks); | |
} | |
/* delimits a string from the left side */ | |
export function delimit(obj, count, delimiter = "") { | |
return map(chunk(obj.split(""), count), arr => arr.join("")).join(delimiter); | |
} | |
/* delimits a string from the right side */ | |
export function delimitRight(obj, count, delimiter = "") { | |
return map(chunkRight(obj.split(""), count), arr => arr.join("")).join(delimiter); | |
} | |
/* depends on: flatten */ | |
export function concat(arr, ...args) { | |
const newArr = []; | |
for (let i = 0, ii = arr.length; i < ii; i++) | |
newArr.push(arr[i]); | |
for (let i = 0, ii = args.length; i < ii; i++) | |
newArr.push(args[i]); | |
return flatten(newArr); | |
} | |
export function debounce(func, debounceTime, runImmediately = false) { | |
if (typeof func !== "function") | |
return console.error("first arg must be a function"); | |
const time = parseInt(debounceTime); | |
if (isNaN(time) || time !== debounceTime) | |
return console.error("debounce time must be an integer (in milliseconds)"); | |
if (time < 0) | |
return console.error("time must be a positive integer"); | |
let timeout = null; | |
return function debounced(...args) { | |
if (timeout) { | |
window.clearTimeout(timeout); | |
} | |
else if (runImmediately) { | |
func(...args) | |
} | |
timeout = setTimeout(() => { | |
func(...args); | |
timeout = null; | |
}, time); | |
} | |
} | |
export function chunkBy(list, keys) { | |
if (!list || !list.length) return []; | |
if (!keys || !keys.length) return list; | |
const chunks = []; | |
for (let i = 0; i < list.length; i++) { | |
const item = list[i]; | |
const lastChunk = chunks[chunks.length - 1]; | |
const lastItemOfLastChunk = lastChunk && lastChunk[lastChunk.length - 1]; | |
if (lastItemOfLastChunk && every(keys, k => lastItemOfLastChunk[k] === item[k])) { | |
lastChunk.push(item); | |
} else { | |
chunks.push([list[i]]); | |
} | |
} | |
return chunks; | |
} | |
/* depends on: isArray, forEach */ | |
export function groupBy(arr, func = element => [element]) { | |
if (!isArray(arr)) return console.error("groupBy takes an array"); | |
if (typeof func !== "function") return {}; | |
const result = {}; | |
forEach(arr, elm => { | |
const key = func(elm); | |
if (!result[key]) { | |
result[key] = []; | |
} | |
result[key].push(elm); | |
}); | |
return result; | |
} | |
/* | |
usage: rand(length, optionalExtraChars) | |
example: rand() | |
example: rand(36) | |
example: rand(24, "$@_*") | |
*/ | |
export const rand = (() => { | |
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" | |
return (size = 12, optChars) => { | |
const srcStr = chars + (optChars || "") | |
let randomChars = ""; | |
for (let i = 0; i < size; i++) | |
randomChars += srcStr.charAt(Math.floor(Math.random() * srcStr.length)); | |
return randomChars; | |
} | |
})() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment