Skip to content
This repository has been archived by the owner on Nov 6, 2019. It is now read-only.

Allow for optional keys in JSON objects #303

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 26 additions & 6 deletions packages/coreutils/src/json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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; }


/**
Expand All @@ -39,7 +39,7 @@ interface JSONArray extends Array<JSONValue> { }
* A type definition for a readonly JSON object.
*/
export
interface ReadonlyJSONObject { readonly [key: string]: ReadonlyJSONValue; }
interface ReadonlyJSONObject { readonly [key: string]: ReadonlyJSONValue | undefined; }


/**
Expand Down Expand Up @@ -220,21 +220,36 @@ 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;
}
}

// Compare the values for equality.
for (let key in first) {
if (!deepEqual(first[key], second[key])) {
// Get the values.
let firstValue = first[key];
let secondValue = second[key];

// 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;
}
}
Expand All @@ -260,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;
}
Expand Down
26 changes: 26 additions & 0 deletions tests/test-coreutils/src/json.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ import {
} from '@phosphor/coreutils';


interface IFoo extends JSONObject {
bar?: string;
}


describe('@phosphor/coreutils', () => {

describe('JSONExt', () => {
Expand Down Expand Up @@ -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()', () => {
Expand Down Expand Up @@ -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);
});

});

});
Expand Down