diff --git a/.travis.yml b/.travis.yml index b41bd9f..ea3ec10 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,4 +17,5 @@ node_js: matrix: fast_finish: true allow_failures: + - node_js: 'node' - node_js: '0.8' diff --git a/README.md b/README.md index f159530..22ea846 100644 --- a/README.md +++ b/README.md @@ -60,33 +60,33 @@ $ npm install -g verbose/verb#dev verb-generate-readme && verb You might also be interested in these projects: -* [assign-deep](https://www.npmjs.com/package/assign-deep): Deeply assign the enumerable properties and/or es6 Symbol properies of source objects to the target… [more](https://github.com/jonschlinkert/assign-deep) | [homepage](https://github.com/jonschlinkert/assign-deep) -* [defaults-deep](https://www.npmjs.com/package/defaults-deep): Like `extend` but recursively copies only the missing properties/values to the target object. | [homepage](https://github.com/jonschlinkert/defaults-deep) -* [extend-shallow](https://www.npmjs.com/package/extend-shallow): Extend an object with the properties of additional objects. node.js/javascript util. | [homepage](https://github.com/jonschlinkert/extend-shallow) -* [merge-deep](https://www.npmjs.com/package/merge-deep): Recursively merge values in a javascript object. | [homepage](https://github.com/jonschlinkert/merge-deep) -* [mixin-deep](https://www.npmjs.com/package/mixin-deep): Deeply mix the properties of objects into the first object. Like merge-deep, but doesn't clone. | [homepage](https://github.com/jonschlinkert/mixin-deep) -* [omit-deep](https://www.npmjs.com/package/omit-deep): Recursively omit the specified key or keys from an object. | [homepage](https://github.com/jonschlinkert/omit-deep) +* [assign-deep](https://www.npmjs.com/package/assign-deep): Deeply assign the values of all enumerable-own-properties and symbols from one or more source objects… [more](https://github.com/jonschlinkert/assign-deep) | [homepage](https://github.com/jonschlinkert/assign-deep "Deeply assign the values of all enumerable-own-properties and symbols from one or more source objects to a target object. Returns the target object.") +* [defaults-deep](https://www.npmjs.com/package/defaults-deep): Like `extend` but recursively copies only the missing properties/values to the target object. | [homepage](https://github.com/jonschlinkert/defaults-deep "Like `extend` but recursively copies only the missing properties/values to the target object.") +* [extend-shallow](https://www.npmjs.com/package/extend-shallow): Extend an object with the properties of additional objects. node.js/javascript util. | [homepage](https://github.com/jonschlinkert/extend-shallow "Extend an object with the properties of additional objects. node.js/javascript util.") +* [merge-deep](https://www.npmjs.com/package/merge-deep): Recursively merge values in a javascript object. | [homepage](https://github.com/jonschlinkert/merge-deep "Recursively merge values in a javascript object.") +* [mixin-deep](https://www.npmjs.com/package/mixin-deep): Deeply mix the properties of objects into the first object. Like merge-deep, but doesn't clone… [more](https://github.com/jonschlinkert/mixin-deep) | [homepage](https://github.com/jonschlinkert/mixin-deep "Deeply mix the properties of objects into the first object. Like merge-deep, but doesn't clone. No dependencies.") +* [omit-deep](https://www.npmjs.com/package/omit-deep): Recursively omit the specified key or keys from an object. | [homepage](https://github.com/jonschlinkert/omit-deep "Recursively omit the specified key or keys from an object.") ### Contributors | **Commits** | **Contributor** | | --- | --- | -| 29 | [jonschlinkert](https://github.com/jonschlinkert) | -| 4 | [doowb](https://github.com/doowb) | +| 32 | [jonschlinkert](https://github.com/jonschlinkert) | +| 8 | [doowb](https://github.com/doowb) | ### Author **Jon Schlinkert** -* [LinkedIn Profile](https://linkedin.com/in/jonschlinkert) * [GitHub Profile](https://github.com/jonschlinkert) * [Twitter Profile](https://twitter.com/jonschlinkert) +* [LinkedIn Profile](https://linkedin.com/in/jonschlinkert) ### License -Copyright © 2018, [Jon Schlinkert](https://github.com/jonschlinkert). +Copyright © 2021, [Jon Schlinkert](https://github.com/jonschlinkert). Released under the [MIT License](LICENSE). *** -_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.6.0, on July 11, 2018._ \ No newline at end of file +_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.8.0, on January 11, 2021._ \ No newline at end of file diff --git a/index.js b/index.js index 16b4690..08db87a 100644 --- a/index.js +++ b/index.js @@ -32,7 +32,7 @@ module.exports = function mergeDeep(orig, objects) { function merge(target, obj) { for (var key in obj) { - if (key === '__proto__' || !hasOwn(obj, key)) { + if (!isValidKey(key) || !hasOwn(obj, key)) { continue; } @@ -57,3 +57,7 @@ function hasOwn(obj, key) { function isObject(val) { return typeOf(val) === 'object' || typeOf(val) === 'function'; } + +function isValidKey(key) { + return key !== '__proto__' && key !== 'constructor' && key !== 'prototype'; +} \ No newline at end of file diff --git a/package.json b/package.json index 2c8959a..ad300ff 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "merge-deep", "description": "Recursively merge values in a javascript object.", - "version": "3.0.2", + "version": "3.0.3", "homepage": "https://github.com/jonschlinkert/merge-deep", "author": "Jon Schlinkert (https://github.com/jonschlinkert)", "repository": "jonschlinkert/merge-deep", diff --git a/test.js b/test.js index 926bbae..f454cf7 100644 --- a/test.js +++ b/test.js @@ -134,4 +134,68 @@ describe('mergeDeep', function() { var actual = merge(fixture); assert.deepEqual(actual, fixture); }); + + it('should not clone invalid keys', function() { + var obj1 = { a: { b: 1 } }; + var obj2 = JSON.parse('{ "a": { "c": 2 }, "constructor": { "keys": 42 } }'); + + var actual = merge({}, obj1, obj2); + assert.deepEqual(actual, { a: { b: 1, c: 2 } }); + assert.notDeepEqual(actual.a, obj1.a); + assert.notDeepEqual(actual.a, obj2.a); + assert.notEqual(actual.keys, 42); + assert.notEqual(actual.constructor.keys, 42); + }); + + it('should allow being used for custom constructors', function() { + // The following setup code is a simple way to demonstrate multiple inheritance by merging the prototype of one class onto another + function Shape() { + this.type = ''; + } + + function Position(x, y) { + this.x = x || 0; + this.y = y || 0; + } + + Position.prototype.stringify = function() { + return '(' + this.x + ', ' + this.y + ')'; + }; + + function Moveable(x, y) { + Position.call(this, x, y); + } + + // By making Moveable inherit from Position, allows us to test what happens when `constructor` is passed to `isValidKey`. + Moveable.prototype = Object.create(Position.prototype); + Moveable.prototype.constructor = Moveable; + Moveable.prototype = merge(Moveable.prototype, Position.prototype); + + Moveable.prototype.move = function(x, y) { + this.x += x; + this.y += y; + }; + + Moveable.prototype.position = function() { + return this.stringify(); + }; + + function Rectangle() { + Shape.call(this); + Moveable.call(this); + this.type = 'rectangle'; + } + + // Single inheritance using Object.create + Rectangle.prototype = Object.create(Shape.prototype); + Rectangle.prototype.constructor = Rectangle; + + // This is the test to ensure that `merge-deep` can be used with prototypal inheritance + Rectangle.prototype = merge(Rectangle.prototype, Moveable.prototype); + + var rectangle = new Rectangle(); + assert.equal(rectangle.position(), '(0, 0)'); + rectangle.move(10, 20); + assert.equal(rectangle.position(), '(10, 20)'); + }); });