diff --git a/lib/utils.js b/lib/utils.js index 98987eb2..33c01c00 100755 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,5 +1,7 @@ 'use strict'; +var has = Object.prototype.hasOwnProperty; + var hexTable = (function () { var array = []; for (var i = 0; i < 256; ++i) { @@ -10,7 +12,7 @@ var hexTable = (function () { }()); exports.arrayToObject = function (source, options) { - var obj = options.plainObjects ? Object.create(null) : {}; + var obj = options && options.plainObjects ? Object.create(null) : {}; for (var i = 0; i < source.length; ++i) { if (typeof source[i] !== 'undefined') { obj[i] = source[i]; @@ -46,6 +48,21 @@ exports.merge = function (target, source, options) { mergeTarget = exports.arrayToObject(target, options); } + if (Array.isArray(target) && Array.isArray(source)) { + source.forEach(function (item, i) { + if (has.call(target, i)) { + if (target[i] && typeof target[i] === 'object') { + target[i] = exports.merge(target[i], item, options); + } else { + target.push(item); + } + } else { + target[i] = item; + } + }); + return target; + } + return Object.keys(source).reduce(function (acc, key) { var value = source[key]; @@ -143,10 +160,9 @@ exports.compact = function (obj, references) { } var keys = Object.keys(obj); - for (var j = 0; j < keys.length; ++j) { - var key = keys[j]; + keys.forEach(function (key) { obj[key] = exports.compact(obj[key], refs); - } + }); return obj; }; diff --git a/test/utils.js b/test/utils.js index 4a8d8246..0721dd8e 100755 --- a/test/utils.js +++ b/test/utils.js @@ -5,5 +5,18 @@ var utils = require('../lib/utils'); test('merge()', function (t) { t.deepEqual(utils.merge({ a: 'b' }, { a: 'c' }), { a: ['b', 'c'] }, 'merges two objects with the same key'); + + var oneMerged = utils.merge({ foo: 'bar' }, { foo: { first: '123' } }); + t.deepEqual(oneMerged, { foo: ['bar', { first: '123' }] }, 'merges a standalone and an object into an array'); + + var twoMerged = utils.merge({ foo: ['bar', { first: '123' }] }, { foo: { second: '456' } }); + t.deepEqual(twoMerged, { foo: { 0: 'bar', 1: { first: '123' }, second: '456' } }, 'merges a standalone and two objects into an array'); + + var sandwiched = utils.merge({ foo: ['bar', { first: '123', second: '456' }] }, { foo: 'baz' }); + t.deepEqual(sandwiched, { foo: ['bar', { first: '123', second: '456' }, 'baz'] }, 'merges an object sandwiched by two standalones into an array'); + + var nestedArrays = utils.merge({ foo: ['baz'] }, { foo: ['bar', 'xyzzy'] }); + t.deepEqual(nestedArrays, { foo: ['baz', 'bar', 'xyzzy'] }); + t.end(); });