Created
September 18, 2016 16:20
-
-
Save Conaclos/ff673cd7b9c08172bb2f7bc33db86204 to your computer and use it in GitHub Desktop.
Function that joins conflict-free objects. It copies all (enum, non-enum, and symbol) properties.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Copyright (c) 2016 Victorien ELVINGER | |
This Source Code Form is subject to the terms of the Mozilla Public | |
License, v. 2.0. If a copy of the MPL was not distributed with this | |
file, You can obtain one at http://mozilla.org/MPL/2.0/. | |
*/ | |
interface DeepJoinFunction { | |
<A, B> (a: A, b: B): A & B | |
<A, B, C> (a: A, b: B, c: C): A & B & C | |
<A, B, C, D> (a: A, b: B, c: C, d: D): A & B & C & D | |
<A, B, C, D, E> (a: A, b: B, c: C, d: D, e: E): A & B & C & D & E | |
} | |
/** | |
* Copy all (enum, non-enum, and symbol) properties from `aSource' into `aTarget'. | |
* @param aSource | |
* @param aSubject - mutable | |
*/ | |
function copyAll (aSource: Properties, aSubject: Properties): void { | |
let props: Array<string | symbol> = Object.getOwnPropertyNames(aSource) | |
props = props.concat(Object.getOwnPropertySymbols(aSource)) | |
for (let f of props) { | |
aSubject[f] = aSource[f] | |
} | |
} | |
/** | |
* | |
* e.g. prototypeChainOfUntil({}, [null]) returns [Object.prototype] | |
* prototypeChainOfUntil({}, [Object.prototype]) returns [] | |
* | |
* @param aTarget | |
* @param aBounds - must contain at least one element of the prototype | |
* chain of `aTarget'. | |
* Note that `null' is the bottom prototype of all objects. | |
* In contrast, `Object.protype' is not: | |
* this is the case for `Object.create(null)' | |
$ @return Prototype chain of `aTarget' until to meet | |
* one prototype of `aBounds'. First item is the deeper prototype. | |
*/ | |
function prototypeChainOfUntil (aTarget: Properties, | |
aBounds: Array<Properties | null>): Array<Properties> { | |
const proto = Reflect.getPrototypeOf(aTarget) | |
if (aBounds.indexOf(proto) === -1) { | |
return prototypeChainOfUntil(proto, aBounds).concat(proto) | |
} else { | |
return [] | |
} | |
} | |
/** | |
* Each pair of objects (a, b) must be conflict-free | |
* (except for "constructor" property). | |
* Every properties (enum, non-enum, and symbol) are copied. | |
* | |
* @param aFirst | |
* @param aOthers | |
* @return Concatenation of `aFirst' and `aOthers'. | |
*/ | |
const deepJoin: DeepJoinFunction = | |
(aFirst: Properties, ...aOthers: Properties[]): Properties => { | |
const result = Object.create(aFirst) // mutable | |
let includedProtos = prototypeChainOfUntil(aFirst, [null]).concat([null]) | |
for (let item of aOthers) { | |
const protos = prototypeChainOfUntil(item, includedProtos) | |
for (let proto of protos) { | |
copyAll(proto, result) | |
} | |
copyAll(item, result) | |
includedProtos = includedProtos.concat(protos) | |
} | |
if (Object.hasOwnProperty.call(result, "constructor")) { | |
delete result.constructor | |
} | |
return result | |
} | |
export {DeepJoinFunction, deepJoin} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment