diff --git a/fp/_baseConvert.js b/fp/_baseConvert.js index 9b2db001f..30d3706ce 100644 --- a/fp/_baseConvert.js +++ b/fp/_baseConvert.js @@ -44,7 +44,7 @@ function baseConvert(util, name, func, options) { var helpers = isLib ? func : { 'ary': util.ary, - 'cloneDeep': util.cloneDeep, + 'clone': util.clone, 'curry': util.curry, 'forEach': util.forEach, 'isArray': util.isArray, @@ -52,18 +52,20 @@ function baseConvert(util, name, func, options) { 'iteratee': util.iteratee, 'keys': util.keys, 'rearg': util.rearg, - 'spread': util.spread + 'spread': util.spread, + 'toPath': util.toPath }; var ary = helpers.ary, - cloneDeep = helpers.cloneDeep, + clone = helpers.clone, curry = helpers.curry, each = helpers.forEach, isArray = helpers.isArray, isFunction = helpers.isFunction, keys = helpers.keys, rearg = helpers.rearg, - spread = helpers.spread; + spread = helpers.spread, + toPath = helpers.toPath; var aryMethodKeys = keys(mapping.aryMethod); @@ -89,6 +91,26 @@ function baseConvert(util, name, func, options) { return result; }; + var cloneByPath = function(object, path) { + path = toPath(path); + + var index = -1, + length = path.length, + result = clone(Object(object)), + nested = result; + + while (nested != null && ++index < length) { + var key = path[index], + value = nested[key]; + + if (value != null) { + nested[key] = clone(Object(value)); + } + nested = nested[key]; + } + return result; + }; + var createCloner = function(func) { return function(object) { return func({}, object); @@ -105,7 +127,7 @@ function baseConvert(util, name, func, options) { while (length--) { args[length] = arguments[length]; } - var result = args[0] = cloner(args[0]); + var result = args[0] = cloner.apply(undefined, args); func.apply(undefined, args); return result; }; @@ -215,7 +237,7 @@ function baseConvert(util, name, func, options) { wrapped = immutWrap(func, createCloner(func)); } else if (mutateMap.set[name]) { - wrapped = immutWrap(func, cloneDeep); + wrapped = immutWrap(func, cloneByPath); } } var result; diff --git a/lib/fp/template/modules/_util.jst b/lib/fp/template/modules/_util.jst index 6f776a9e9..afa811bc6 100644 --- a/lib/fp/template/modules/_util.jst +++ b/lib/fp/template/modules/_util.jst @@ -1,6 +1,6 @@ module.exports = { 'ary': require('../ary'), - 'cloneDeep': require('../cloneDeep'), + 'clone': require('../clone'), 'curry': require('../curry'), 'forEach': require('../_arrayEach'), 'isArray': require('../isArray'), @@ -8,5 +8,6 @@ module.exports = { 'iteratee': require('../iteratee'), 'keys': require('../_baseKeys'), 'rearg': require('../rearg'), - 'spread': require('../spread') + 'spread': require('../spread'), + 'toPath': require('../toPath') }; diff --git a/package.json b/package.json index 4af4c0039..7a9b0ad9a 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "istanbul": "0.4.2", "jquery": "^2.2.0", "jscs": "^2.10.1", - "lodash": "^3.10.1", + "lodash": "4.4.0", "platform": "^1.3.1", "qunit-extras": "^1.4.5", "qunitjs": "~1.21.0", diff --git a/test/test-fp.js b/test/test-fp.js index 3b6f72b4f..583ea936c 100644 --- a/test/test-fp.js +++ b/test/test-fp.js @@ -691,7 +691,7 @@ actual = fp.unset('a.b')(value); assert.deepEqual(value, deepObject, 'fp.unset'); - assert.deepEqual(actual, { 'a': { 'c': 3 } }, 'fp.set'); + assert.deepEqual(actual, { 'a': { 'c': 3 } }, 'fp.unset'); }); }()); @@ -731,6 +731,42 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('set methods'); + + (function() { + var array = [1, 2, 3], + object = { 'a': 1 }, + deepObject = { 'a': { 'b': 2, 'c': 3 } }; + + QUnit.test('should only clone objects in `path`', function(assert) { + assert.expect(8); + + var object = { 'a': { 'b': { 'c': 1 }, 'd': { 'e': 1 } } }, + value = _.cloneDeep(object), + actual = fp.set('a.b.c.d.e', 3, value); + + assert.ok(_.isObject(actual.a.b.c), 'fp.set'); + assert.ok(_.isNumber(actual.a.b.c), 'fp.set'); + + assert.strictEqual(actual.a.b.c.d.e, 3, 'fp.set'); + assert.strictEqual(actual.d, value.d, 'fp.set'); + + value = _.cloneDeep(object); + actual = fp.setWith(Object)('a.b.c')(2)(value); + + assert.strictEqual(actual.a.b.c, 2, 'fp.setWith'); + assert.strictEqual(actual.d, value.d, 'fp.setWith'); + + value = _.cloneDeep(object); + actual = fp.unset('a.b')(value); + + assert.notOk('b' in actual, 'fp.unset'); + assert.strictEqual(actual.d, value.d, 'fp.unset'); + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('with methods'); (function() {