npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

merge-dictionaries

v1.0.0

Published

Recursively merge two dictionaries together

Downloads

150,847

Readme

merge-dictionaries

A wrapper around the Lodash 3 .merge() function that addresses some issues with arrays and object references. Intended for merging configuration files together.

Usage

npm install merge-dictionaries
var mergeDictionaries = require('merge-dictionaries');
mergeDictionaries(dictA, dictB);

What’s the problem that this solves?

The .merge() function works great in most cases, but the default behavior has two problems:

First, array values in the second argument are merged weirdly with values in the first argument. Examples:

// Two arrays are "merged" together by replacing values in the first array with values from
// the second, by index:
var dictA = { foo: ['owl', 'snake', 'fish'] };
var dictB = { foo: ['cat', 'dog']};
_.merge(dictA, dictB);

// Results in:
// { foo: ['cat', 'dog', 'fish'] }


// Merging an array into a string causes the string to be busted up into an array of characters,
// which is then merged on-top-of as above:
var dictA = { foo: 'abcde' };
var dictB = { foo: ['cat', 'dog']};
_.merge(dictA, dictB);

// Results in:
// { foo: ['cat', 'dog', 'c', 'd', 'e'] }

Second, dictionaries in the second argument that do not have corresponding dictionary values in the first argument (or whose corresponding values are {}) are copied over by value instead of by reference:

var dictA = { foo: 'bar' };
var dictB = { nested: { owl: 'hoot' } };
var owl = dictB.nested; // <-- owl is { owl: 'hoot' }
var merged = _.merge(dictA, dictB);

// Results in:
// { foo: 'bar', nested: { owl: 'hoot' } }

console.log(owl === merged.nested);
// Results in:
// false

This might not seem like a big issue, but it can be a real problem when merging dictionaries that contain references to objects created by another module. For example imagine:

var configA = { someConfigValue: 'some default value' };
var configB = { someConfigValue: 'a custom value',  someModule: require('my-module') };
var mergedObj = _.merge(configA, configB);

where my-module looks like:

module.exports = ( function() {
  // Declare the public data dictionary exposed by this module.
  var publicData = {};
  return {
    // Expose the public data to the outside world.
    somePublicData: publicData
    // Declare a function for initializing the module.
    init: function() {
      publicData.foo = 'bar';
    }
  }
} )()

If you call mergedObj.someModule.init() later, you might expect mergedObj.someModule.somePublicData to be set to {foo: 'bar'}, but it’ll still just be an empty dictionary, because a different somePublicData dictionary was copied into the merged object.

What’s the solution?

The solution is very simple, because the _.merge() function can take a third argument that allows you to customize the merge behavior. We can use this to tell _.merge() to only do its regular thing when the left-hand value is a non-empty plain dictionary. In all other cases, a is replaced by b.

Keep in mind that this means that if a looks like a dictionary, but was created by a custom constructor (i.e. it is not a “plain” dictionary, it will be replaced by b! For example:

var myClass = function() {this.foo = 'bar'};
var obj1 = { abc: new myClass() };
// Result:
// { abc: { foo: 'bar' } }

var obj2 = { abc: { owl: 'hoot' } };
var merged = mergeDictionaries(obj1, obj2);

// Result:
// { abc: { owl: 'hoot' } }

Help

If you have questions or are having trouble, click here.

Bugs   NPM version

To report a bug, click here.

Contributing

Please observe the guidelines and conventions laid out in the Sails project contribution guide when opening issues or submitting pull requests.

NPM

License

Like the Sails framework, this package is free and open-source under the MIT License.