/** * Copied from chakra-ui, license MIT * Accessed 2021-12-26, commit March 15th, 2021 * See also: https://github.com/chakra-ui/chakra-ui/blob/4db1f22/packages/utils/src/object.ts */ import type { Dict, Omit } from "./types"; export { default as mergeWith } from "lodash.mergewith"; export function omit(object: T, keys: K[]) { const result: Dict = {}; Object.keys(object).forEach((key) => { if (keys.includes(key as K)) return; result[key] = object[key]; }); return result as Omit; } export function pick(object: T, keys: K[]) { const result = {} as { [P in K]: T[P] }; keys.forEach((key) => { if (key in object) { result[key] = object[key]; } }); return result; } export function split(object: T, keys: K[]) { const picked: Dict = {}; const omitted: Dict = {}; Object.keys(object).forEach((key) => { if (keys.includes(key as T[K])) { picked[key] = object[key]; } else { omitted[key] = object[key]; } }); return [picked, omitted] as [{ [P in K]: T[P] }, Omit]; } /** * Get value from a deeply nested object using a string path. * Memoizes the value. * @param obj - the object * @param path - the string path * @param def - the fallback value */ export function get( obj: object, path: string | number, fallback?: any, index?: number, ) { const key = typeof path === "string" ? path.split(".") : [path]; for (index = 0; index < key.length; index += 1) { if (!obj) break; // @ts-expect-error obj = obj[key[index]]; } return obj === undefined ? fallback : obj; } type Get = ( obj: Readonly, path: string | number, fallback?: any, index?: number, ) => any; export const memoize = (fn: Get) => { const cache = new WeakMap(); const memoizedFn: Get = (obj, path, fallback, index) => { if (typeof obj === "undefined") { return fn(obj, path, fallback); } if (!cache.has(obj)) { cache.set(obj, new Map()); } const map = cache.get(obj); if (map.has(path)) { return map.get(path); } const value = fn(obj, path, fallback, index); map.set(path, value); return value; }; return memoizedFn; }; export const memoizedGet = memoize(get); /** * Get value from deeply nested object, based on path * It returns the path value if not found in object * * @param path - the string path or value * @param scale - the string path or value */ export function getWithDefault(path: any, scale: any) { return memoizedGet(scale, path, path); } type FilterFn = (value: any, key: string, object: T) => boolean; /** * Returns the items of an object that meet the condition specified in a callback function. * * @param object the object to loop through * @param fn The filter function */ export function objectFilter(object: T, fn: FilterFn) { const result: Dict = {}; Object.keys(object).forEach((key) => { const value = object[key]; const shouldPass = fn(value, key, object); if (shouldPass) { result[key] = value; } }); return result; } export const filterUndefined = (object: Dict) => objectFilter(object, (val) => val !== null && val !== undefined); export const objectKeys = (obj: T) => Object.keys(obj) as unknown as (keyof T)[]; /** * Object.entries polyfill for Nodev10 compatibility */ export const fromEntries = (entries: [string, any][]) => entries.reduce((carry, [key, value]) => { // @ts-expect-error carry[key] = value; return carry; }, {}) as T; /** * Get the CSS variable ref stored in the theme */ export const getCSSVar = (theme: Dict, scale: string, value: any) => theme.__cssMap[`${scale}.${value}`]?.varRef ?? value;