From 9bc737cf2cddda2d67e83e670926936d2f306014 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 18 Jul 2017 14:36:56 -0500 Subject: [PATCH 1/4] Allow for optional keys in json objects --- packages/coreutils/src/json.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/coreutils/src/json.ts b/packages/coreutils/src/json.ts index 018f3e08b..d1ab79064 100644 --- a/packages/coreutils/src/json.ts +++ b/packages/coreutils/src/json.ts @@ -25,7 +25,7 @@ type JSONValue = JSONPrimitive | JSONObject | JSONArray; * A type definition for a JSON object. */ export -interface JSONObject { [key: string]: JSONValue; } +interface JSONObject { [key: string]: JSONValue | undefined; } /** @@ -39,7 +39,7 @@ interface JSONArray extends Array { } * A type definition for a readonly JSON object. */ export -interface ReadonlyJSONObject { readonly [key: string]: ReadonlyJSONValue; } +interface ReadonlyJSONObject { readonly [key: string]: ReadonlyJSONValue | undefined; } /** @@ -234,7 +234,13 @@ namespace JSONExt { // Compare the values for equality. for (let key in first) { - if (!deepEqual(first[key], second[key])) { + let firstValue = first[key]; + let secondValue = second[key]; + if ( + firstValue === undefined || + secondValue === undefined || + !deepEqual(firstValue, secondValue) + ) { return false; } } From d107d4885719db876f8969d0b7346d9b30768d59 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 18 Jul 2017 14:45:24 -0500 Subject: [PATCH 2/4] Handle more edge cases --- packages/coreutils/src/json.ts | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/packages/coreutils/src/json.ts b/packages/coreutils/src/json.ts index d1ab79064..1a7b5dd69 100644 --- a/packages/coreutils/src/json.ts +++ b/packages/coreutils/src/json.ts @@ -234,13 +234,22 @@ namespace JSONExt { // Compare the values for equality. for (let key in first) { + // Get the values. let firstValue = first[key]; let secondValue = second[key]; - if ( - firstValue === undefined || - secondValue === undefined || - !deepEqual(firstValue, secondValue) - ) { + + // If both are undefined, ignore the key. + if (firstValue === undefined && secondValue === undefined) { + continue; + } + + // If only one value is undefined, the objects are not equal. + if (firstValue === undefined || secondValue === undefined) { + return false; + } + + // Compare the values. + if (!deepEqual(firstValue, secondValue)) { return false; } } @@ -266,7 +275,12 @@ namespace JSONExt { function deepObjectCopy(value: any): any { let result: any = {}; for (let key in value) { - result[key] = deepCopy(value[key]); + // Ignore undefined values. + let subvalue = value[key]; + if (subvalue === undefined) { + continue; + } + result[key] = deepCopy(subvalue); } return result; } From 02c3786669dfc0c6aba45aa19ecba932b8c93aeb Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 18 Jul 2017 15:03:54 -0500 Subject: [PATCH 3/4] Improved equality check --- packages/coreutils/src/json.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/coreutils/src/json.ts b/packages/coreutils/src/json.ts index 1a7b5dd69..9116c2909 100644 --- a/packages/coreutils/src/json.ts +++ b/packages/coreutils/src/json.ts @@ -220,14 +220,14 @@ namespace JSONExt { // Check for the first object's keys in the second object. for (let key in first) { - if (!(key in second)) { + if (first[key] !== undefined && !(key in second)) { return false; } } // Check for the second object's keys in the first object. for (let key in second) { - if (!(key in first)) { + if (second[key] !== undefined && !(key in first)) { return false; } } From 70c3b338da90bcdfdb0f5b4912020368e72d5703 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 18 Jul 2017 15:03:57 -0500 Subject: [PATCH 4/4] Update tests --- tests/test-coreutils/src/json.spec.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/test-coreutils/src/json.spec.ts b/tests/test-coreutils/src/json.spec.ts index 62dc6c29b..71ae9e9b0 100644 --- a/tests/test-coreutils/src/json.spec.ts +++ b/tests/test-coreutils/src/json.spec.ts @@ -14,6 +14,11 @@ import { } from '@phosphor/coreutils'; +interface IFoo extends JSONObject { + bar?: string; +} + + describe('@phosphor/coreutils', () => { describe('JSONExt', () => { @@ -74,6 +79,15 @@ describe('@phosphor/coreutils', () => { expect(JSONExt.deepEqual({ b: 1 }, { a: 1 })).to.equal(false); }); + it('should handle optional keys', () => { + let a: IFoo = { }; + let b: IFoo = { bar: 'a' }; + let c: IFoo = { bar: undefined }; + expect(JSONExt.deepEqual(a, b)).to.equal(false); + expect(JSONExt.deepEqual(a, c)).to.equal(true); + expect(JSONExt.deepEqual(c, a)).to.equal(true); + }); + }); describe('deepCopy()', () => { @@ -110,6 +124,18 @@ describe('@phosphor/coreutils', () => { expect(v7['c']).to.not.equal(r7['c']); }); + it('should handle optional keys', () => { + let v1: IFoo = { }; + let v2: IFoo = { bar: 'a' }; + let v3: JSONObject = { a: false, b: { bar: undefined }}; + let r1 = JSONExt.deepCopy(v1); + let r2 = JSONExt.deepCopy(v2); + let r3 = JSONExt.deepCopy(v3); + expect(Object.keys(r1).length).to.equal(0); + expect(v2.bar).to.equal(r2.bar); + expect(Object.keys(r3.b).length).to.equal(0); + }); + }); });