export function toSetMethodName(key: string) { return 'set' + key[0].toUpperCase() + key.slice(1) } export const merge = (target: any, source: any) => { // Iterate through `source` properties and if an `Object` set property to merge of `target` and `source` properties for (const key of Object.keys(source)) { if (source[key] instanceof Object) Object.assign(source[key], merge(target[key], source[key])) } // Join `target` and modified `source` Object.assign(target || {}, source) return target } const HTML_TAGS = 'html,body,base,head,link,meta,style,title,address,article,aside,footer,' + 'header,hgroup,h1,h2,h3,h4,h5,h6,nav,section,div,dd,dl,dt,figcaption,' + 'figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,' + 'data,dfn,em,i,kbd,mark,q,rp,rt,ruby,s,samp,small,span,strong,sub,sup,' + 'time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,' + 'canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,' + 'th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,' + 'option,output,progress,select,textarea,details,dialog,menu,' + 'summary,template,blockquote,iframe,tfoot' export const isHTMLTag = /*#__PURE__*/ makeMap(HTML_TAGS) export function kebabToCamel(str: string) { return str.replace(/-([a-z])/g, (_, c) => c.toUpperCase()) } export function makeMap(str: string, expectsLowerCase?: boolean): (key: string) => boolean { const map: Record = Object.create(null) const list: Array = str.split(',') for (let i = 0; i < list.length; i++) { map[list[i]] = true } return expectsLowerCase ? val => !!map[val.toLowerCase()] : val => !!map[val] } export const uniqueBy = (array: T[], iteratee: (value: T) => K): T[] => { const seen = new Set() const result: T[] = [] for (const item of array) { const identifier = iteratee(item) if (!seen.has(identifier)) { seen.add(identifier) result.push(item) } } return result } export const get = (obj: any, path: string | string[]): T | undefined => { if (!path) return undefined; // Regex explained: https://regexr.com/58j0k const pathArray = Array.isArray(path) ? path : path.match(/([^[.\]])+/g); return pathArray?.reduce((prevObj, key) => prevObj && prevObj[key], obj); }; export const set = (obj: any, path: string | string[], value: any): void => { // Regex explained: https://regexr.com/58j0k const pathArray = Array.isArray(path) ? path : path.match(/([^[.\]])+/g); if (pathArray) pathArray.reduce((acc, key, i) => { if (acc[key] === undefined) acc[key] = {}; if (i === pathArray.length - 1) acc[key] = value; return acc[key]; }, obj); }; export function deepEqual(a: any, b: any): boolean { // If both are primitives, return true if they are equal if (a === b) return true; // If either of them is null or not an object, return false if (a === null || typeof a !== "object" || b === null || typeof b !== "object") return false; // Get the keys of both objects const keysA = Object.keys(a), keysB = Object.keys(b); // If they have different number of keys, they are not equal if (keysA.length !== keysB.length) return false; // Check each key in A to see if it exists in B and its value is the same in both for (const key of keysA) { if (!keysB.includes(key) || !deepEqual(a[key], b[key])) return false; } return true; } export function deepArrayEqual(arr1: any[], arr2: any[]): boolean { // If they're not both arrays, return false if (!Array.isArray(arr1) || !Array.isArray(arr2)) return false; // If they don't have the same length, they're not equal if (arr1.length !== arr2.length) return false; // Check each element of arr1 against the corresponding element of arr2 for (let i = 0; i < arr1.length; i++) { if (!deepEqual(arr1[i], arr2[i])) return false; } return true; }