Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit b281292

Browse files
ankomattphillips
authored andcommitted
Support diffing keys named like Object.prototype properties
Fixes mattphillips#58. Previously, the code assumed that input objects have a `hasOwnProperty` function, or that at least they will acquire one when passed through `utils.properObject`. However, this assumption is flawed: As noted in issue mattphillips#58, when given input objects have a property on them called `hasOwnProperty`, it overrides the prototype's function property that the code relied on, causing any diffing function to error out with Uncaught TypeError: r.hasOwnProperty is not a function The solution taken here is to forget about `utils.properObject`, and instead introduce `utils.hasOwnProperty` which uses `Object.prototype.hasOwnProperty.call` instead of assuming anything about the input object, and replacing all direct `inputObject.hasOwnProperty` calls with it instead.
1 parent ca791b3 commit b281292

File tree

8 files changed

+31
-54
lines changed

8 files changed

+31
-54
lines changed

‎src/added/index.js‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
import { isEmpty, isObject, properObject } from '../utils';
1+
import { isEmpty, isObject, hasOwnProperty } from '../utils';
22

33
const addedDiff = (lhs, rhs) => {
44

55
if (lhs === rhs || !isObject(lhs) || !isObject(rhs)) return {};
66

7-
const l = properObject(lhs);
8-
const r = properObject(rhs);
7+
const l = lhs;
8+
const r = rhs;
99

1010
return Object.keys(r).reduce((acc, key) => {
11-
if (l.hasOwnProperty(key)) {
11+
if (hasOwnProperty(l,key)) {
1212
const difference = addedDiff(l[key], r[key]);
1313

1414
if (isObject(difference) && isEmpty(difference)) return acc;

‎src/arrayDiff/index.js‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
import { isDate, isEmpty, isObject, properObject } from '../utils';
1+
import { isDate, isEmpty, isObject, hasOwnProperty } from '../utils';
22

33
const diff = (lhs, rhs) => {
44
if (lhs === rhs) return {}; // equal return no diff
55

66
if (!isObject(lhs) || !isObject(rhs)) return rhs; // return updated rhs
77

8-
const l = properObject(lhs);
9-
const r = properObject(rhs);
8+
const l = lhs;
9+
const r = rhs;
1010

1111
const deletedValues = Object.keys(l).reduce((acc, key) => {
12-
return r.hasOwnProperty(key) ? acc : { ...acc, [key]: undefined };
12+
return hasOwnProperty(r,key) ? acc : { ...acc, [key]: undefined };
1313
}, {});
1414

1515
if (isDate(l) || isDate(r)) {
@@ -19,11 +19,11 @@ const diff = (lhs, rhs) => {
1919

2020
if (Array.isArray(r) && Array.isArray(l)) {
2121
const deletedValues = l.reduce((acc, item, index) => {
22-
return r.hasOwnProperty(index) ? acc.concat(item) : acc.concat(undefined);
22+
return hasOwnProperty(r,index) ? acc.concat(item) : acc.concat(undefined);
2323
}, []);
2424

2525
return r.reduce((acc, rightItem, index) => {
26-
if (!deletedValues.hasOwnProperty(index)) {
26+
if (!hasOwnProperty(deletedValues,index)) {
2727
return acc.concat(rightItem);
2828
}
2929

@@ -40,7 +40,7 @@ const diff = (lhs, rhs) => {
4040
}
4141

4242
return Object.keys(r).reduce((acc, key) => {
43-
if (!l.hasOwnProperty(key)) return { ...acc, [key]: r[key] }; // return added r key
43+
if (!hasOwnProperty(l,key)) return { ...acc, [key]: r[key] }; // return added r key
4444

4545
const difference = diff(l[key], r[key]);
4646

‎src/deleted/index.js‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
import { isEmpty, isObject, properObject } from '../utils';
1+
import { isEmpty, isObject, hasOwnProperty } from '../utils';
22

33
const deletedDiff = (lhs, rhs) => {
44
if (lhs === rhs || !isObject(lhs) || !isObject(rhs)) return {};
55

6-
const l = properObject(lhs);
7-
const r = properObject(rhs);
6+
const l = lhs;
7+
const r = rhs;
88

99
return Object.keys(l).reduce((acc, key) => {
10-
if (r.hasOwnProperty(key)) {
10+
if (hasOwnProperty(r,key)) {
1111
const difference = deletedDiff(l[key], r[key]);
1212

1313
if (isObject(difference) && isEmpty(difference)) return acc;

‎src/diff/index.js‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
import { isDate, isEmptyObject, isObject, properObject } from "../utils";
1+
import { isDate, isEmptyObject, isObject, hasOwnProperty } from '../utils';
22

33
const diff = (lhs, rhs) => {
44
if (lhs === rhs) return {}; // equal return no diff
55

66
if (!isObject(lhs) || !isObject(rhs)) return rhs; // return updated rhs
77

8-
const l = properObject(lhs);
9-
const r = properObject(rhs);
8+
const l = lhs;
9+
const r = rhs;
1010

1111
const deletedValues = Object.keys(l).reduce((acc, key) => {
12-
return r.hasOwnProperty(key) ? acc : { ...acc, [key]: undefined };
12+
return hasOwnProperty(r,key) ? acc : { ...acc, [key]: undefined };
1313
}, {});
1414

1515
if (isDate(l) || isDate(r)) {
@@ -18,7 +18,7 @@ const diff = (lhs, rhs) => {
1818
}
1919

2020
return Object.keys(r).reduce((acc, key) => {
21-
if (!l.hasOwnProperty(key)) return { ...acc, [key]: r[key] }; // return added r key
21+
if (!hasOwnProperty(l,key)) return { ...acc, [key]: r[key] }; // return added r key
2222

2323
const difference = diff(l[key], r[key]);
2424

‎src/preserveArray.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { isObject } from './utils';
1+
import { isObject,hasOwnProperty } from './utils';
22

33
const getLargerArray = (l, r) => l.length > r.length ? l : r;
44

@@ -16,7 +16,7 @@ const preserve = (diff, left, right) => {
1616
return {
1717
...acc,
1818
[key]: array.reduce((acc2, item, index) => {
19-
if (diff[key].hasOwnProperty(index)) {
19+
if (hasOwnProperty(diff[key],index)) {
2020
acc2[index] = preserve(diff[key][index], leftArray[index], rightArray[index]); // diff recurse and check for nested arrays
2121
return acc2;
2222
}

‎src/updated/index.js‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
import { isDate, isEmptyObject, isObject, properObject } from "../utils";
1+
import { isDate, isEmptyObject, isObject, hasOwnProperty } from '../utils';
22

33
const updatedDiff = (lhs, rhs) => {
44
if (lhs === rhs) return {};
55

66
if (!isObject(lhs) || !isObject(rhs)) return rhs;
77

8-
const l = properObject(lhs);
9-
const r = properObject(rhs);
8+
const l = lhs;
9+
const r = rhs;
1010

1111
if (isDate(l) || isDate(r)) {
1212
if (l.valueOf() == r.valueOf()) return {};
1313
return r;
1414
}
1515

1616
return Object.keys(r).reduce((acc, key) => {
17-
if (l.hasOwnProperty(key)) {
17+
if (hasOwnProperty(l,key)) {
1818
const difference = updatedDiff(l[key], r[key]);
1919

2020
// If the difference is empty, and the lhs is an empty object or the rhs is not an empty object

‎src/utils/index.js‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
export const isDate = (d) => d instanceof Date;
2-
export const isEmpty = (o) => Object.keys(o).length === 0;
3-
export const isObject = (o) => o != null && typeof o === "object";
4-
export const properObject = (o) => (isObject(o)&&!o.hasOwnProperty ? { ...o} : o);
1+
export const isDate = d => d instanceof Date;
2+
export const isEmpty = o => Object.keys(o).length === 0;
3+
export const isObject = o => o != null && typeof o === 'object';
4+
export const hasOwnProperty = (o, ...args) => Object.prototype.hasOwnProperty.call(o, ...args)
55
export const isEmptyObject = (o) => isObject(o) && isEmpty(o);

‎src/utils/index.test.js‎

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { isDate, isEmpty, isObject,properObject } from './';
1+
import { isDate, isEmpty, isObject } from './';
22

33
describe('utils', () => {
44

@@ -70,27 +70,4 @@ describe('utils', () => {
7070
expect(isObject(value)).toBe(false);
7171
});
7272
});
73-
74-
describe('.properObject', () => {
75-
it('returns given object when object has keys and hasOwnProperty function', () => {
76-
const o = { a: 1 };
77-
const a = [1];
78-
expect(properObject(o)).toBe(o);
79-
expect(properObject(a)).toBe(a);
80-
});
81-
82-
it('returns given value when value is not an object', () => {
83-
const o = 'hello';
84-
expect(properObject(o)).toBe(o);
85-
});
86-
87-
it('returns object that has given keys and hasOwnProperty function when given object is created from a null', () => {
88-
const o = Object.create(null);
89-
o.a = 1;
90-
const actual = properObject(o);
91-
expect(actual).toEqual({ a: 1 });
92-
expect(typeof actual.hasOwnProperty === 'function').toBe(true);
93-
expect(actual).not.toBe(o);
94-
});
95-
});
9673
});

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /