Merging algorithm

Last updated 7 months ago

When composing stamps you actually merge their descriptors (aka metadata).

The Object.assign is used for these descriptor properties:

The special deep merging algorithm (see below) is used for these descriptor properties:

The array concatenation and deduplication (see below) is used for these descriptor properties:

Array concatenation and deduplication

This is how initializers and composers metadata gets merged.

const _ = require('lodash')
descriptor.initializers = _.uniq(_.concat(descriptor1.initializers, descriptor2.initializers))
descriptor.composers = _.uniq(_.concat(descriptor1.composers, descriptor2.composers))

See the exact line of the reference implementation source code.

Deep merging algorithm

The stamp specification standardized the deep merging algorithm to, basically, this:

  • Plain objects are (recursively) deep merged, including ES6 Symbol keys.

  • Arrays are concatenated.

  • Functions, Symbols, RegExp, etc. values are copied by reference.

  • The last object type overwrites previous object type.

const MyStamp1 = stampit()
const deepObject1 = {
[Symbol('foo')]: { one: 'first' }, // this plain object will be deep merged
array: [0, 'bar', () => {}, { obj: 'my object' }], // this array will be concatenated with
func: MyStamp1, // this stamp will be replaced with another stamp
something: [42], // this array will be replaced with an object
oldKey: 'some value'
}
const MyStamp2 = stampit()
const deepObject2 = {
[Symbol('foo')]: { two: 'second' },
array: [0, 'bar', { another: 'object' }],
func: MyStamp2,
something: { [0]: 42 },
newKey: 'some value'
}

The merged result of the two objects above will be this:

const deepResult = {
[Symbol('foo')]: { one: 'first', two: 'second' }, // contains properties from both objects
array: [0, 'bar', () => {}, { obj: 'my object' }, 0, 'bar', { another: 'object' }], // both arrays are here
func: MyStamp2, // Stamp2 replaced the Stamp1
something: { [0]: 42 }, // the array was replaced with the object
oldKey: 'some value', // these two were simply carried across
newKey: 'some value'
}

See the exact line of the reference implementation source code.