Skip to content

Commit

Permalink
Add ignoreKeys and ignoreUnderscores (#51)
Browse files Browse the repository at this point in the history
* Adding options.ignoreKeys
* Adding options.ignoreUnderScores
  • Loading branch information
codenamezjames authored Mar 9, 2020
1 parent 626629d commit e518c99
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 18 deletions.
14 changes: 14 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,20 @@ declare namespace onChange {
@default false
*/
ignoreSymbols?: boolean;

/**
Setting properties in this array won't trigger the callback.
@default undefined
*/
ignoreKeys?: Array<string|symbol>;

/**
Setting properties with an underscore as the first character won't trigger the callback.
@default false
*/
ignoreUnderscores?: boolean;
}
}

Expand Down
16 changes: 10 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,11 @@ const onChange = (object, onChange, options = {}) => {
return target;
};

const ignoreChange = property => {
return isUnsubscribed || (options.ignoreSymbols === true && typeof property === 'symbol');
const ignoreProperty = property => {
return isUnsubscribed ||
(options.ignoreSymbols === true && typeof property === 'symbol') ||
(options.ignoreUnderscores === true && property.charAt(0) === '_') ||
(options.ignoreKeys !== undefined && options.ignoreKeys.includes(property));
};

const handler = {
Expand All @@ -173,7 +176,8 @@ const onChange = (object, onChange, options = {}) => {
isPrimitive(value) ||
isBuiltinWithoutMutableMethods(value) ||
property === 'constructor' ||
options.isShallow === true
options.isShallow === true ||
ignoreProperty(property)
) {
return value;
}
Expand All @@ -198,7 +202,7 @@ const onChange = (object, onChange, options = {}) => {
value = value[proxyTarget];
}

const ignore = ignoreChange(property);
const ignore = ignoreProperty(property);
const previous = ignore ? null : Reflect.get(target, property, receiver);
const isChanged = !(property in target) || !equals(previous, value);
let result = true;
Expand All @@ -220,7 +224,7 @@ const onChange = (object, onChange, options = {}) => {
if (!isSameDescriptor(descriptor, getOwnPropertyDescriptor(target, property))) {
result = Reflect.defineProperty(target, property, descriptor);

if (result && !ignoreChange(property) && !isSameDescriptor()) {
if (result && !ignoreProperty(property) && !isSameDescriptor()) {
invalidateCachedDescriptor(target, property);

handleChange(pathCache.get(target), property, undefined, descriptor.value);
Expand All @@ -235,7 +239,7 @@ const onChange = (object, onChange, options = {}) => {
return true;
}

const ignore = ignoreChange(property);
const ignore = ignoreProperty(property);
const previous = ignore ? null : Reflect.get(target, property);
const result = Reflect.deleteProperty(target, property);

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
"listener"
],
"devDependencies": {
"ava": "^3.4.0",
"display-value": "^1.3.2",
"ava": "^3.5.0",
"display-value": "^1.6.0",
"matcha": "^0.7.0",
"tsd": "^0.11.0",
"xo": "^0.27.2"
Expand Down
14 changes: 14 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,20 @@ Default: false

Setting properties as `Symbol` won't trigger the callback.

##### ignoreKeys

Type: `Array<string|symbol>`<br>
Default: undefined

Setting properties in this array won't trigger the callback.

##### ignoreUnderscores

Type: `boolean`<br>
Default: false

Setting properties with an underscore as the first character won't trigger the callback.

### onChange.target(object)

Returns the original unwatched object.
Expand Down
104 changes: 94 additions & 10 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,16 @@ const testHelper = (t, object, options, callback) => {

// eslint-disable-next-line max-params
const verify = (count, thisArg, path, value, previous, fullObject) => {
t.is(last.count, count);
t.is(last.thisArg, thisArg);
t.deepEqual(last.path, path);
t.deepEqual(last.value, value);
t.deepEqual(last.previous, previous);
t.is(count, last.count);
t.is(thisArg, last.thisArg);
t.deepEqual(path, last.path);
t.deepEqual(value, last.value);
t.deepEqual(previous, last.previous);

t.is(onChange.target(proxy), object);
t.is(object, onChange.target(proxy));

if (fullObject !== undefined) {
t.deepEqual(object, fullObject);
t.deepEqual(fullObject, object);
t.deepEqual(proxy, object);
}
};
Expand Down Expand Up @@ -386,7 +386,7 @@ test('the callback should return a raw value when apply traps are triggered', t
});
});

test('the callback should trigger when a Symbol is used as the key and ignoreSymbols is not set', t => {
test('should trigger the callback when a Symbol is used as the key and ignoreSymbols is not set', t => {
const object = {
x: {
y: [{
Expand Down Expand Up @@ -418,7 +418,7 @@ test('the callback should trigger when a Symbol is used as the key and ignoreSym
});
});

test('the callback should not trigger when a Symbol is used as the key and ignoreSymbols is true', t => {
test('should not trigger the callback when a Symbol is used as the key and ignoreSymbols is true', t => {
const object = {
x: {
y: [{
Expand All @@ -430,8 +430,16 @@ test('the callback should not trigger when a Symbol is used as the key and ignor
testHelper(t, object, {ignoreSymbols: true}, (proxy, verify) => {
const SYMBOL = Symbol('test');
const SYMBOL2 = Symbol('test2');
const object2 = {
c: 2
};

proxy[SYMBOL] = true;
proxy[SYMBOL] = object2;
verify(0);

t.is(proxy[SYMBOL], object2);

proxy[SYMBOL].c = 3;
verify(0);

Object.defineProperty(proxy, SYMBOL2, {
Expand All @@ -450,6 +458,82 @@ test('the callback should not trigger when a Symbol is used as the key and ignor
});
});

test('should not trigger the callback when a key is used that is in ignoreKeys', t => {
const object = {
x: {
y: [{
z: 0
}]
}
};

testHelper(t, object, {ignoreKeys: ['a', 'b']}, (proxy, verify) => {
const object2 = {
c: 2
};

proxy.a = object2;
verify(0);

t.is(proxy.a, object2);

proxy.a.c = 3;
verify(0);

Object.defineProperty(proxy, 'b', {
value: true,
configurable: true,
writable: true,
enumerable: false
});
verify(0);

delete proxy.b;
verify(0);

proxy.z = true;
verify(1, proxy, 'z', true, undefined);
});
});

test('should not trigger the callback when a key with an underscore is used and ignoreUnderscores is true', t => {
const object = {
x: {
y: [{
z: 0
}]
}
};

testHelper(t, object, {ignoreUnderscores: true}, (proxy, verify) => {
const object2 = {
c: 2
};

proxy._a = object2;
verify(0);

t.is(proxy._a, object2);

proxy._a.c = 3;
verify(0);

Object.defineProperty(proxy, '_b', {
value: true,
configurable: true,
writable: true,
enumerable: false
});
verify(0);

delete proxy._b;
verify(0);

proxy.z = true;
verify(1, proxy, 'z', true, undefined);
});
});

test('should not call the callback for nested items if isShallow is true', t => {
const object = {
x: {
Expand Down

0 comments on commit e518c99

Please sign in to comment.