Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

on-change

Package Overview
Dependencies
Maintainers
2
Versions
38
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

on-change - npm Package Compare versions

Comparing version 2.1.3 to 2.1.4

40

index.js

@@ -6,5 +6,4 @@ 'use strict';

const path = require('./lib/path');
const isArray = require('./lib/is-array');
const isSymbol = require('./lib/is-symbol');
const isObject = require('./lib/is-object');
const isSymbol = require('./lib/is-symbol');
const ignoreProperty = require('./lib/ignore-property');

@@ -14,5 +13,17 @@ const Cache = require('./lib/cache');

const defaultOptions = {
equals: Object.is,
isShallow: false,
pathAsArray: false,
ignoreSymbols: false,
ignoreUnderscores: false
};
const onChange = (object, onChange, options = {}) => {
options = {
...defaultOptions,
...options
};
const proxyTarget = Symbol('ProxyTarget');
const equals = options.equals || Object.is;
const {equals, isShallow} = options;
const cache = new Cache(equals);

@@ -53,7 +64,10 @@ const smartClone = new SmartClone();

const value = Reflect.get(target, property, receiver);
const value = isBuiltin.withMutableMethods(target) ?
Reflect.get(target, property) :
Reflect.get(target, property, receiver);
if (
isBuiltin.withoutMutableMethods(value) ||
property === 'constructor' ||
(options.isShallow === true && !smartClone.isHandledMethod(target, property)) ||
(isShallow && !smartClone.isHandledMethod(target, property)) ||
ignoreProperty(cache, options, property) ||

@@ -69,3 +83,3 @@ cache.isGetInvariant(target, property)

set(target, property, value, receiver) {
if (value) {
if (isObject(value)) {
const valueProxyTarget = value[proxyTarget];

@@ -79,3 +93,3 @@

const reflectTarget = target[proxyTarget] || target;
const previous = Reflect.get(reflectTarget, property, receiver);
const previous = reflectTarget[property];
const hasProperty = property in target;

@@ -131,3 +145,3 @@

if (smartClone.isCloning || cache.isUnsubscribed) {
return Reflect.apply(target, thisArg, argumentsList);
return Reflect.apply(target, thisProxyTarget, argumentsList);
}

@@ -137,4 +151,4 @@

if (isMutable || isArray(thisArg) || isObject(thisArg)) {
smartClone.start(thisProxyTarget, applyPath);
if (isMutable || smartClone.isHandledType(thisProxyTarget)) {
smartClone.start(thisProxyTarget, applyPath, argumentsList);
}

@@ -148,3 +162,3 @@

if (smartClone.isChanged(isMutable, thisArg, equals)) {
if (smartClone.isChanged(isMutable, thisProxyTarget, equals, argumentsList)) {
const clone = smartClone.done();

@@ -157,3 +171,3 @@ handleChange(applyPath, '', clone, thisProxyTarget, target.name);

if (
(isArray(result) || isObject(result)) &&
smartClone.isHandledType(result) &&
smartClone.isHandledMethod(thisProxyTarget, target.name)

@@ -168,3 +182,3 @@ ) {

const proxy = cache.getProxy(object, options.pathAsArray === true ? [] : '', handler);
const proxy = cache.getProxy(object, options.pathAsArray ? [] : '', handler);
onChange = onChange.bind(proxy);

@@ -171,0 +185,0 @@

@@ -7,5 +7,5 @@ 'use strict';

return cache.isUnsubscribed ||
(options.ignoreSymbols === true && isSymbol(property)) ||
(options.ignoreUnderscores === true && property.charAt(0) === '_') ||
(options.ignoreSymbols && isSymbol(property)) ||
(options.ignoreUnderscores && property.charAt(0) === '_') ||
('ignoreKeys' in options && options.ignoreKeys.includes(property));
};
'use strict';
module.exports = {
withMutableMethods: value => value instanceof Date,
withoutMutableMethods: value =>
value === null ||
(typeof value !== 'object' && typeof value !== 'function') ||
value instanceof RegExp
const isPrimitive = value => typeof value === 'object' ? value === null : typeof value !== 'function';
const isBuiltin = {
withMutableMethods: value => {
if (isPrimitive(value)) {
return false;
}
return value instanceof Date ||
value instanceof Set ||
value instanceof Map ||
value instanceof WeakSet ||
value instanceof WeakMap;
},
withoutMutableMethods: value => isPrimitive(value) || value instanceof RegExp
};
module.exports = isBuiltin;

@@ -5,8 +5,42 @@ 'use strict';

const isArray = require('./is-array');
const isBuiltin = require('./is-builtin');
const isObject = require('./is-object');
const shallowEqual = (clone, value) => {
const certainChange = () => true;
const shallowEqualArrays = (clone, value) => {
return clone.length !== value.length || clone.some((item, index) => value[index] !== item);
};
const shallowEqualSets = (a, b) => {
if (a.size !== b.size) {
return true;
}
for (const element of a) {
if (!b.has(element)) {
return true;
}
}
return false;
};
const shallowEqualMaps = (a, b) => {
if (a.size !== b.size) {
return true;
}
let bValue;
for (const [key, aValue] of a) {
bValue = b.get(key);
if (bValue !== aValue || (bValue === undefined && !b.has(key))) {
return true;
}
}
return false;
};
const IMMUTABLE_OBJECT_METHODS = new Set([

@@ -29,16 +63,46 @@ 'hasOwnProperty',

const IMMUTABLE_SET_METHODS = new Set([
'has',
'toString',
'keys'
]);
const IMMUTABLE_MAP_METHODS = new Set([...IMMUTABLE_SET_METHODS].concat(['get']));
const SHALLOW_MUTABLE_ARRAY_METHODS = {
push: () => true,
pop: () => true,
shift: () => true,
unshift: () => true,
push: certainChange,
pop: certainChange,
shift: certainChange,
unshift: certainChange,
concat: (clone, value) => clone.length !== value.length,
copyWithin: shallowEqual,
reverse: shallowEqual,
sort: shallowEqual,
splice: shallowEqual,
flat: shallowEqual,
fill: shallowEqual
copyWithin: shallowEqualArrays,
reverse: shallowEqualArrays,
sort: shallowEqualArrays,
splice: shallowEqualArrays,
flat: shallowEqualArrays,
fill: shallowEqualArrays
};
const SHALLOW_MUTABLE_SET_METHODS = {
add: shallowEqualSets,
clear: shallowEqualSets,
delete: shallowEqualSets
};
const SHALLOW_MUTABLE_MAP_METHODS = {
set: shallowEqualMaps,
clear: shallowEqualMaps,
delete: shallowEqualMaps
};
const HANDLED_ARRAY_METHODS = new Set([...IMMUTABLE_OBJECT_METHODS]
.concat([...IMMUTABLE_ARRAY_METHODS])
.concat(Object.keys(SHALLOW_MUTABLE_ARRAY_METHODS)));
const HANDLED_SET_METHODS = new Set([...IMMUTABLE_SET_METHODS]
.concat(Object.keys(SHALLOW_MUTABLE_SET_METHODS)));
const HANDLED_MAP_METHODS = new Set([...IMMUTABLE_MAP_METHODS]
.concat(Object.keys(SHALLOW_MUTABLE_MAP_METHODS)));
class smartClone {

@@ -49,11 +113,15 @@ constructor() {

shallowClone(value) {
_shallowClone(value) {
let clone;
if (isArray(value)) {
if (isObject(value)) {
clone = {...value};
} else if (isArray(value)) {
clone = [...value];
} else if (value instanceof Date) {
clone = new Date(value);
} else {
clone = {...value};
} else if (value instanceof Set) {
clone = new Set(value);
} else if (value instanceof Map) {
clone = new Map(value);
}

@@ -66,3 +134,3 @@

start(value, path) {
start(value, path, argumentsList) {
if (this._cache === undefined) {

@@ -72,3 +140,10 @@ this._cache = new Set();

this.clone = path === undefined ? value : this.shallowClone(value);
if (value instanceof WeakSet) {
this._weakValue = value.has(argumentsList[0]);
} else if (value instanceof WeakMap) {
this._weakValue = value.get(argumentsList[0]);
} else {
this.clone = path === undefined ? value : this._shallowClone(value);
}
this._path = path;

@@ -78,10 +153,26 @@ this.isCloning = true;

isHandledType(value) {
return isObject(value) ||
isArray(value) ||
isBuiltin.withMutableMethods(value);
}
isHandledMethod(target, name) {
if (isArray(target) && (IMMUTABLE_OBJECT_METHODS.has(name) ||
IMMUTABLE_ARRAY_METHODS.has(name) ||
name in SHALLOW_MUTABLE_ARRAY_METHODS)) {
return true;
if (isObject(target)) {
return IMMUTABLE_OBJECT_METHODS.has(name);
}
return isObject(target) && IMMUTABLE_OBJECT_METHODS.has(name);
if (isArray(target)) {
return HANDLED_ARRAY_METHODS.has(name);
}
if (target instanceof Set) {
return HANDLED_SET_METHODS.has(name);
}
if (target instanceof Map) {
return HANDLED_MAP_METHODS.has(name);
}
return target instanceof WeakSet || target instanceof WeakMap;
}

@@ -95,2 +186,6 @@

this._onIsChanged = SHALLOW_MUTABLE_ARRAY_METHODS[name];
} else if (thisProxyTarget instanceof Set) {
this._onIsChanged = SHALLOW_MUTABLE_SET_METHODS[name];
} else if (thisProxyTarget instanceof Map) {
this._onIsChanged = SHALLOW_MUTABLE_MAP_METHODS[name];
}

@@ -110,3 +205,3 @@

if (!this._cache.has(object[key])) {
object[key] = this.shallowClone(object[key]);
object[key] = this._shallowClone(object[key]);
}

@@ -130,3 +225,4 @@

this.clone = null;
this.clone = undefined;
this._weakValue = undefined;
this.isCloning = false;

@@ -140,5 +236,15 @@ this._path = null;

isChanged(isMutable, value, equals) {
isChanged(isMutable, value, equals, argumentsList) {
if (isMutable) {
return !equals(this.clone.valueOf(), value.valueOf());
if (value instanceof Date) {
return !equals(this.clone.valueOf(), value.valueOf());
}
if (value instanceof WeakSet) {
return this._weakValue !== value.has(argumentsList[0]);
}
if (value instanceof WeakMap) {
return this._weakValue !== value.get(argumentsList[0]);
}
}

@@ -145,0 +251,0 @@

{
"name": "on-change",
"version": "2.1.3",
"version": "2.1.4",
"description": "Watch an object or array for changes",

@@ -5,0 +5,0 @@ "license": "MIT",

@@ -124,3 +124,3 @@ # on-change [![Build Status](https://travis-ci.org/sindresorhus/on-change.svg?branch=master)](https://travis-ci.org/sindresorhus/on-change)

2. The new value at the path.
3. The previous value at the path.
3. The previous value at the path. Changes in `WeakSets` and `WeakMaps` will return `undefined`.
4. The name of the method that produced the change.

@@ -127,0 +127,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc