From 4952147fd71d42c150dd550c2544d29bd4aae9e9 Mon Sep 17 00:00:00 2001 From: David Kebler Date: Fri, 12 Jun 2020 08:57:10 -0700 Subject: [PATCH] swap missing parent assignment of {} to after last target check to avoid extraneous assignment and support setter with observable --- index.js | 8 +++--- package.json | 3 ++- test.js | 74 +++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 76 insertions(+), 9 deletions(-) diff --git a/index.js b/index.js index fef5f36..febdfbf 100644 --- a/index.js +++ b/index.js @@ -37,15 +37,15 @@ function set(target, path, value, options) { for (let i = 0; i < len; i++) { let prop = keys[i]; - if (!isObject(target[prop])) { - target[prop] = {}; - } - if (i === len - 1) { result(target, prop, value, merge); break; } + if (!isObject(target[prop])) { + target[prop] = {}; + } + target = target[prop]; } diff --git a/package.json b/package.json index e62b6f2..4499d80 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "test": "mocha" }, "dependencies": { - "is-plain-object": "^2.0.4" + "is-plain-object": "^2.0.4", + "rxjs": "^6.5.5" }, "devDependencies": { "benchmarked": "^2.0.0", diff --git a/test.js b/test.js index ea93097..5caa4e5 100644 --- a/test.js +++ b/test.js @@ -188,25 +188,91 @@ describe('options', function() { it('should use a custom function to not split inside square brackets', function() { var o = {}; - set(o, "a.[b.c.d].e", 'c', options); + set(o, 'a.[b.c.d].e', 'c', options); assert.equal(o.a['[b.c.d]'].e, 'c'); }); it('should use a custom function to not split inside parens', function() { var o = {}; - set(o, "a.(b.c.d).e", 'c', options); + set(o, 'a.(b.c.d).e', 'c', options); assert.equal(o.a['(b.c.d)'].e, 'c'); }); it('should use a custom function to not split inside angle brackets', function() { var o = {}; - set(o, "a..e", 'c', options); + set(o, 'a..e', 'c', options); assert.equal(o.a[''].e, 'c'); }); it('should use a custom function to not split inside curly braces', function() { var o = {}; - set(o, "a.{b.c.d}.e", 'c', options); + set(o, 'a.{b.c.d}.e', 'c', options); assert.equal(o.a['{b.c.d}'].e, 'c'); }); }); + +const Rx = require('rxjs'); +const opers = require('rxjs/operators'); + +var _value = 0; +var o = {a: { b: {} } }; +var obs = Rx.from(new Rx.BehaviorSubject()).pipe( + opers.skip(1), +); + +Object.defineProperty(o.a.b, 'c', { + configurable: true, + get() { return _value; }, + set(value) { + _value = value; + obs.next(value); + } +}); + +describe('Setter with Observable', function() { + // const expected = 11; + var received = []; + const noop = () => {}; + it('should only assign/emit once for each call of set', function(done) { + var subs = obs.subscribe( + data => { received.push(data); }, + noop, + () => { + assert.equal(received.length, 1); + done(); + } + ); + set(o, 'a.b.c', 5); + subs.complete(); + }); + + it('should work assignment via setter', function(done) { + received = null; + var subs = obs.subscribe( + data => { received = data; }, + noop, + () => { + assert.equal(received, 10); + done(); + } + ); + set(o, 'a.b.c', 10); + subs.complete(); + }); + + it('should work with merge of object via setter', function(done) { + received = null; + set(o, 'a.b.c', {foo: 'bar'}); + var subs = obs.subscribe( + data => { received = data; }, + noop, + () => { + assert.deepEqual(o.a.b.c, { foo: 'bar', bing: 'bong' }); + done(); + } + ); + set(o, 'a.b.c', { bing: 'bong'}, {merge: true}); + subs.complete(); + }); + +});