diff --git a/changelog.md b/changelog.md index 025005e..bc13a3e 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,7 @@ +# 2022-04-06 - v2.4.6 + + - bug fixes on mergeChanges and unwrap methods + # 2021-10-27 - v2.4.5 - Fix the ownKeys function type issue. diff --git a/package-lock.json b/package-lock.json index 71eb9e0..d3ae1dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@creately/sakota", - "version": "2.4.4", + "version": "2.4.6", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 2134532..ca0d4e8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@creately/sakota", - "version": "2.4.5", + "version": "2.4.6", "description": "Proxies js objects and records all changes made on an object without modifying the object.", "main": "dist/index.js", "typings": "dist/index.d.ts", diff --git a/src/__tests__/index.spec.ts b/src/__tests__/index.spec.ts index e6a1449..d9800bc 100644 --- a/src/__tests__/index.spec.ts +++ b/src/__tests__/index.spec.ts @@ -719,6 +719,47 @@ describe('Sakota', () => { wrapped.__sakota__.mergeChanges(wrapped1.__sakota__.getChanges()); expect(wrapped).toEqual(target as any); }); + + it('should merge only upto 2 levels', () => { + const entity = { + data: { d1: 'data1' }, + }; + const wrapped = Sakota.create(entity); + const modifier = { $set: { 'links.l1': { id: 'l1' } } }; + spyOn(console, 'warn'); + wrapped.__sakota__.mergeChanges(modifier); + expect(wrapped).toEqual({ + ...entity, + links: { + l1: { + id: 'l1', + }, + }, + } as any); + expect(console.warn).toHaveBeenCalled(); + }); + + it('throw if the modifier is incorrect', () => { + const entity = { + data: { d1: 'data1' }, + }; + const wrapped = Sakota.create(entity); + const modifier = { $set: { 'links.l1.data': 'data1' } }; + spyOn(console, 'warn'); + expect(() => wrapped.__sakota__.mergeChanges(modifier)).toThrow(); + expect(console.warn).toHaveBeenCalled(); + }); + + it('throw if the modifier is incorrect(2)', () => { + const entity = { + data: { d1: 'data1' }, + }; + const wrapped = Sakota.create(entity); + const modifier = { $unset: { 'links.l1': true } }; + spyOn(console, 'warn'); + expect(() => wrapped.__sakota__.mergeChanges(modifier)).toThrow(); + expect(console.warn).toHaveBeenCalled(); + }); }); // Test for unwrap @@ -797,13 +838,23 @@ describe('Sakota', () => { a: [{ b: 234 }], }; const wrapped = Sakota.create(obj); - delete obj.a[0].b; + delete wrapped.a[0].b; const unwrapped = wrapped.__sakota__.unwrap(true); expect(unwrapped === obj).toBeTruthy(); expect(unwrapped).toEqual({ a: [{}] }); expect(Sakota.hasSakota(unwrapped)).toBeFalsy(); }); + + it('should preserve the object type information after unwrap', () => { + // class APoint extends Point {} + const obj: any = new Point(); + const wrapped = Sakota.create(obj); + wrapped.p = { x: 2, y: 3 }; + + const unwrapped = wrapped.__sakota__.unwrap(); + expect(unwrapped).toEqual(new Point(2, 3)); + }); }); describe('mergeChanges + unwrap', () => { diff --git a/src/index.ts b/src/index.ts index 7c53a9f..f943956 100644 --- a/src/index.ts +++ b/src/index.ts @@ -383,7 +383,7 @@ export class Sakota implements ProxyHandler { } else { console.warn('unexpected modifier', { path: k, modifier: changes }); const skeys = Object.keys(kidChanges[k].$set); - const ukeys = Object.keys(kidChanges[k].$set); + const ukeys = Object.keys(kidChanges[k].$unset); if (skeys.length === 0 || ukeys.length > 0 || skeys.some(k => k.includes('.'))) { throw new Error('Invalid modifier'); // this scenario is not expected. } else { @@ -459,7 +459,12 @@ export class Sakota implements ProxyHandler { val = inplace ? this.target : this.target.slice(); Object.keys($set).forEach(k => (val[k] = $set[k])); } else { - val = inplace ? Object.assign(this.target, $set) : Object.assign({}, this.target, $set); + if (inplace) { + val = Object.assign(this.target, $set); + } else { + val = Object.assign({}, this.target, $set); + Object.setPrototypeOf(val, Object.getPrototypeOf(this.target)); + } } $unset.forEach(k => delete val[k]); return val;