Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | 8x 8x 8x 69x 146x 17x 2x 15x 15x 50x 2x 129x 15x 27x 2x 140x 69x 79x 17x 17x 69x 69x 2x 2x 67x 17x 62x 5x 57x 22x 35x 8x 5x 5x 5x 5x 5x 8x 7x 7x 7x 7x 7x | import { isDefined, isArray, isObject } from './guards'; import { uniq } from './uniq'; import { clone } from './clone'; import { DeepPartial, DeepPartialObject } from './types'; function isCyclic(object: unknown) { const seenObjects = new WeakMap(); // use to keep track of which objects have been seen. function detectCycle(obj: unknown) { // If 'obj' is an actual object (i.e., has the form of '{}'), check // if it's been seen already. if ( isObject(obj) && Object.prototype.toString.call(obj) == '[object Object]' ) { if (seenObjects.has(obj)) { return true; } // If 'obj' hasn't been seen, add it to 'seenObjects'. // Since 'obj' is used as a key, the value of 'seenObjects[obj]' // is irrelevant and can be set as literally anything you want. I // just went with 'undefined'. seenObjects.set(obj, undefined); // Recurse through the object, looking for more circular references. for (var key in obj) { if (detectCycle(obj[key])) { return true; } } // If 'obj' is an array, check if any of it's elements are // an object that has been seen already. } else if (Array.isArray(obj)) { for (var i in obj) { if (detectCycle(obj[i])) { return true; } } } return false; } return detectCycle(object); } /** * Merging @param a and @param b recursively @param a is most important */ function recursiveMerge(a: unknown, b: unknown): unknown { if (isObject(a) && isObject(b)) { const output = { ...a }; const keys = uniq([...Object.keys(a), ...Object.keys(b)]); for (const k of keys) { // If object cyclic I will not try to merge objects if (isCyclic(a[k])) { output[k] = a[k]; continue; } output[k] = recursiveMerge(a[k], b[k]); } return output; } if (isArray(a) && isArray(b)) { // This step will nicely merge primitive values but will leave objects as duplicates return uniq(a.concat(b)); } // If we here we know that a is primitive value if it's defined we chose a over b // Unless this value is empty string if (isDefined(a)) { return a; } return b; } /** * Merging object from left to right * * @param target - value be preserved if possible. * @param sources - value be preserved if possible. * @description * Consider following * * - `array + obj = array` * - `obj + array = obj` * - `obj + obj = obj` (recursively merged) * - `array + array = array` (removes duplicates using Set) * - `(truthy plain value) + ob = (truthy plain value)` * - `(truthy plain value) + undefined = (truthy plain value)` * - `A(truthy plain value) + B(truthy plain value) = A(truthy plain value)` * - `undefined + B(truthy plain value) = B(truthy plain value)` * - `null + B(truthy plain value) = B(truthy plain value)` * * * Handles circular references * @category Utility */ export function deepMergeLeft<T extends object, X extends DeepPartial<T>>(data: T, ...source: X[]): T; export function deepMergeLeft<T extends object>(...sources: T[]): T; export function deepMergeLeft<T extends object>( target: T, ...sources: DeepPartialObject<T>[] ): T { let output = { ...target } as unknown; for (const source of sources) { output = recursiveMerge(output, source); } return output as any; } /** * Merging object from right to left * * @param target value will be replaced if possible. * @description * Consider following * - `array + obj = obj` * - `obj + array = array` * - `obj + obj = obj` (recursively merged) * - `array + array = array` (removes duplicates using Set) * - `(truthy plain value) + undefined = (truthy plain value)` * - `A(truthy plain value) + B(truthy plain value) = B(truthy plain value)` * Handles circular references * @category Utility */ export function deepMergeRight<T extends object, X extends DeepPartial<T>>(data: T, ...source: X[]): T; export function deepMergeRight<T extends object>(...sources: T[]): T; export function deepMergeRight<T extends object>( target: T, ...sources: DeepPartialObject<T>[] ): T { let output = clone(target) as unknown; for (const source of sources) { // Only difference from mergeDeepLeft // That source go first and output last output = recursiveMerge(source, output); } return output as any; } |