@travetto/base
Advanced tools
Comparing version 0.0.69 to 0.0.70
@@ -19,3 +19,3 @@ { | ||
"scripts": {}, | ||
"version": "0.0.69" | ||
"version": "0.0.70" | ||
} |
@@ -26,3 +26,7 @@ export function isPrimitive(el: any): el is (string | boolean | number | RegExp) { | ||
function _deepMerge(a: any, b: any, level = 0) { | ||
function shallowClone(a: any) { | ||
return Array.isArray(a) ? a.slice(0) : (isSimple(a) ? a : { ...a }); | ||
} | ||
function _deepMerge(a: any, b: any, mode: 'loose' | 'strict' | 'coerce' = 'loose') { | ||
const isEmptyA = a === undefined || a === null; | ||
@@ -32,44 +36,51 @@ const isEmptyB = b === undefined || b === null; | ||
const isArrB = Array.isArray(b); | ||
const isSimpA = !isEmptyA && isSimple(a); | ||
const isSimpB = !isEmptyB && isSimple(b); | ||
if (isEmptyB) { | ||
return a; | ||
} | ||
let ret: any; | ||
if (isSimple(b)) { // Scalars | ||
if (isEmptyA || isSimple(a)) { | ||
a = b; | ||
} else { | ||
throw new Error(`Cannot merge primitive ${b} with ${a}`); | ||
if (isEmptyA || isEmptyB) { // If no `a`, `b` always wins | ||
ret = b === null ? b : shallowClone(b || a); | ||
} else { | ||
if (isArrA !== isArrB || isSimpA !== isSimpB) { | ||
throw new Error(`Cannot merge differing types ${a} and ${b}`); | ||
} | ||
} else if (isArrB) { // Arrays | ||
const bArr = b; | ||
if (a === undefined) { | ||
return bArr.slice(0); | ||
} else if (isArrA) { | ||
const aArr = (a as any as any[]).slice(0); | ||
for (let i = 0; i < bArr.length; i++) { | ||
aArr[i] = _deepMerge(aArr[i], bArr[i], level + 1); | ||
if (isArrB) { // Arrays | ||
ret = a.slice(0); | ||
for (let i = 0; i < b.length; i++) { | ||
ret[i] = _deepMerge(ret[i], b[i], mode); | ||
} | ||
a = aArr; | ||
} else if (b !== undefined) { | ||
throw new Error(`Cannot merge ${b} with ${a}`); | ||
} | ||
} else { // Object | ||
if (isEmptyA || isArrA || isPrimitive(a)) { | ||
if (level === 0) { | ||
throw new Error(`Cannot merge ${b} onto ${a}`); | ||
} else { | ||
a = {}; | ||
} else if (isSimpB) { // Scalars | ||
const match = typeof a === typeof b; | ||
ret = b; | ||
if (!match) { // If types do not match | ||
if (mode === 'strict') { // Bail on strict | ||
throw new Error(`Cannot merge ${a} [${typeof a}] with ${b} [${typeof b}]`); | ||
} else if (mode === 'coerce') { // Force on coerce | ||
switch (typeof a) { | ||
case 'string': ret = `${b}`; break; | ||
case 'number': ret = `${b}`.indexOf('.') >= 0 ? parseFloat(`${b}`) : parseInt(`${b}`, 10); break; | ||
case 'boolean': ret = !!b; break; | ||
default: | ||
throw new Error(`Unknown type ${typeof a}`); | ||
} | ||
} | ||
} | ||
} else { // Object merge | ||
ret = { ...a }; | ||
for (const key of Object.keys(b)) { | ||
ret[key] = _deepMerge(ret[key], b[key], mode); | ||
} | ||
} | ||
for (const key of Object.keys(b)) { | ||
a[key] = _deepMerge(a[key], b[key], level + 1); | ||
} | ||
} | ||
return a; | ||
return ret; | ||
} | ||
export function deepMerge<T extends any, U extends any>(a: T, b: U): T & U { | ||
return _deepMerge(a, b, 0) as T & U; | ||
export function deepMerge<T extends any, U extends any>(a: T, b: U, mode: 'loose' | 'strict' | 'coerce' = 'loose'): T & U { | ||
if (!a || isPrimitive(a)) { | ||
throw new Error(`Cannot merge onto a primitive value, ${a}`); | ||
} | ||
return _deepMerge(a, b, mode) as T & U; | ||
} | ||
@@ -76,0 +87,0 @@ |
require('../bootstrap').run().then(x => { | ||
// require('./stack'); | ||
require('./watch'); | ||
// require('./watch'); | ||
require('./merge'); | ||
}); |
@@ -1,4 +0,3 @@ | ||
import { deepMerge, isPrimitive } from '../src/util'; | ||
import { deepMerge, isPrimitive, isFunction } from '../src/util'; | ||
import * as assert from 'assert'; | ||
import { isFunction } from 'util'; | ||
@@ -40,7 +39,25 @@ class Test { } | ||
assert.strictEqual(deepMerge({ a: {} }, { a: { b: Test } }).a.b, Test); | ||
assert(deepMerge({ a: { b: 5 } }, { a: null }).a === null); | ||
assert.deepEqual(deepMerge({ a: { b: 5 } }, { a: undefined }).a, { b: 5 }); | ||
} | ||
// setTimeout(() => { | ||
function testStrict() { | ||
assert.throws(() => | ||
deepMerge({ a: 1 }, { a: '5' }, 'strict') | ||
); | ||
} | ||
function testCoerce() { | ||
assert(deepMerge({ a: 1 }, { a: '5' }, 'coerce').a === 5); | ||
assert(deepMerge({ a: '1' }, { a: 5 }, 'coerce').a === '5'); | ||
assert(isNaN(deepMerge({ a: 1 }, { a: true }, 'coerce').a)); | ||
assert(deepMerge({ a: true }, { a: null }, 'coerce').a === null); | ||
assert(deepMerge({ a: true }, { a: null }, 'coerce').a === null); | ||
} | ||
testPrimitive(); | ||
testMerge(); | ||
// }, 1); | ||
testStrict(); | ||
testCoerce(); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
28382
845