Comparing version 0.2.0 to 1.0.0
117
index.js
'use strict'; | ||
const blacklist = [ | ||
'sort', | ||
'reverse', | ||
'splice', | ||
'pop', | ||
'unshift', | ||
'shift', | ||
'push' | ||
]; | ||
const isPrimitive = value => value === null || (typeof value !== 'object' && typeof value !== 'function'); | ||
const proxyTarget = Symbol('ProxyTarget'); | ||
module.exports = (object, onChange) => { | ||
let isBlocked = false; | ||
let inApply = false; | ||
let changed = false; | ||
const propCache = new WeakMap(); | ||
const handleChange = () => { | ||
if (!inApply) { | ||
onChange(); | ||
} else if (!changed) { | ||
changed = true; | ||
} | ||
}; | ||
const getOwnPropertyDescriptor = (target, property) => { | ||
if (!propCache.has(target)) { | ||
propCache.set(target, new Map()); | ||
} | ||
const props = propCache.get(target); | ||
if (props.has(property)) { | ||
return props.get(property); | ||
} | ||
const prop = Reflect.getOwnPropertyDescriptor(target, property); | ||
props.set(property, prop); | ||
return prop; | ||
}; | ||
const invalidateCachedDescriptor = (target, property) => { | ||
if (!propCache.has(target)) { | ||
return; | ||
} | ||
const props = propCache.get(target); | ||
props.delete(property); | ||
}; | ||
const handler = { | ||
get(target, property, receiver) { | ||
try { | ||
return new Proxy(target[property], handler); | ||
} catch (_) { | ||
return Reflect.get(target, property, receiver); | ||
if (property === proxyTarget) { | ||
return target; | ||
} | ||
const value = Reflect.get(target, property, receiver); | ||
if (isPrimitive(value)) { | ||
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 new Proxy(value, handler); | ||
}, | ||
set(target, property, value, receiver) { | ||
if (value && value[proxyTarget] !== undefined) { | ||
value = value[proxyTarget]; | ||
} | ||
const previous = Reflect.get(target, property, value, receiver); | ||
const result = Reflect.set(target, property, value); | ||
if (previous !== value) { | ||
handleChange(); | ||
} | ||
return result; | ||
}, | ||
defineProperty(target, property, descriptor) { | ||
const result = Reflect.defineProperty(target, property, descriptor); | ||
invalidateCachedDescriptor(target, property); | ||
if (!isBlocked) { | ||
onChange(); | ||
} | ||
handleChange(); | ||
return result; | ||
}, | ||
deleteProperty(target, property) { | ||
const result = Reflect.deleteProperty(target, property); | ||
invalidateCachedDescriptor(target, property); | ||
if (!isBlocked) { | ||
onChange(); | ||
} | ||
handleChange(); | ||
return result; | ||
}, | ||
apply(target, thisArg, argumentsList) { | ||
if (blacklist.includes(target.name)) { | ||
isBlocked = true; | ||
if (!inApply) { | ||
inApply = true; | ||
const result = Reflect.apply(target, thisArg, argumentsList); | ||
onChange(); | ||
isBlocked = false; | ||
if (changed) { | ||
onChange(); | ||
} | ||
inApply = false; | ||
changed = false; | ||
return result; | ||
@@ -49,0 +118,0 @@ } |
{ | ||
"name": "on-change", | ||
"version": "0.2.0", | ||
"version": "1.0.0", | ||
"description": "Watch an object or array for changes", | ||
@@ -39,3 +39,3 @@ "license": "MIT", | ||
"devDependencies": { | ||
"ava": "^0.25.0", | ||
"ava": "^1.0.1", | ||
"matcha": "^0.7.0", | ||
@@ -42,0 +42,0 @@ "xo": "^0.23.0" |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
6355
93
1