@nx-js/observer-util
Advanced tools
Comparing version 4.1.3 to 4.2.0
@@ -75,3 +75,4 @@ 'use strict'; | ||
var runningReaction; | ||
// reactions can call each other and form a call stack | ||
var reactionStack = []; | ||
var isDebugging = false; | ||
@@ -82,17 +83,21 @@ | ||
if (reaction.unobserved) { | ||
return fn.apply(context, args); | ||
return Reflect.apply(fn, context, args); | ||
} | ||
// release the (obj -> key -> reactions) connections | ||
// and reset the cleaner connections | ||
releaseReaction(reaction); | ||
// only run the reaction if it is not already in the reaction stack | ||
// TODO: improve this to allow explicitly recursive reactions | ||
if (reactionStack.indexOf(reaction) === -1) { | ||
// release the (obj -> key -> reactions) connections | ||
// and reset the cleaner connections | ||
releaseReaction(reaction); | ||
try { | ||
// set the reaction as the currently running one | ||
// this is required so that we can create (observable.prop -> reaction) pairs in the get trap | ||
runningReaction = reaction; | ||
return fn.apply(context, args); | ||
} finally { | ||
// always remove the currently running flag from the reaction when it stops execution | ||
runningReaction = undefined; | ||
try { | ||
// set the reaction as the currently running one | ||
// this is required so that we can create (observable.prop -> reaction) pairs in the get trap | ||
reactionStack.push(reaction); | ||
return Reflect.apply(fn, context, args); | ||
} finally { | ||
// always remove the currently running flag from the reaction when it stops execution | ||
reactionStack.pop(); | ||
} | ||
} | ||
@@ -103,2 +108,4 @@ } | ||
function registerRunningReactionForOperation(operation) { | ||
// get the current reaction from the top of the stack | ||
var runningReaction = reactionStack[reactionStack.length - 1]; | ||
if (runningReaction) { | ||
@@ -139,3 +146,3 @@ debugOperation(runningReaction, operation); | ||
function hasRunningReaction() { | ||
return runningReaction !== undefined; | ||
return reactionStack.length > 0; | ||
} | ||
@@ -181,3 +188,2 @@ | ||
var getPrototypeOf = Object.getPrototypeOf; | ||
var hasOwnProperty = Object.prototype.hasOwnProperty; | ||
@@ -188,3 +194,3 @@ | ||
var target = proxyToRaw.get(this); | ||
var proto = getPrototypeOf(this); | ||
var proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target: target, key: key, type: 'has' }); | ||
@@ -195,3 +201,3 @@ return proto.has.apply(target, arguments); | ||
var target = proxyToRaw.get(this); | ||
var proto = getPrototypeOf(this); | ||
var proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target: target, key: key, type: 'get' }); | ||
@@ -202,3 +208,3 @@ return proto.get.apply(target, arguments); | ||
var target = proxyToRaw.get(this); | ||
var proto = getPrototypeOf(this); | ||
var proto = Reflect.getPrototypeOf(this); | ||
var hadKey = proto.has.call(target, key); | ||
@@ -214,3 +220,3 @@ // forward the operation before queueing reactions | ||
var target = proxyToRaw.get(this); | ||
var proto = getPrototypeOf(this); | ||
var proto = Reflect.getPrototypeOf(this); | ||
var hadKey = proto.has.call(target, key); | ||
@@ -229,3 +235,3 @@ var oldValue = proto.get.call(target, key); | ||
var target = proxyToRaw.get(this); | ||
var proto = getPrototypeOf(this); | ||
var proto = Reflect.getPrototypeOf(this); | ||
var hadKey = proto.has.call(target, key); | ||
@@ -242,3 +248,3 @@ var oldValue = proto.get ? proto.get.call(target, key) : undefined; | ||
var target = proxyToRaw.get(this); | ||
var proto = getPrototypeOf(this); | ||
var proto = Reflect.getPrototypeOf(this); | ||
var hadItems = target.size !== 0; | ||
@@ -255,3 +261,3 @@ var oldTarget = target instanceof Map ? new Map(target) : new Set(target); | ||
var target = proxyToRaw.get(this); | ||
var proto = getPrototypeOf(this); | ||
var proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target: target, type: 'iterate' }); | ||
@@ -262,3 +268,3 @@ return proto.forEach.apply(target, arguments); | ||
var target = proxyToRaw.get(this); | ||
var proto = getPrototypeOf(this); | ||
var proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target: target, type: 'iterate' }); | ||
@@ -269,3 +275,3 @@ return proto.keys.apply(target, arguments); | ||
var target = proxyToRaw.get(this); | ||
var proto = getPrototypeOf(this); | ||
var proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target: target, type: 'iterate' }); | ||
@@ -276,3 +282,3 @@ return proto.values.apply(target, arguments); | ||
var target = proxyToRaw.get(this); | ||
var proto = getPrototypeOf(this); | ||
var proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target: target, type: 'iterate' }); | ||
@@ -283,3 +289,3 @@ return proto.entries.apply(target, arguments); | ||
var target = proxyToRaw.get(this); | ||
var proto = getPrototypeOf(this); | ||
var proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target: target, type: 'iterate' }); | ||
@@ -291,3 +297,3 @@ return Reflect.get(proto, 'size', target); | ||
var target = proxyToRaw.get(this); | ||
var proto = getPrototypeOf(this); | ||
var proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target: target, type: 'iterate' }); | ||
@@ -326,2 +332,3 @@ return proto[Symbol.iterator].apply(target, arguments); | ||
var hasOwnProperty$1 = Object.prototype.hasOwnProperty; | ||
var wellKnownSymbols = new Set(Object.getOwnPropertyNames(Symbol).map(function (key) { return Symbol[key]; }).filter(function (value) { return typeof value === 'symbol'; })); | ||
@@ -331,4 +338,5 @@ // intercept get operations on observables to know which reaction uses their properties | ||
var result = Reflect.get(target, key, receiver); | ||
// do not register (observable.prop -> reaction) pairs for these cases | ||
if (typeof key === 'symbol' || typeof result === 'function') { | ||
// do not register (observable.prop -> reaction) pairs for well known symbols | ||
// these symbols are frequently retrieved in low level JavaScript under the hood | ||
if (typeof key === 'symbol' && wellKnownSymbols.has(key)) { | ||
return result; | ||
@@ -358,6 +366,2 @@ } | ||
var result = Reflect.has(target, key); | ||
// do not register (observable.prop -> reaction) pairs for these cases | ||
if (typeof key === 'symbol') { | ||
return result; | ||
} | ||
// register and save (observable.prop -> runningReaction) | ||
@@ -385,15 +389,7 @@ registerRunningReactionForOperation({ target: target, key: key, type: 'has' }); | ||
var result = Reflect.set(target, key, value, receiver); | ||
// emit a warning and do not queue anything when another reaction is queued | ||
// from an already running reaction | ||
if (hasRunningReaction()) { | ||
console.error(("Mutating observables in reactions is forbidden. You set " + key + " to " + value + ".")); | ||
return result; | ||
} | ||
// do not queue reactions if it is a symbol keyed property | ||
// or the target of the operation is not the raw receiver | ||
// do not queue reactions if the target of the operation is not the raw receiver | ||
// (possible because of prototypal inheritance) | ||
if (typeof key === 'symbol' || target !== proxyToRaw.get(receiver)) { | ||
if (target !== proxyToRaw.get(receiver)) { | ||
return result; | ||
} | ||
// queue a reaction if it's a new property or its value changed | ||
@@ -421,4 +417,4 @@ if (!hadKey) { | ||
var result = Reflect.deleteProperty(target, key); | ||
// only queue reactions for non symbol keyed property delete which resulted in an actual change | ||
if (typeof key !== 'symbol' && hadKey) { | ||
// only queue reactions for delete operations which resulted in an actual change | ||
if (hadKey) { | ||
queueReactionsForOperation({ target: target, key: key, oldValue: oldValue, type: 'delete' }); | ||
@@ -425,0 +421,0 @@ } |
@@ -67,3 +67,4 @@ 'use strict'; | ||
let runningReaction; | ||
// reactions can call each other and form a call stack | ||
const reactionStack = []; | ||
let isDebugging = false; | ||
@@ -74,17 +75,21 @@ | ||
if (reaction.unobserved) { | ||
return fn.apply(context, args); | ||
return Reflect.apply(fn, context, args); | ||
} | ||
// release the (obj -> key -> reactions) connections | ||
// and reset the cleaner connections | ||
releaseReaction(reaction); | ||
// only run the reaction if it is not already in the reaction stack | ||
// TODO: improve this to allow explicitly recursive reactions | ||
if (reactionStack.indexOf(reaction) === -1) { | ||
// release the (obj -> key -> reactions) connections | ||
// and reset the cleaner connections | ||
releaseReaction(reaction); | ||
try { | ||
// set the reaction as the currently running one | ||
// this is required so that we can create (observable.prop -> reaction) pairs in the get trap | ||
runningReaction = reaction; | ||
return fn.apply(context, args); | ||
} finally { | ||
// always remove the currently running flag from the reaction when it stops execution | ||
runningReaction = undefined; | ||
try { | ||
// set the reaction as the currently running one | ||
// this is required so that we can create (observable.prop -> reaction) pairs in the get trap | ||
reactionStack.push(reaction); | ||
return Reflect.apply(fn, context, args); | ||
} finally { | ||
// always remove the currently running flag from the reaction when it stops execution | ||
reactionStack.pop(); | ||
} | ||
} | ||
@@ -95,2 +100,4 @@ } | ||
function registerRunningReactionForOperation(operation) { | ||
// get the current reaction from the top of the stack | ||
const runningReaction = reactionStack[reactionStack.length - 1]; | ||
if (runningReaction) { | ||
@@ -131,3 +138,3 @@ debugOperation(runningReaction, operation); | ||
function hasRunningReaction() { | ||
return runningReaction !== undefined; | ||
return reactionStack.length > 0; | ||
} | ||
@@ -171,3 +178,2 @@ | ||
const getPrototypeOf = Object.getPrototypeOf; | ||
const hasOwnProperty = Object.prototype.hasOwnProperty; | ||
@@ -178,3 +184,3 @@ | ||
const target = proxyToRaw.get(this); | ||
const proto = getPrototypeOf(this); | ||
const proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target, key, type: 'has' }); | ||
@@ -185,3 +191,3 @@ return proto.has.apply(target, arguments); | ||
const target = proxyToRaw.get(this); | ||
const proto = getPrototypeOf(this); | ||
const proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target, key, type: 'get' }); | ||
@@ -192,3 +198,3 @@ return proto.get.apply(target, arguments); | ||
const target = proxyToRaw.get(this); | ||
const proto = getPrototypeOf(this); | ||
const proto = Reflect.getPrototypeOf(this); | ||
const hadKey = proto.has.call(target, key); | ||
@@ -204,3 +210,3 @@ // forward the operation before queueing reactions | ||
const target = proxyToRaw.get(this); | ||
const proto = getPrototypeOf(this); | ||
const proto = Reflect.getPrototypeOf(this); | ||
const hadKey = proto.has.call(target, key); | ||
@@ -219,3 +225,3 @@ const oldValue = proto.get.call(target, key); | ||
const target = proxyToRaw.get(this); | ||
const proto = getPrototypeOf(this); | ||
const proto = Reflect.getPrototypeOf(this); | ||
const hadKey = proto.has.call(target, key); | ||
@@ -232,3 +238,3 @@ const oldValue = proto.get ? proto.get.call(target, key) : undefined; | ||
const target = proxyToRaw.get(this); | ||
const proto = getPrototypeOf(this); | ||
const proto = Reflect.getPrototypeOf(this); | ||
const hadItems = target.size !== 0; | ||
@@ -245,3 +251,3 @@ const oldTarget = target instanceof Map ? new Map(target) : new Set(target); | ||
const target = proxyToRaw.get(this); | ||
const proto = getPrototypeOf(this); | ||
const proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target, type: 'iterate' }); | ||
@@ -252,3 +258,3 @@ return proto.forEach.apply(target, arguments); | ||
const target = proxyToRaw.get(this); | ||
const proto = getPrototypeOf(this); | ||
const proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target, type: 'iterate' }); | ||
@@ -259,3 +265,3 @@ return proto.keys.apply(target, arguments); | ||
const target = proxyToRaw.get(this); | ||
const proto = getPrototypeOf(this); | ||
const proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target, type: 'iterate' }); | ||
@@ -266,3 +272,3 @@ return proto.values.apply(target, arguments); | ||
const target = proxyToRaw.get(this); | ||
const proto = getPrototypeOf(this); | ||
const proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target, type: 'iterate' }); | ||
@@ -273,3 +279,3 @@ return proto.entries.apply(target, arguments); | ||
const target = proxyToRaw.get(this); | ||
const proto = getPrototypeOf(this); | ||
const proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target, type: 'iterate' }); | ||
@@ -280,3 +286,3 @@ return proto[Symbol.iterator].apply(target, arguments); | ||
const target = proxyToRaw.get(this); | ||
const proto = getPrototypeOf(this); | ||
const proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target, type: 'iterate' }); | ||
@@ -314,2 +320,3 @@ return Reflect.get(proto, 'size', target); | ||
const hasOwnProperty$1 = Object.prototype.hasOwnProperty; | ||
const wellKnownSymbols = new Set(Object.getOwnPropertyNames(Symbol).map(key => Symbol[key]).filter(value => typeof value === 'symbol')); | ||
@@ -319,4 +326,5 @@ // intercept get operations on observables to know which reaction uses their properties | ||
const result = Reflect.get(target, key, receiver); | ||
// do not register (observable.prop -> reaction) pairs for these cases | ||
if (typeof key === 'symbol' || typeof result === 'function') { | ||
// do not register (observable.prop -> reaction) pairs for well known symbols | ||
// these symbols are frequently retrieved in low level JavaScript under the hood | ||
if (typeof key === 'symbol' && wellKnownSymbols.has(key)) { | ||
return result; | ||
@@ -346,6 +354,2 @@ } | ||
const result = Reflect.has(target, key); | ||
// do not register (observable.prop -> reaction) pairs for these cases | ||
if (typeof key === 'symbol') { | ||
return result; | ||
} | ||
// register and save (observable.prop -> runningReaction) | ||
@@ -373,15 +377,7 @@ registerRunningReactionForOperation({ target, key, type: 'has' }); | ||
const result = Reflect.set(target, key, value, receiver); | ||
// emit a warning and do not queue anything when another reaction is queued | ||
// from an already running reaction | ||
if (hasRunningReaction()) { | ||
console.error(`Mutating observables in reactions is forbidden. You set ${key} to ${value}.`); | ||
return result; | ||
} | ||
// do not queue reactions if it is a symbol keyed property | ||
// or the target of the operation is not the raw receiver | ||
// do not queue reactions if the target of the operation is not the raw receiver | ||
// (possible because of prototypal inheritance) | ||
if (typeof key === 'symbol' || target !== proxyToRaw.get(receiver)) { | ||
if (target !== proxyToRaw.get(receiver)) { | ||
return result; | ||
} | ||
// queue a reaction if it's a new property or its value changed | ||
@@ -409,4 +405,4 @@ if (!hadKey) { | ||
const result = Reflect.deleteProperty(target, key); | ||
// only queue reactions for non symbol keyed property delete which resulted in an actual change | ||
if (typeof key !== 'symbol' && hadKey) { | ||
// only queue reactions for delete operations which resulted in an actual change | ||
if (hadKey) { | ||
queueReactionsForOperation({ target, key, oldValue, type: 'delete' }); | ||
@@ -413,0 +409,0 @@ } |
@@ -71,3 +71,4 @@ var connectionStore = new WeakMap(); | ||
var runningReaction; | ||
// reactions can call each other and form a call stack | ||
var reactionStack = []; | ||
var isDebugging = false; | ||
@@ -78,17 +79,21 @@ | ||
if (reaction.unobserved) { | ||
return fn.apply(context, args); | ||
return Reflect.apply(fn, context, args); | ||
} | ||
// release the (obj -> key -> reactions) connections | ||
// and reset the cleaner connections | ||
releaseReaction(reaction); | ||
// only run the reaction if it is not already in the reaction stack | ||
// TODO: improve this to allow explicitly recursive reactions | ||
if (reactionStack.indexOf(reaction) === -1) { | ||
// release the (obj -> key -> reactions) connections | ||
// and reset the cleaner connections | ||
releaseReaction(reaction); | ||
try { | ||
// set the reaction as the currently running one | ||
// this is required so that we can create (observable.prop -> reaction) pairs in the get trap | ||
runningReaction = reaction; | ||
return fn.apply(context, args); | ||
} finally { | ||
// always remove the currently running flag from the reaction when it stops execution | ||
runningReaction = undefined; | ||
try { | ||
// set the reaction as the currently running one | ||
// this is required so that we can create (observable.prop -> reaction) pairs in the get trap | ||
reactionStack.push(reaction); | ||
return Reflect.apply(fn, context, args); | ||
} finally { | ||
// always remove the currently running flag from the reaction when it stops execution | ||
reactionStack.pop(); | ||
} | ||
} | ||
@@ -99,2 +104,4 @@ } | ||
function registerRunningReactionForOperation(operation) { | ||
// get the current reaction from the top of the stack | ||
var runningReaction = reactionStack[reactionStack.length - 1]; | ||
if (runningReaction) { | ||
@@ -135,3 +142,3 @@ debugOperation(runningReaction, operation); | ||
function hasRunningReaction() { | ||
return runningReaction !== undefined; | ||
return reactionStack.length > 0; | ||
} | ||
@@ -177,3 +184,2 @@ | ||
var getPrototypeOf = Object.getPrototypeOf; | ||
var hasOwnProperty = Object.prototype.hasOwnProperty; | ||
@@ -184,3 +190,3 @@ | ||
var target = proxyToRaw.get(this); | ||
var proto = getPrototypeOf(this); | ||
var proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target: target, key: key, type: 'has' }); | ||
@@ -191,3 +197,3 @@ return proto.has.apply(target, arguments); | ||
var target = proxyToRaw.get(this); | ||
var proto = getPrototypeOf(this); | ||
var proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target: target, key: key, type: 'get' }); | ||
@@ -198,3 +204,3 @@ return proto.get.apply(target, arguments); | ||
var target = proxyToRaw.get(this); | ||
var proto = getPrototypeOf(this); | ||
var proto = Reflect.getPrototypeOf(this); | ||
var hadKey = proto.has.call(target, key); | ||
@@ -210,3 +216,3 @@ // forward the operation before queueing reactions | ||
var target = proxyToRaw.get(this); | ||
var proto = getPrototypeOf(this); | ||
var proto = Reflect.getPrototypeOf(this); | ||
var hadKey = proto.has.call(target, key); | ||
@@ -225,3 +231,3 @@ var oldValue = proto.get.call(target, key); | ||
var target = proxyToRaw.get(this); | ||
var proto = getPrototypeOf(this); | ||
var proto = Reflect.getPrototypeOf(this); | ||
var hadKey = proto.has.call(target, key); | ||
@@ -238,3 +244,3 @@ var oldValue = proto.get ? proto.get.call(target, key) : undefined; | ||
var target = proxyToRaw.get(this); | ||
var proto = getPrototypeOf(this); | ||
var proto = Reflect.getPrototypeOf(this); | ||
var hadItems = target.size !== 0; | ||
@@ -251,3 +257,3 @@ var oldTarget = target instanceof Map ? new Map(target) : new Set(target); | ||
var target = proxyToRaw.get(this); | ||
var proto = getPrototypeOf(this); | ||
var proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target: target, type: 'iterate' }); | ||
@@ -258,3 +264,3 @@ return proto.forEach.apply(target, arguments); | ||
var target = proxyToRaw.get(this); | ||
var proto = getPrototypeOf(this); | ||
var proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target: target, type: 'iterate' }); | ||
@@ -265,3 +271,3 @@ return proto.keys.apply(target, arguments); | ||
var target = proxyToRaw.get(this); | ||
var proto = getPrototypeOf(this); | ||
var proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target: target, type: 'iterate' }); | ||
@@ -272,3 +278,3 @@ return proto.values.apply(target, arguments); | ||
var target = proxyToRaw.get(this); | ||
var proto = getPrototypeOf(this); | ||
var proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target: target, type: 'iterate' }); | ||
@@ -279,3 +285,3 @@ return proto.entries.apply(target, arguments); | ||
var target = proxyToRaw.get(this); | ||
var proto = getPrototypeOf(this); | ||
var proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target: target, type: 'iterate' }); | ||
@@ -287,3 +293,3 @@ return Reflect.get(proto, 'size', target); | ||
var target = proxyToRaw.get(this); | ||
var proto = getPrototypeOf(this); | ||
var proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target: target, type: 'iterate' }); | ||
@@ -322,2 +328,3 @@ return proto[Symbol.iterator].apply(target, arguments); | ||
var hasOwnProperty$1 = Object.prototype.hasOwnProperty; | ||
var wellKnownSymbols = new Set(Object.getOwnPropertyNames(Symbol).map(function (key) { return Symbol[key]; }).filter(function (value) { return typeof value === 'symbol'; })); | ||
@@ -327,4 +334,5 @@ // intercept get operations on observables to know which reaction uses their properties | ||
var result = Reflect.get(target, key, receiver); | ||
// do not register (observable.prop -> reaction) pairs for these cases | ||
if (typeof key === 'symbol' || typeof result === 'function') { | ||
// do not register (observable.prop -> reaction) pairs for well known symbols | ||
// these symbols are frequently retrieved in low level JavaScript under the hood | ||
if (typeof key === 'symbol' && wellKnownSymbols.has(key)) { | ||
return result; | ||
@@ -354,6 +362,2 @@ } | ||
var result = Reflect.has(target, key); | ||
// do not register (observable.prop -> reaction) pairs for these cases | ||
if (typeof key === 'symbol') { | ||
return result; | ||
} | ||
// register and save (observable.prop -> runningReaction) | ||
@@ -381,15 +385,7 @@ registerRunningReactionForOperation({ target: target, key: key, type: 'has' }); | ||
var result = Reflect.set(target, key, value, receiver); | ||
// emit a warning and do not queue anything when another reaction is queued | ||
// from an already running reaction | ||
if (hasRunningReaction()) { | ||
console.error(("Mutating observables in reactions is forbidden. You set " + key + " to " + value + ".")); | ||
return result; | ||
} | ||
// do not queue reactions if it is a symbol keyed property | ||
// or the target of the operation is not the raw receiver | ||
// do not queue reactions if the target of the operation is not the raw receiver | ||
// (possible because of prototypal inheritance) | ||
if (typeof key === 'symbol' || target !== proxyToRaw.get(receiver)) { | ||
if (target !== proxyToRaw.get(receiver)) { | ||
return result; | ||
} | ||
// queue a reaction if it's a new property or its value changed | ||
@@ -417,4 +413,4 @@ if (!hadKey) { | ||
var result = Reflect.deleteProperty(target, key); | ||
// only queue reactions for non symbol keyed property delete which resulted in an actual change | ||
if (typeof key !== 'symbol' && hadKey) { | ||
// only queue reactions for delete operations which resulted in an actual change | ||
if (hadKey) { | ||
queueReactionsForOperation({ target: target, key: key, oldValue: oldValue, type: 'delete' }); | ||
@@ -421,0 +417,0 @@ } |
@@ -63,3 +63,4 @@ const connectionStore = new WeakMap(); | ||
let runningReaction; | ||
// reactions can call each other and form a call stack | ||
const reactionStack = []; | ||
let isDebugging = false; | ||
@@ -70,17 +71,21 @@ | ||
if (reaction.unobserved) { | ||
return fn.apply(context, args); | ||
return Reflect.apply(fn, context, args); | ||
} | ||
// release the (obj -> key -> reactions) connections | ||
// and reset the cleaner connections | ||
releaseReaction(reaction); | ||
// only run the reaction if it is not already in the reaction stack | ||
// TODO: improve this to allow explicitly recursive reactions | ||
if (reactionStack.indexOf(reaction) === -1) { | ||
// release the (obj -> key -> reactions) connections | ||
// and reset the cleaner connections | ||
releaseReaction(reaction); | ||
try { | ||
// set the reaction as the currently running one | ||
// this is required so that we can create (observable.prop -> reaction) pairs in the get trap | ||
runningReaction = reaction; | ||
return fn.apply(context, args); | ||
} finally { | ||
// always remove the currently running flag from the reaction when it stops execution | ||
runningReaction = undefined; | ||
try { | ||
// set the reaction as the currently running one | ||
// this is required so that we can create (observable.prop -> reaction) pairs in the get trap | ||
reactionStack.push(reaction); | ||
return Reflect.apply(fn, context, args); | ||
} finally { | ||
// always remove the currently running flag from the reaction when it stops execution | ||
reactionStack.pop(); | ||
} | ||
} | ||
@@ -91,2 +96,4 @@ } | ||
function registerRunningReactionForOperation(operation) { | ||
// get the current reaction from the top of the stack | ||
const runningReaction = reactionStack[reactionStack.length - 1]; | ||
if (runningReaction) { | ||
@@ -127,3 +134,3 @@ debugOperation(runningReaction, operation); | ||
function hasRunningReaction() { | ||
return runningReaction !== undefined; | ||
return reactionStack.length > 0; | ||
} | ||
@@ -167,3 +174,2 @@ | ||
const getPrototypeOf = Object.getPrototypeOf; | ||
const hasOwnProperty = Object.prototype.hasOwnProperty; | ||
@@ -174,3 +180,3 @@ | ||
const target = proxyToRaw.get(this); | ||
const proto = getPrototypeOf(this); | ||
const proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target, key, type: 'has' }); | ||
@@ -181,3 +187,3 @@ return proto.has.apply(target, arguments); | ||
const target = proxyToRaw.get(this); | ||
const proto = getPrototypeOf(this); | ||
const proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target, key, type: 'get' }); | ||
@@ -188,3 +194,3 @@ return proto.get.apply(target, arguments); | ||
const target = proxyToRaw.get(this); | ||
const proto = getPrototypeOf(this); | ||
const proto = Reflect.getPrototypeOf(this); | ||
const hadKey = proto.has.call(target, key); | ||
@@ -200,3 +206,3 @@ // forward the operation before queueing reactions | ||
const target = proxyToRaw.get(this); | ||
const proto = getPrototypeOf(this); | ||
const proto = Reflect.getPrototypeOf(this); | ||
const hadKey = proto.has.call(target, key); | ||
@@ -215,3 +221,3 @@ const oldValue = proto.get.call(target, key); | ||
const target = proxyToRaw.get(this); | ||
const proto = getPrototypeOf(this); | ||
const proto = Reflect.getPrototypeOf(this); | ||
const hadKey = proto.has.call(target, key); | ||
@@ -228,3 +234,3 @@ const oldValue = proto.get ? proto.get.call(target, key) : undefined; | ||
const target = proxyToRaw.get(this); | ||
const proto = getPrototypeOf(this); | ||
const proto = Reflect.getPrototypeOf(this); | ||
const hadItems = target.size !== 0; | ||
@@ -241,3 +247,3 @@ const oldTarget = target instanceof Map ? new Map(target) : new Set(target); | ||
const target = proxyToRaw.get(this); | ||
const proto = getPrototypeOf(this); | ||
const proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target, type: 'iterate' }); | ||
@@ -248,3 +254,3 @@ return proto.forEach.apply(target, arguments); | ||
const target = proxyToRaw.get(this); | ||
const proto = getPrototypeOf(this); | ||
const proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target, type: 'iterate' }); | ||
@@ -255,3 +261,3 @@ return proto.keys.apply(target, arguments); | ||
const target = proxyToRaw.get(this); | ||
const proto = getPrototypeOf(this); | ||
const proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target, type: 'iterate' }); | ||
@@ -262,3 +268,3 @@ return proto.values.apply(target, arguments); | ||
const target = proxyToRaw.get(this); | ||
const proto = getPrototypeOf(this); | ||
const proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target, type: 'iterate' }); | ||
@@ -269,3 +275,3 @@ return proto.entries.apply(target, arguments); | ||
const target = proxyToRaw.get(this); | ||
const proto = getPrototypeOf(this); | ||
const proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target, type: 'iterate' }); | ||
@@ -276,3 +282,3 @@ return proto[Symbol.iterator].apply(target, arguments); | ||
const target = proxyToRaw.get(this); | ||
const proto = getPrototypeOf(this); | ||
const proto = Reflect.getPrototypeOf(this); | ||
registerRunningReactionForOperation({ target, type: 'iterate' }); | ||
@@ -310,2 +316,3 @@ return Reflect.get(proto, 'size', target); | ||
const hasOwnProperty$1 = Object.prototype.hasOwnProperty; | ||
const wellKnownSymbols = new Set(Object.getOwnPropertyNames(Symbol).map(key => Symbol[key]).filter(value => typeof value === 'symbol')); | ||
@@ -315,4 +322,5 @@ // intercept get operations on observables to know which reaction uses their properties | ||
const result = Reflect.get(target, key, receiver); | ||
// do not register (observable.prop -> reaction) pairs for these cases | ||
if (typeof key === 'symbol' || typeof result === 'function') { | ||
// do not register (observable.prop -> reaction) pairs for well known symbols | ||
// these symbols are frequently retrieved in low level JavaScript under the hood | ||
if (typeof key === 'symbol' && wellKnownSymbols.has(key)) { | ||
return result; | ||
@@ -342,6 +350,2 @@ } | ||
const result = Reflect.has(target, key); | ||
// do not register (observable.prop -> reaction) pairs for these cases | ||
if (typeof key === 'symbol') { | ||
return result; | ||
} | ||
// register and save (observable.prop -> runningReaction) | ||
@@ -369,15 +373,7 @@ registerRunningReactionForOperation({ target, key, type: 'has' }); | ||
const result = Reflect.set(target, key, value, receiver); | ||
// emit a warning and do not queue anything when another reaction is queued | ||
// from an already running reaction | ||
if (hasRunningReaction()) { | ||
console.error(`Mutating observables in reactions is forbidden. You set ${key} to ${value}.`); | ||
return result; | ||
} | ||
// do not queue reactions if it is a symbol keyed property | ||
// or the target of the operation is not the raw receiver | ||
// do not queue reactions if the target of the operation is not the raw receiver | ||
// (possible because of prototypal inheritance) | ||
if (typeof key === 'symbol' || target !== proxyToRaw.get(receiver)) { | ||
if (target !== proxyToRaw.get(receiver)) { | ||
return result; | ||
} | ||
// queue a reaction if it's a new property or its value changed | ||
@@ -405,4 +401,4 @@ if (!hadKey) { | ||
const result = Reflect.deleteProperty(target, key); | ||
// only queue reactions for non symbol keyed property delete which resulted in an actual change | ||
if (typeof key !== 'symbol' && hadKey) { | ||
// only queue reactions for delete operations which resulted in an actual change | ||
if (hadKey) { | ||
queueReactionsForOperation({ target, key, oldValue, type: 'delete' }); | ||
@@ -409,0 +405,0 @@ } |
{ | ||
"name": "@nx-js/observer-util", | ||
"version": "4.1.3", | ||
"version": "4.2.0", | ||
"description": "Simple transparent reactivity with 100% language coverage. Made with ES6 Proxies.", | ||
@@ -46,4 +46,3 @@ "main": "dist/cjs.es5.js", | ||
"devDependencies": { | ||
"babel-core": "6.25.0", | ||
"babel-minify": "^0.2.0", | ||
"babel-core": "6.26.3", | ||
"babel-preset-es2016": "^6.24.1", | ||
@@ -54,25 +53,25 @@ "babel-preset-es2017": "^6.24.1", | ||
"buble": "^0.15.2", | ||
"chai": "^4.1.1", | ||
"coveralls": "^2.13.1", | ||
"karma": "^1.7.0", | ||
"chai": "^4.1.2", | ||
"coveralls": "^3.0.1", | ||
"karma": "^2.0.2", | ||
"karma-chai": "^0.1.0", | ||
"karma-chrome-launcher": "^2.2.0", | ||
"karma-coverage": "^1.1.1", | ||
"karma-coverage": "^1.1.2", | ||
"karma-mocha": "^1.3.0", | ||
"karma-mocha-reporter": "^2.2.5", | ||
"karma-rollup-preprocessor": "^5.0.1", | ||
"karma-source-map-support": "^1.2.0", | ||
"markdown-toc": "^1.1.0", | ||
"mocha": "^3.5.0", | ||
"nyc": "11.1.0", | ||
"karma-rollup-preprocessor": "^6.0.0", | ||
"karma-source-map-support": "^1.3.0", | ||
"markdown-toc": "^1.2.0", | ||
"mocha": "^5.2.0", | ||
"nyc": "12.0.2", | ||
"pre-push": "^0.1.1", | ||
"prettier": "^1.6.1", | ||
"rollup": "^0.49.0", | ||
"rollup-plugin-alias": "^1.3.1", | ||
"rollup-plugin-auto-external": "^1.0.0", | ||
"rollup-plugin-babel": "^3.0.2", | ||
"rollup-plugin-commonjs": "^8.2.0", | ||
"prettier": "^1.13.5", | ||
"rollup": "^0.60.1", | ||
"rollup-plugin-alias": "^1.4.0", | ||
"rollup-plugin-auto-external": "^1.2.0", | ||
"rollup-plugin-babel": "^3.0.4", | ||
"rollup-plugin-commonjs": "^9.1.3", | ||
"rollup-plugin-coverage": "^0.1.4", | ||
"rollup-plugin-node-resolve": "^3.0.0", | ||
"standard": "^10.0.3" | ||
"rollup-plugin-node-resolve": "^3.3.0", | ||
"standard": "^11.0.1" | ||
}, | ||
@@ -79,0 +78,0 @@ "engines": { |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
29
0
80509
8
1558