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.4 to 2.2.0

7

index.d.ts

@@ -88,2 +88,9 @@ declare namespace onChange {

pathAsArray?: boolean;
/**
Ignore changes to objects that become detached from the watched object.
@default false
*/
ignoreDetached?: boolean;
}

@@ -90,0 +97,0 @@ }

64

index.js

@@ -7,3 +7,2 @@ 'use strict';

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

@@ -18,3 +17,4 @@ const Cache = require('./lib/cache');

ignoreSymbols: false,
ignoreUnderscores: false
ignoreUnderscores: false,
ignoreDetached: false
};

@@ -28,3 +28,3 @@

const proxyTarget = Symbol('ProxyTarget');
const {equals, isShallow} = options;
const {equals, isShallow, ignoreDetached} = options;
const cache = new Cache(equals);

@@ -34,3 +34,6 @@ const smartClone = new SmartClone();

const handleChangeOnTarget = (target, property, previous, value) => {
if (!ignoreProperty(cache, options, property)) {
if (
!ignoreProperty(cache, options, property) &&
!(ignoreDetached && cache.isDetached(target, object))
) {
handleChange(cache.getPath(target), property, previous, value);

@@ -73,5 +76,6 @@ }

property === 'constructor' ||
(isShallow && !smartClone.isHandledMethod(target, property)) ||
(isShallow && !SmartClone.isHandledMethod(target, property)) ||
ignoreProperty(cache, options, property) ||
cache.isGetInvariant(target, property)
cache.isGetInvariant(target, property) ||
(ignoreDetached && cache.isDetached(target, object))
) {

@@ -85,3 +89,3 @@ return value;

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

@@ -138,40 +142,36 @@

apply(target, thisArg, argumentsList) {
const isMutable = isBuiltin.withMutableMethods(thisArg);
const thisProxyTarget = thisArg[proxyTarget] || thisArg;
if (isMutable) {
thisArg = thisProxyTarget;
}
if (smartClone.isCloning || cache.isUnsubscribed) {
if (cache.isUnsubscribed) {
return Reflect.apply(target, thisProxyTarget, argumentsList);
}
const applyPath = path.initial(cache.getPath(target));
if (SmartClone.isHandledType(thisProxyTarget)) {
const applyPath = path.initial(cache.getPath(target));
if (isMutable || smartClone.isHandledType(thisProxyTarget)) {
smartClone.start(thisProxyTarget, applyPath, argumentsList);
}
const result = Reflect.apply(
target,
smartClone.preferredThisArg(target, thisArg, thisProxyTarget),
argumentsList
);
const result = Reflect.apply(
target,
smartClone.preferredThisArg(target, thisArg, thisProxyTarget),
argumentsList
);
if (smartClone.isChanged(isMutable, thisProxyTarget, equals, argumentsList)) {
const clone = smartClone.done();
handleChange(applyPath, '', clone, thisProxyTarget, target.name);
}
const isChanged = smartClone.isChanged(thisProxyTarget, equals, argumentsList);
const clone = smartClone.stop();
smartClone.done();
if (isChanged) {
if (smartClone.isCloning) {
handleChange(path.initial(applyPath), path.last(applyPath), clone, thisProxyTarget, target.name);
} else {
handleChange(applyPath, '', clone, thisProxyTarget, target.name);
}
}
if (
smartClone.isHandledType(result) &&
smartClone.isHandledMethod(thisProxyTarget, target.name)
) {
return cache.getProxy(result, applyPath, handler);
return (SmartClone.isHandledType(result) && SmartClone.isHandledMethod(thisProxyTarget, target.name)) ?
cache.getProxy(result, applyPath, handler) :
result;
}
return result;
return Reflect.apply(target, thisArg, argumentsList);
}

@@ -178,0 +178,0 @@ };

'use strict';
const path = require('./path');
/**

@@ -72,2 +74,12 @@ * @class Cache

isDetached(target, object) {
path.walk(this.getPath(target), key => {
if (object) {
object = object[key];
}
});
return !Object.is(target, object);
}
defineProperty(target, property, descriptor) {

@@ -74,0 +86,0 @@ if (!Reflect.defineProperty(target, property, descriptor)) {

'use strict';
const isPrimitive = value => typeof value === 'object' ? value === null : typeof value !== 'function';
const isBuiltin = {
withMutableMethods: value => {
if (isPrimitive(value)) {
return false;
}
return value instanceof Date ||

@@ -17,5 +11,5 @@ value instanceof Set ||

},
withoutMutableMethods: value => isPrimitive(value) || value instanceof RegExp
withoutMutableMethods: value => (typeof value === 'object' ? value === null : typeof value !== 'function') || value instanceof RegExp
};
module.exports = isBuiltin;

@@ -36,3 +36,3 @@ 'use strict';

if (isSymbol(key)) {
return path + 'Symbol(' + key.description + ')';
return path + key.toString();
}

@@ -62,2 +62,19 @@

},
last: path => {
if (isArray(path)) {
return path[path.length - 1] || '';
}
if (path === '') {
return path;
}
const index = path.lastIndexOf(PATH_SEPARATOR);
if (index === -1) {
return path;
}
return path.slice(index + 1);
},
walk: (path, callback) => {

@@ -64,0 +81,0 @@ if (isArray(path)) {

@@ -14,9 +14,9 @@ 'use strict';

const shallowEqualSets = (a, b) => {
if (a.size !== b.size) {
const shallowEqualSets = (clone, value) => {
if (clone.size !== value.size) {
return true;
}
for (const element of a) {
if (!b.has(element)) {
for (const element of clone) {
if (!value.has(element)) {
return true;

@@ -29,4 +29,4 @@ }

const shallowEqualMaps = (a, b) => {
if (a.size !== b.size) {
const shallowEqualMaps = (clone, value) => {
if (clone.size !== value.size) {
return true;

@@ -36,6 +36,6 @@ }

let bValue;
for (const [key, aValue] of a) {
bValue = b.get(key);
for (const [key, aValue] of clone) {
bValue = value.get(key);
if (bValue !== aValue || (bValue === undefined && !b.has(key))) {
if (bValue !== aValue || (bValue === undefined && !value.has(key))) {
return true;

@@ -58,2 +58,3 @@ }

const IMMUTABLE_ARRAY_METHODS = new Set([
'concat',
'includes',

@@ -79,3 +80,2 @@ 'indexOf',

unshift: certainChange,
concat: (clone, value) => clone.length !== value.length,
copyWithin: shallowEqualArrays,

@@ -111,5 +111,15 @@ reverse: shallowEqualArrays,

class smartClone {
constructor() {
this.done();
class Clone {
constructor(value, path, argumentsList) {
this._path = path;
this._isChanged = false;
this._clonedCache = new Set();
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);
}
}

@@ -132,3 +142,3 @@

this._cache.add(clone);
this._clonedCache.add(clone);

@@ -138,49 +148,6 @@ return clone;

start(value, path, argumentsList) {
if (this._cache === undefined) {
this._cache = new Set();
}
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;
this.isCloning = true;
}
isHandledType(value) {
return isObject(value) ||
isArray(value) ||
isBuiltin.withMutableMethods(value);
}
isHandledMethod(target, name) {
if (isObject(target)) {
return 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;
}
preferredThisArg(target, thisArg, thisProxyTarget) {
const {name} = target;
if (this.isHandledMethod(thisProxyTarget, name)) {
if (SmartClone.isHandledMethod(thisProxyTarget, name)) {
if (isArray(thisProxyTarget)) {

@@ -205,3 +172,3 @@ this._onIsChanged = SHALLOW_MUTABLE_ARRAY_METHODS[name];

path.walk(path.after(fullPath, this._path), key => {
if (!this._cache.has(object[key])) {
if (!this._clonedCache.has(object[key])) {
object[key] = this._shallowClone(object[key]);

@@ -219,40 +186,77 @@ }

done() {
const {clone} = this;
isChanged(value, equals, argumentsList) {
if (value instanceof Date) {
return !equals(this.clone.valueOf(), value.valueOf());
}
if (this._cache !== undefined) {
this._cache.clear();
if (value instanceof WeakSet) {
return this._weakValue !== value.has(argumentsList[0]);
}
this.clone = undefined;
this._weakValue = undefined;
this.isCloning = false;
this._path = null;
this._onIsChanged = null;
this._isChanged = false;
if (value instanceof WeakMap) {
return this._weakValue !== value.get(argumentsList[0]);
}
return clone;
return this._onIsChanged === undefined ?
this._isChanged :
this._onIsChanged(this.clone, value);
}
}
isChanged(isMutable, value, equals, argumentsList) {
if (isMutable) {
if (value instanceof Date) {
return !equals(this.clone.valueOf(), value.valueOf());
}
class SmartClone {
constructor() {
this.stack = [];
}
if (value instanceof WeakSet) {
return this._weakValue !== value.has(argumentsList[0]);
}
static isHandledType(value) {
return isObject(value) ||
isArray(value) ||
isBuiltin.withMutableMethods(value);
}
if (value instanceof WeakMap) {
return this._weakValue !== value.get(argumentsList[0]);
}
static isHandledMethod(target, name) {
if (isObject(target)) {
return IMMUTABLE_OBJECT_METHODS.has(name);
}
return this._onIsChanged ?
this._onIsChanged(this.clone, value) :
this._isChanged;
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 isBuiltin.withMutableMethods(target);
}
get isCloning() {
return this.stack.length !== 0;
}
start(value, path, argumentsList) {
this.stack.push(new Clone(value, path, argumentsList));
}
update(fullPath, property, value) {
this.stack[this.stack.length - 1].update(fullPath, property, value);
}
preferredThisArg(target, thisArg, thisProxyTarget) {
return this.stack[this.stack.length - 1].preferredThisArg(target, thisArg, thisProxyTarget);
}
isChanged(isMutable, value, equals, argumentsList) {
return this.stack[this.stack.length - 1].isChanged(isMutable, value, equals, argumentsList);
}
stop() {
return this.stack.pop().clone;
}
}
module.exports = smartClone;
module.exports = SmartClone;
{
"name": "on-change",
"version": "2.1.4",
"version": "2.2.0",
"description": "Watch an object or array for changes",

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

"devDependencies": {
"ava": "^3.11.1",
"display-value": "^1.7.3",
"karma-webpack-bundle": "^0.5.0",
"ava": "^3.13.0",
"display-value": "^1.8.1",
"karma-webpack-bundle": "^0.5.3",
"powerset": "0.0.1",

@@ -47,0 +47,0 @@ "tsd": "^0.13.1",

@@ -1,2 +0,2 @@

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

@@ -175,2 +175,11 @@ > Watch an object or array for changes

##### ignoreDetached
Type: `boolean`\
Default: `false`
Ignore changes to objects that become detached from the watched object.
<br/>
### onChange.target(object)

@@ -177,0 +186,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