UNPKG

datum-merge

Version:

Simplified diff and merging for deeply nested objects

109 lines (97 loc) 3.02 kB
import { cloneDeep, get } from "lodash-es"; import equal from 'fast-deep-equal'; export function getObjectKeys( obj: any, excludeKeys?: string[], includeKeys?: string[], ): string[] { if (!obj) { return []; } let sourceKeys = Object.keys(obj); if (includeKeys && !!includeKeys.length) { includeKeys.filter((k) => !sourceKeys.includes(k)) .forEach((k) => sourceKeys.push(k)); //no dupes } if (excludeKeys && !!excludeKeys.length) { sourceKeys = sourceKeys.filter((k) => !excludeKeys.includes(k)); } return sourceKeys; }; export function createValueKeys<T>( keys: string[], value: T, ): { [key: string]: T } { return Object.fromEntries(keys.map((k) => [k, value])); } export function deepEquals(lhs: any, rhs: any): boolean { return equal(lhs, rhs); } export function deepEqualsPath(lhs: any, rhs: any, atPath: string): boolean { return equal(get(lhs, atPath), get(rhs, atPath)); } export function deepClone<T = any>(val: T): T { return cloneDeep(val); } export function toUniqueArray<T>(arr: T[]): T[] { return [...new Set<T>(arr)]; } export function areArraysEqual<T>( arr1: T[] | undefined, arr2: T[] | undefined, ): boolean { if (arr1 == null && arr2 == null) return true; if (arr1 == null || arr2 == null) return false; if (arr1.length !== arr2.length) return false; for (let i = 0; i < arr1.length; i++) { if (arr1[i] !== arr2[i]) { return false; } } return true; } //----------------------------------------------------------------------------- export function createGlobRegex( search: string ): RegExp { const pattern = search.replace(/\*/g, ".+"); //pattern = pattern.replace(/\?/g, "."); return new RegExp(`^${pattern}$`); } export function getGlobKeys( obj: any, includePats: string[] = ["*"], //globs or labels excludeKeys?: string[], //labels only ): string[] { const includeKeys: string[] = []; if (!obj || !includePats?.length) { return includeKeys; } const labels: string[] = getObjectKeys(obj, excludeKeys); if (!labels || !labels.length) { return includeKeys; } const globPats = includePats.filter((s) => s.includes("*")) .map((g) => createGlobRegex(g)); for (const label of labels) { if (includePats.includes(label)) { includeKeys.push(label); } else if (globPats.findIndex((r) => r.test(label)) >= 0) { includeKeys.push(label); } } return includeKeys; } export function selectObjKeys<T extends object>( obj: T, includeKeys: string[], ): Partial<T> { if (!includeKeys?.length) return { ...obj }; return Object.fromEntries(Object.entries(obj) .filter(([k, _]) => includeKeys.includes(k)) ) as Partial<T>; }