New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.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.0.1 to 2.0.2

lib/cache.js

4

index.d.ts

@@ -180,3 +180,3 @@ declare namespace onChange {

*/
target<ObjectType extends {[key: string]: any}>(object: ObjectType): ObjectType;
target<ObjectType extends {[key: string]: any}>(object: ObjectType): ObjectType; // eslint-disable-line @typescript-eslint/method-signature-style

@@ -189,5 +189,5 @@ /**

*/
unsubscribe<ObjectType extends {[key: string]: any}>(object: ObjectType): ObjectType;
unsubscribe<ObjectType extends {[key: string]: any}>(object: ObjectType): ObjectType; // eslint-disable-line @typescript-eslint/method-signature-style
};
export = onChange;
'use strict';
const {TARGET, UNSUBSCRIBE} = require('./lib/constants');
const isBuiltin = require('./lib/is-builtin');
const path = require('./lib/path');
const isArray = require('./lib/is-array');
const isSymbol = require('./lib/is-symbol');
const ignoreProperty = require('./lib/ignore-property');
const Cache = require('./lib/cache');
const SmartClone = require('./lib/smart-clone');
const isPrimitive = value => value === null || (typeof value !== 'object' && typeof value !== 'function');
const isBuiltinWithoutMutableMethods = value => value instanceof RegExp || value instanceof Number;
const isBuiltinWithMutableMethods = value => value instanceof Date;
const isSameDescriptor = (a, b) => {
return a !== undefined && b !== undefined &&
Object.is(a.value, b.value) &&
(a.writable || false) === (b.writable || false) &&
(a.enumerable || false) === (b.enumerable || false) &&
(a.configurable || false) === (b.configurable || false);
};
const shallowClone = value => {
if (isArray(value)) {
return value.slice();
}
return {...value};
};
const onChange = (object, onChange, options = {}) => {
const proxyTarget = Symbol('ProxyTarget');
let inApply = false;
let changed = false;
let applyPath;
let applyPrevious;
let isUnsubscribed = false;
const equals = options.equals || Object.is;
let propCache = new WeakMap();
let pathCache = new WeakMap();
let proxyCache = new WeakMap();
const cache = new Cache(equals);
const smartClone = new SmartClone();
const handleChange = (changePath, property, previous, value) => {
if (isUnsubscribed) {
return;
const handleChangeOnTarget = (target, property, previous, value) => {
if (!ignoreProperty(cache, options, property)) {
handleChange(cache.getPath(target), property, previous, value);
}
};
if (!inApply) {
const handleChange = (changePath, property, previous, value) => {
if (smartClone.isCloning) {
smartClone.update(changePath, property, previous);
} else {
onChange(path.concat(changePath, property), value, previous);
return;
}
if (inApply && applyPrevious && previous !== undefined && value !== undefined && property !== 'length') {
let item = applyPrevious;
if (changePath !== applyPath) {
changePath = path.after(changePath, applyPath);
path.walk(changePath, key => {
item[key] = shallowClone(item[key]);
item = item[key];
});
}
item[property] = previous;
}
changed = true;
};
const getOwnPropertyDescriptor = (target, property) => {
let props = propCache !== null && propCache.get(target);
if (props) {
props = props.get(property);
}
if (props) {
return props;
}
props = new Map();
propCache.set(target, props);
let prop = props.get(property);
if (!prop) {
prop = Reflect.getOwnPropertyDescriptor(target, property);
props.set(property, prop);
}
return prop;
};
const invalidateCachedDescriptor = (target, property) => {
const props = propCache ? propCache.get(target) : undefined;
if (props) {
props.delete(property);
}
};
const buildProxy = (value, path) => {
if (isUnsubscribed) {
return value;
}
pathCache.set(value, path);
let proxy = proxyCache.get(value);
if (proxy === undefined) {
proxy = new Proxy(value, handler);
proxyCache.set(value, proxy);
}
return proxy;
};
const unsubscribe = target => {
isUnsubscribed = true;
propCache = null;
pathCache = null;
proxyCache = null;
return target;
};
const ignoreProperty = property => {
return isUnsubscribed ||
(options.ignoreSymbols === true && isSymbol(property)) ||
(options.ignoreUnderscores === true && property.charAt(0) === '_') ||
(options.ignoreKeys !== undefined && options.ignoreKeys.includes(property));
};
const handler = {
get(target, property, receiver) {
if (property === proxyTarget || property === TARGET) {
return target;
}
if (isSymbol(property)) {
if (property === proxyTarget || property === TARGET) {
return target;
}
if (property === UNSUBSCRIBE &&
pathCache !== null &&
pathCache.get(target) === '') {
return unsubscribe(target);
if (
property === UNSUBSCRIBE &&
!cache.isUnsubscribed &&
cache.getPath(target).length === 0
) {
cache.unsubscribe();
return target;
}
}

@@ -149,7 +51,7 @@

if (
isPrimitive(value) ||
isBuiltinWithoutMutableMethods(value) ||
isBuiltin.withoutMutableMethods(value) ||
property === 'constructor' ||
options.isShallow === true ||
ignoreProperty(property)
ignoreProperty(cache, options, property) ||
cache.isGetInvariant(target, property)
) {

@@ -159,15 +61,3 @@ return value;

// Preserve invariants
const descriptor = getOwnPropertyDescriptor(target, property);
if (descriptor && !descriptor.configurable) {
if (descriptor.set && !descriptor.get) {
return undefined;
}
if (descriptor.writable === false) {
return value;
}
}
return buildProxy(value, path.concat(pathCache.get(target), property));
return cache.getProxy(value, path.concat(cache.getPath(target), property), handler);
},

@@ -180,32 +70,27 @@

const ignore = ignoreProperty(property);
const previous = ignore ? null : Reflect.get(target, property, receiver);
const isChanged = !(property in target) || !equals(previous, value);
let result = true;
const reflectTarget = target[proxyTarget] || target;
const previous = Reflect.get(reflectTarget, property, receiver);
const hasProperty = property in target;
if (isChanged) {
result = Reflect.set(target[proxyTarget] || target, property, value);
if (cache.setProperty(reflectTarget, property, value, receiver, previous)) {
if (!equals(previous, value) || !hasProperty) {
handleChangeOnTarget(target, property, previous, value);
}
if (!ignore && result) {
handleChange(pathCache.get(target), property, previous, value);
}
return true;
}
return result;
return false;
},
defineProperty(target, property, descriptor) {
let result = true;
if (!cache.isSameDescriptor(descriptor, target, property)) {
if (!cache.defineProperty(target, property, descriptor)) {
return false;
}
if (!isSameDescriptor(descriptor, getOwnPropertyDescriptor(target, property))) {
result = Reflect.defineProperty(target, property, descriptor);
if (result && !ignoreProperty(property) && !isSameDescriptor()) {
invalidateCachedDescriptor(target, property);
handleChange(pathCache.get(target), property, undefined, descriptor.value);
}
handleChangeOnTarget(target, property, undefined, descriptor.value);
}
return result;
return true;
},

@@ -218,53 +103,49 @@

const ignore = ignoreProperty(property);
const previous = ignore ? null : Reflect.get(target, property);
const result = Reflect.deleteProperty(target, property);
const previous = Reflect.get(target, property);
if (!ignore && result) {
invalidateCachedDescriptor(target, property);
if (cache.deleteProperty(target, property, previous)) {
handleChangeOnTarget(target, property, previous);
handleChange(pathCache.get(target), property, previous);
return true;
}
return result;
return false;
},
apply(target, thisArg, argumentsList) {
const compare = isBuiltinWithMutableMethods(thisArg);
const isMutable = isBuiltin.withMutableMethods(thisArg);
if (compare) {
if (isMutable) {
thisArg = thisArg[proxyTarget];
}
if (!inApply) {
inApply = true;
if (smartClone.isCloning || cache.isUnsubscribed) {
return Reflect.apply(target, thisArg, argumentsList);
}
if (compare) {
applyPrevious = thisArg.valueOf();
}
const applyPath = path.initial(cache.getPath(target));
if (isArray(thisArg) || toString.call(thisArg) === '[object Object]') {
applyPrevious = shallowClone(thisArg[proxyTarget]);
}
if (
isMutable ||
isArray(thisArg) ||
toString.call(thisArg) === '[object Object]'
) {
smartClone.start(thisArg[proxyTarget] || thisArg, applyPath);
}
applyPath = path.initial(pathCache.get(target));
const result = Reflect.apply(target, thisArg, argumentsList);
const result = Reflect.apply(target, thisArg, argumentsList);
if (smartClone.isChanged(isMutable, thisArg, equals)) {
const {clone} = smartClone;
smartClone.done();
handleChange(applyPath, '', clone, thisArg[proxyTarget] || thisArg);
}
inApply = false;
smartClone.done();
if (changed || (compare && !equals(applyPrevious, thisArg.valueOf()))) {
handleChange(applyPath, '', applyPrevious, thisArg[proxyTarget] || thisArg);
applyPrevious = null;
changed = false;
}
return result;
}
return Reflect.apply(target, thisArg, argumentsList);
return result;
}
};
const proxy = buildProxy(object, options.pathAsArray === true ? [] : '');
const proxy = cache.getProxy(object, options.pathAsArray === true ? [] : '', handler);
onChange = onChange.bind(proxy);

@@ -271,0 +152,0 @@

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

if (isArray(path)) {
path.forEach(callback);
path.forEach(key => callback(key));
} else if (path !== '') {

@@ -66,0 +66,0 @@ let position = 0;

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

@@ -42,8 +42,9 @@ "license": "MIT",

"devDependencies": {
"ava": "^3.5.0",
"display-value": "^1.6.0",
"karma-webpack-bundle": "^0.1.2",
"tsd": "^0.11.0",
"xo": "^0.28.0"
"ava": "^3.11.1",
"display-value": "^1.7.3",
"karma-webpack-bundle": "^0.5.0",
"powerset": "0.0.1",
"tsd": "^0.13.1",
"xo": "^0.32.1"
}
}

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

- [negative-array](https://github.com/sindresorhus/negative-array) - Negative array index support `array[-1]` *(Uses `Proxy` too)*
- [statux](https://github.com/franciscop/state) - State manager *(Uses `Proxy` too)*
- [atama](https://github.com/franciscop/atama) - State manager *(Uses `Proxy` too)*
- [introspected](https://github.com/WebReflection/introspected) - Never-ending Proxy with multiple observers *(Uses `Proxy` too)*

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