Socket
Socket
Sign inDemoInstall

@nx-js/observer-util

Package Overview
Dependencies
Maintainers
1
Versions
20
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@nx-js/observer-util - npm Package Compare versions

Comparing version 4.3.0-alpha.0 to 4.3.0-alpha.1

691

dist/cjs.es6.js

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

const connectionStore = new WeakMap();
const ITERATION_KEY = Symbol('iteration key');
var connectionStore = new WeakMap();
var ITERATION_KEY = Symbol('iteration key');
function storeObservable(obj) {

@@ -13,4 +12,7 @@ // this will be used to save (obj.key -> reaction) connections later

}
function registerReactionForOperation(reaction, { target, key, type }) {
function registerReactionForOperation(reaction, {
target,
key,
type
}) {
if (type === 'iterate') {

@@ -20,9 +22,11 @@ key = ITERATION_KEY;

const reactionsForObj = connectionStore.get(target);
let reactionsForKey = reactionsForObj.get(key);
var reactionsForObj = connectionStore.get(target);
var reactionsForKey = reactionsForObj.get(key);
if (!reactionsForKey) {
reactionsForKey = new Set();
reactionsForObj.set(key, reactionsForKey);
}
// save the fact that the key is used by the reaction during its current run
} // save the fact that the key is used by the reaction during its current run
if (!reactionsForKey.has(reaction)) {

@@ -33,7 +37,10 @@ reactionsForKey.add(reaction);

}
function getReactionsForOperation({
target,
key,
type
}) {
var reactionsForTarget = connectionStore.get(target);
var reactionsForKey = new Set();
function getReactionsForOperation({ target, key, type }) {
const reactionsForTarget = connectionStore.get(target);
const reactionsForKey = new Set();
if (type === 'clear') {

@@ -48,3 +55,3 @@ reactionsForTarget.forEach((_, key) => {

if (type === 'add' || type === 'delete' || type === 'clear') {
const iterationKey = Array.isArray(target) ? 'length' : ITERATION_KEY;
var iterationKey = Array.isArray(target) ? 'length' : ITERATION_KEY;
addReactionsForKey(reactionsForKey, reactionsForTarget, iterationKey);

@@ -57,3 +64,3 @@ }

function addReactionsForKey(reactionsForKey, reactionsForTarget, key) {
const reactions = reactionsForTarget.get(key);
var reactions = reactionsForTarget.get(key);
reactions && reactions.forEach(reactionsForKey.add, reactionsForKey);

@@ -66,2 +73,3 @@ }

}
reaction.cleaners = [];

@@ -74,56 +82,109 @@ }

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
// default handlers are exposed in the public API
// to allow devs to augment them instead of overwriting them
// they are frozen as they can only be used but must not be overwritten
// devs should use the setHandlers function for that
const defaultHandlers = Object.freeze({
orderReactions(reactions) {
return reactions;
},
runReaction(target, context, args) {
return Reflect.apply(target, context, args);
},
get(target, key, receiver) {
return Reflect.get(target, key, receiver);
},
has(target, key) {
return Reflect.has(target, key);
},
ownKeys(target) {
return Reflect.ownKeys(target);
},
set(target, key, value, receiver) {
return Reflect.set(target, key, value, receiver);
},
deleteProperty(target, key) {
return Reflect.deleteProperty(target, key);
return obj;
}
function ownKeys(object, enumerableOnly) {
var keys = Object.keys(object);
if (Object.getOwnPropertySymbols) {
var symbols = Object.getOwnPropertySymbols(object);
if (enumerableOnly) symbols = symbols.filter(function (sym) {
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
});
keys.push.apply(keys, symbols);
}
});
let handlers = defaultHandlers;
return keys;
}
// add the new handlers to the existing ones
function setHandlers(newHandlers) {
handlers = _extends({}, handlers, newHandlers);
function _objectSpread2(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
if (i % 2) {
ownKeys(Object(source), true).forEach(function (key) {
_defineProperty(target, key, source[key]);
});
} else if (Object.getOwnPropertyDescriptors) {
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
} else {
ownKeys(Object(source)).forEach(function (key) {
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
});
}
}
return target;
}
// reset all handlers to the default ones
function clearHandlers() {
handlers = _extends({}, defaultHandlers);
var proxyToRaw = new WeakMap();
var rawToProxy = new WeakMap(); // stores custom proxy handlers for observables
var rawToOptions = new WeakMap();
// this is a copy of the built-in Reflect object
// Reflect keys are not enumerable, so a simple { ...Reflect } spread does not work here
// we have to copy all Reflect handlers to the object instead
var proxyHandlers = Object.freeze(Object.getOwnPropertyNames(Reflect).reduce((handlers, key) => _objectSpread2(_objectSpread2({}, handlers), {}, {
[key]: Reflect[key]
}), {})); // ES6 collection method related handlers
var collectionHandlers = Object.freeze({
has: (target, ...args) => target.has(...args),
get: (target, ...args) => target.get(...args),
add: (target, ...args) => target.add(...args),
set: (target, ...args) => target.set(...args),
delete: (target, ...args) => target.delete(...args),
clear: (target, ...args) => target.clear(...args),
forEach: (target, ...args) => target.forEach(...args),
keys: (target, ...args) => target.keys(...args),
values: (target, ...args) => target.values(...args),
entries: (target, ...args) => target.entries(...args),
[Symbol.iterator]: (target, ...args) => target[Symbol.iterator](...args),
size: target => target.size
});
var reactionHandlers = Object.freeze({
// order/filter reactions triggered by an atomic observable mutation
transformReactions: (target, key, reactions) => reactions
});
var defaultHandlers = {
proxyHandlers,
collectionHandlers,
reactionHandlers
};
var runProxyHandler = (...args) => runHandler('proxyHandlers', ...args);
var runCollectionHandler = (...args) => runHandler('collectionHandlers', ...args);
var runReactionHandler = (...args) => runHandler('reactionHandlers', ...args); // runs the default or custom (user-provided) handler for the specific operation
function runHandler(handlers, name, target, ...args) {
var _options$handlers;
var options = rawToOptions.get(target);
var handler = (options === null || options === void 0 ? void 0 : (_options$handlers = options[handlers]) === null || _options$handlers === void 0 ? void 0 : _options$handlers[name]) || defaultHandlers[handlers][name];
return handler(target, ...args);
}
// reactions can call each other and form a call stack
const reactionStack = [];
let isDebugging = false;
var reactionStack = [];
var isDebugging = false;
function runAsReaction(reaction, fn, context, args) {
// do not build reactive relations, if the reaction is unobserved
if (reaction.unobserved) {
return handlers.runReaction(fn, context, args);
}
return Reflect.apply(fn, context, args);
} // only run the reaction if it is not already in the reaction stack
// TODO: improve this to allow explicitly recursive reactions
// 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) {

@@ -138,3 +199,3 @@ // release the (obj -> key -> reactions) connections

reactionStack.push(reaction);
return handlers.runReaction(fn, context, args);
return Reflect.apply(fn, context, args);
} finally {

@@ -145,8 +206,8 @@ // always remove the currently running flag from the reaction when it stops execution

}
}
} // register the currently running reaction to be queued again on obj.key mutations
// register the currently running reaction to be queued again on obj.key mutations
function registerRunningReactionForOperation(operation) {
// get the current reaction from the top of the stack
const runningReaction = reactionStack[reactionStack.length - 1];
var runningReaction = reactionStack[reactionStack.length - 1];
if (runningReaction) {

@@ -157,11 +218,13 @@ debugOperation(runningReaction, operation);

}
function queueReactionsForOperation(operation) {
// iterate and queue every reaction, which is triggered by obj.key mutation
handlers.orderReactions(getReactionsForOperation(operation)).forEach(queueReaction, operation);
var target = operation.target,
key = operation.key;
var reactions = getReactionsForOperation(operation);
runReactionHandler('transformReactions', target, key, Array.from(reactions)).forEach(queueReaction, operation);
}
function queueReaction(reaction) {
debugOperation(reaction, this);
// queue the reaction for later execution or run it immediately
debugOperation(reaction, this); // queue the reaction for later execution or run it immediately
if (typeof reaction.scheduler === 'function') {

@@ -187,25 +250,20 @@ reaction.scheduler(reaction);

function hasRunningReaction() {
return reactionStack.length > 0;
}
const IS_REACTION = Symbol('is reaction');
var IS_REACTION = Symbol('is reaction');
function observe(fn, options = {}) {
// wrap the passed function in a reaction, if it is not already one
const reaction = fn[IS_REACTION] ? fn : function reaction() {
var reaction = fn[IS_REACTION] ? fn : function reaction() {
return runAsReaction(reaction, fn, this, arguments);
};
// save the scheduler and debugger on the reaction
}; // save the scheduler and debugger on the reaction
reaction.scheduler = options.scheduler;
reaction.debugger = options.debugger;
// save the fact that this is a reaction
reaction[IS_REACTION] = true;
// run the reaction once if it is not a lazy one
reaction.debugger = options.debugger; // save the fact that this is a reaction
reaction[IS_REACTION] = true; // run the reaction once if it is not a lazy one
if (!options.lazy) {
reaction();
}
return reaction;
}
function unobserve(reaction) {

@@ -215,7 +273,8 @@ // do nothing, if the reaction is already unobserved

// indicate that the reaction should not be triggered any more
reaction.unobserved = true;
// release (obj -> key -> reaction) connections
reaction.unobserved = true; // release (obj -> key -> reaction) connections
releaseReaction(reaction);
}
// unschedule the reaction, if it is scheduled
} // unschedule the reaction, if it is scheduled
if (typeof reaction.scheduler === 'object') {

@@ -226,232 +285,305 @@ reaction.scheduler.delete(reaction);

const proxyToRaw = new WeakMap();
const rawToProxy = new WeakMap();
function patchIterator(iterator, target, isEntries) {
var originalNext = iterator.next;
const hasOwnProperty = Object.prototype.hasOwnProperty;
iterator.next = () => {
var _originalNext$call = originalNext.call(iterator),
done = _originalNext$call.done,
value = _originalNext$call.value;
function findObservable(obj) {
const observableObj = rawToProxy.get(obj);
if (hasRunningReaction() && typeof obj === 'object' && obj !== null) {
if (observableObj) {
return observableObj;
}
return observable(obj);
}
return observableObj || obj;
}
function patchIterator(iterator, isEntries) {
const originalNext = iterator.next;
iterator.next = () => {
let { done, value } = originalNext.call(iterator);
if (!done) {
if (isEntries) {
value[1] = findObservable(value[1]);
value[1] = observableChild(value[1], target);
} else {
value = findObservable(value);
value = observableChild(value, target);
}
}
return { done, value };
return {
done,
value
};
};
return iterator;
}
const instrumentations = {
var collectionHandlers$1 = {
has(key) {
const target = proxyToRaw.get(this);
const proto = Reflect.getPrototypeOf(this);
registerRunningReactionForOperation({ target, key, type: 'has' });
return proto.has.apply(target, arguments);
var target = proxyToRaw.get(this);
registerRunningReactionForOperation({
target,
key,
type: 'has'
});
return runCollectionHandler('has', target, ...arguments);
},
get(key) {
const target = proxyToRaw.get(this);
const proto = Reflect.getPrototypeOf(this);
registerRunningReactionForOperation({ target, key, type: 'get' });
return findObservable(proto.get.apply(target, arguments));
var target = proxyToRaw.get(this);
registerRunningReactionForOperation({
target,
key,
type: 'get'
});
return observableChild(runCollectionHandler('get', target, ...arguments), target);
},
add(key) {
const target = proxyToRaw.get(this);
const proto = Reflect.getPrototypeOf(this);
const hadKey = proto.has.call(target, key);
// forward the operation before queueing reactions
const result = proto.add.apply(target, arguments);
var target = proxyToRaw.get(this);
var hadKey = target.has(key); // forward the operation before queueing reactions
var result = runCollectionHandler('add', target, ...arguments);
if (!hadKey) {
queueReactionsForOperation({ target, key, value: key, type: 'add' });
queueReactionsForOperation({
target,
key,
value: key,
type: 'add'
});
}
return result;
},
set(key, value) {
const target = proxyToRaw.get(this);
const proto = Reflect.getPrototypeOf(this);
const hadKey = proto.has.call(target, key);
const oldValue = proto.get.call(target, key);
// forward the operation before queueing reactions
const result = proto.set.apply(target, arguments);
var target = proxyToRaw.get(this);
var hadKey = target.has(key);
var oldValue = target.get(key); // forward the operation before queueing reactions
var result = runCollectionHandler('set', target, ...arguments);
if (!hadKey) {
queueReactionsForOperation({ target, key, value, type: 'add' });
queueReactionsForOperation({
target,
key,
value,
type: 'add'
});
} else if (value !== oldValue) {
queueReactionsForOperation({ target, key, value, oldValue, type: 'set' });
queueReactionsForOperation({
target,
key,
value,
oldValue,
type: 'set'
});
}
return result;
},
delete(key) {
const target = proxyToRaw.get(this);
const proto = Reflect.getPrototypeOf(this);
const hadKey = proto.has.call(target, key);
const oldValue = proto.get ? proto.get.call(target, key) : undefined;
// forward the operation before queueing reactions
const result = proto.delete.apply(target, arguments);
var target = proxyToRaw.get(this);
var hadKey = target.has(key);
var oldValue = target.get ? target.get(key) : undefined; // forward the operation before queueing reactions
var result = runCollectionHandler('delete', target, ...arguments);
if (hadKey) {
queueReactionsForOperation({ target, key, oldValue, type: 'delete' });
queueReactionsForOperation({
target,
key,
oldValue,
type: 'delete'
});
}
return result;
},
clear() {
const target = proxyToRaw.get(this);
const proto = Reflect.getPrototypeOf(this);
const hadItems = target.size !== 0;
const oldTarget = target instanceof Map ? new Map(target) : new Set(target);
// forward the operation before queueing reactions
const result = proto.clear.apply(target, arguments);
var target = proxyToRaw.get(this);
var hadItems = target.size !== 0;
var oldTarget = target instanceof Map ? new Map(target) : new Set(target); // forward the operation before queueing reactions
var result = runCollectionHandler('clear', target, ...arguments);
if (hadItems) {
queueReactionsForOperation({ target, oldTarget, type: 'clear' });
queueReactionsForOperation({
target,
oldTarget,
type: 'clear'
});
}
return result;
},
forEach(cb, ...args) {
const target = proxyToRaw.get(this);
const proto = Reflect.getPrototypeOf(this);
registerRunningReactionForOperation({ target, type: 'iterate' });
// swap out the raw values with their observable pairs
forEach(callback, ...args) {
var target = proxyToRaw.get(this);
registerRunningReactionForOperation({
target,
type: 'iterate'
}); // swap out the raw values with their observable pairs
// before passing them to the callback
const wrappedCb = (value, ...rest) => cb(findObservable(value), ...rest);
return proto.forEach.call(target, wrappedCb, ...args);
var wrappedCallback = (value, ...rest) => callback(observableChild(value, target), ...rest);
return runCollectionHandler('forEach', target, wrappedCallback, ...args);
},
keys() {
const target = proxyToRaw.get(this);
const proto = Reflect.getPrototypeOf(this);
registerRunningReactionForOperation({ target, type: 'iterate' });
return proto.keys.apply(target, arguments);
var target = proxyToRaw.get(this);
registerRunningReactionForOperation({
target,
type: 'iterate'
}); // TODO: no need to patch this?
return runCollectionHandler('keys', target, ...arguments);
},
values() {
const target = proxyToRaw.get(this);
const proto = Reflect.getPrototypeOf(this);
registerRunningReactionForOperation({ target, type: 'iterate' });
const iterator = proto.values.apply(target, arguments);
return patchIterator(iterator, false);
var target = proxyToRaw.get(this);
registerRunningReactionForOperation({
target,
type: 'iterate'
});
var iterator = runCollectionHandler('values', target, ...arguments);
return patchIterator(iterator, target, false);
},
entries() {
const target = proxyToRaw.get(this);
const proto = Reflect.getPrototypeOf(this);
registerRunningReactionForOperation({ target, type: 'iterate' });
const iterator = proto.entries.apply(target, arguments);
return patchIterator(iterator, true);
var target = proxyToRaw.get(this);
registerRunningReactionForOperation({
target,
type: 'iterate'
});
var iterator = runCollectionHandler('entries', target, ...arguments);
return patchIterator(iterator, target, true);
},
[Symbol.iterator]() {
const target = proxyToRaw.get(this);
const proto = Reflect.getPrototypeOf(this);
registerRunningReactionForOperation({ target, type: 'iterate' });
const iterator = proto[Symbol.iterator].apply(target, arguments);
return patchIterator(iterator, target instanceof Map);
var target = proxyToRaw.get(this);
registerRunningReactionForOperation({
target,
type: 'iterate'
});
var iterator = runCollectionHandler(Symbol.iterator, target, ...arguments);
return patchIterator(iterator, target, target instanceof Map);
},
get size() {
const target = proxyToRaw.get(this);
const proto = Reflect.getPrototypeOf(this);
registerRunningReactionForOperation({ target, type: 'iterate' });
return Reflect.get(proto, 'size', target);
var target = proxyToRaw.get(this);
registerRunningReactionForOperation({
target,
type: 'iterate'
});
return runCollectionHandler('size', target);
}
};
var collectionHandlers = {
var collectionHandlers$2 = {
get(target, key, receiver) {
// instrument methods and property accessors to be reactive
target = hasOwnProperty.call(instrumentations, key) ? instrumentations : target;
// eslint-disable-next-line no-prototype-builtins
target = collectionHandlers$1.hasOwnProperty(key) ? collectionHandlers$1 : target;
return Reflect.get(target, key, receiver);
}
};
const globalObj =
// eslint-disable-next-line
typeof window === "object" ? window : Function("return this")();
var globalObj = // eslint-disable-next-line no-new-func
typeof window === 'object' ? window : Function('return this')(); // these stateful built-in objects can and should be wrapped by Proxies if they are part of a store
// simple ones - like arrays - ar wrapped with the normal observable Proxy
// complex ones - like Map and Set - are wrapped with a Proxy of instrumented methods
// built-in object can not be wrapped by Proxies
// their methods expect the object instance as the 'this' instead of the Proxy wrapper
// complex objects are wrapped with a Proxy of instrumented methods
// which switch the proxy to the raw object and to add reactive wiring
const handlers$1 = new Map([[Map, collectionHandlers], [Set, collectionHandlers], [WeakMap, collectionHandlers], [WeakSet, collectionHandlers], [Object, false], [Array, false], [Int8Array, false], [Uint8Array, false], [Uint8ClampedArray, false], [Int16Array, false], [Uint16Array, false], [Int32Array, false], [Uint32Array, false], [Float32Array, false], [Float64Array, false]]);
var handlers = new Map([[Map, collectionHandlers$2], [Set, collectionHandlers$2], [WeakMap, collectionHandlers$2], [WeakSet, collectionHandlers$2], [Object, false], [Array, false], [Int8Array, false], [Uint8Array, false], [Uint8ClampedArray, false], [Int16Array, false], [Uint16Array, false], [Int32Array, false], [Uint32Array, false], [Float32Array, false], [Float64Array, false]]); // some (usually stateless) built-in objects can not be and should not be wrapped by Proxies
// their methods expect the object instance as the receiver ('this') instead of the Proxy wrapper
// wrapping them and calling their methods causes erros like: "TypeError: this is not a Date object."
function shouldInstrument({ constructor }) {
const isBuiltIn = typeof constructor === 'function' && constructor.name in globalObj && globalObj[constructor.name] === constructor;
return !isBuiltIn || handlers$1.has(constructor);
function shouldInstrument(obj) {
var constructor = obj.constructor; // functions and objects in the above handlers array are safe to instrument
if (typeof obj === 'function' || handlers.has(constructor)) {
return true;
} // other built-in objects should not be implemented
var isBuiltIn = typeof constructor === 'function' && constructor.name in globalObj && globalObj[constructor.name] === constructor;
return !isBuiltIn;
}
function getHandlers(obj) {
return handlers$1.get(obj.constructor);
return handlers.get(obj.constructor);
}
var _extends$1 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var hasOwnProperty = Object.prototype.hasOwnProperty;
var wellKnownSymbols = new Set(Object.getOwnPropertyNames(Symbol).map(key => Symbol[key]).filter(value => typeof value === 'symbol')); // intercept get operations on observables to know which reaction uses their properties
const hasOwnProperty$1 = Object.prototype.hasOwnProperty;
const wellKnownSymbols = new Set(Object.getOwnPropertyNames(Symbol).map(key => Symbol[key]).filter(value => typeof value === 'symbol'));
// intercept get operations on observables to know which reaction uses their properties
function get(target, key, receiver) {
const result = handlers.get(target, key, receiver);
// do not register (observable.prop -> reaction) pairs for well known symbols
var result = runProxyHandler('get', target, key, receiver); // 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;
}
// register and save (observable.prop -> runningReaction)
registerRunningReactionForOperation({ target, key, receiver, type: 'get' });
// if we are inside a reaction and observable.prop is an object wrap it in an observable too
// this is needed to intercept property access on that object too (dynamic observable tree)
const observableResult = rawToProxy.get(result);
if (hasRunningReaction() && typeof result === 'object' && result !== null) {
if (observableResult) {
return observableResult;
}
// do not violate the none-configurable none-writable prop get handler invariant
// fall back to none reactive mode in this case, instead of letting the Proxy throw a TypeError
const descriptor = Reflect.getOwnPropertyDescriptor(target, key);
if (!descriptor || !(descriptor.writable === false && descriptor.configurable === false)) {
return observable(result);
}
}
// otherwise return the observable wrapper if it is already created and cached or the raw object
return observableResult || result;
} // register and save the (observable.prop -> runningReaction) relation
registerRunningReactionForOperation({
target,
key,
receiver,
type: 'get'
}); // do not violate the none-configurable none-writable prop get handler invariant
// fall back to none reactive mode in this case, instead of letting the Proxy throw a TypeError
var descriptor = Reflect.getOwnPropertyDescriptor(target, key);
if (descriptor && descriptor.writable === false && descriptor.configurable === false) {
return result;
} // otherwise return the observable wrapper if it is already created and cached or the raw object
return observableChild(result, target);
}
function has(target, key) {
const result = handlers.has(target, key);
// register and save (observable.prop -> runningReaction)
registerRunningReactionForOperation({ target, key, type: 'has' });
var result = runProxyHandler('has', target, key); // register and save (observable.prop -> runningReaction)
registerRunningReactionForOperation({
target,
key,
type: 'has'
});
return result;
}
function ownKeys(target) {
registerRunningReactionForOperation({ target, type: 'iterate' });
return handlers.ownKeys(target);
}
function ownKeys$1(target) {
registerRunningReactionForOperation({
target,
type: 'iterate'
});
return runProxyHandler('ownKeys', target);
} // intercept set operations on observables to know when to trigger reactions
// intercept set operations on observables to know when to trigger reactions
function set(target, key, value, receiver) {
// make sure to do not pollute the raw object with observables
if (typeof value === 'object' && value !== null) {
value = proxyToRaw.get(value) || value;
}
// save if the object had a descriptor for this key
const hadKey = hasOwnProperty$1.call(target, key);
// save if the value changed because of this set operation
const oldValue = target[key];
// execute the set operation before running any reaction
const result = handlers.set(target, key, value, receiver);
// do not queue reactions if the target of the operation is not the raw receiver
// (possible because of prototypal inheritance)
value = proxyToRaw.get(value) || value; // save if the object had a descriptor for this key
var hadKey = hasOwnProperty.call(target, key); // save if the value changed because of this set operation
var oldValue = target[key]; // execute the set operation before running any reaction
var result = runProxyHandler('set', target, key, value, receiver); // do not queue reactions if the target of the operation is not the raw receiver
// this possible because of prototypal inheritance
// when the prototype has a setter the set operation traverses the whole prototype chain
// and calls the set trap on every object until it finds the setter
// this is undesired, it is enough for us to trigger the reactions in the set trap of
// the receiver (child) object to avoid duplicate reactions
if (target !== proxyToRaw.get(receiver)) {
return result;
}
// queue a reaction if it's a new property or its value changed
} // queue a reaction if it's a new property or its value changed
if (!hadKey) {
queueReactionsForOperation({ target, key, value, receiver, type: 'add' });
queueReactionsForOperation({
target,
key,
value,
receiver,
type: 'add'
});
} else if (value !== oldValue) {

@@ -467,2 +599,3 @@ queueReactionsForOperation({

}
return result;

@@ -473,44 +606,76 @@ }

// save if the object had the key
const hadKey = hasOwnProperty$1.call(target, key);
const oldValue = target[key];
// execute the delete operation before running any reaction
const result = handlers.deleteProperty(target, key);
// only queue reactions for delete operations which resulted in an actual change
var hadKey = hasOwnProperty.call(target, key);
var oldValue = target[key]; // execute the delete operation before running any reaction
var result = runProxyHandler('deleteProperty', target, key); // only queue reactions for delete operations which resulted in an actual change
if (hadKey) {
queueReactionsForOperation({ target, key, oldValue, type: 'delete' });
queueReactionsForOperation({
target,
key,
oldValue,
type: 'delete'
});
}
return result;
} // return an observable object instance when an observable class is instantiated
function construct(target, args, newTarget) {
return observable(runProxyHandler('construct', target, args, newTarget));
}
// allow custom handlers for proxy traps that this lib does not use
// this prevents the need for double Proxy wrapping for users
// who wish to further extend JS behavior with Proxy traps
var baseHandlers = _extends$1({}, handlers, { get, has, ownKeys, set, deleteProperty });
var proxyHandlers$1 = {
get,
has,
ownKeys: ownKeys$1,
set,
deleteProperty,
construct
};
function observable(obj = {}) {
function observable(obj = {}, options) {
// if it is already an observable or it should not be wrapped, return it
if (proxyToRaw.has(obj) || !shouldInstrument(obj)) {
return obj;
}
// if it already has a cached observable wrapper, return it
} // if it already has a cached observable wrapper, return it
// otherwise create a new observable
return rawToProxy.get(obj) || createObservable(obj);
return rawToProxy.get(obj) || createObservable(obj, options);
}
function createObservable(obj) {
function createObservable(obj, options) {
// if it is a complex built-in object or a normal object, wrap it
const handlers = getHandlers(obj) || baseHandlers;
const observable = new Proxy(obj, handlers);
// save these to switch between the raw object and the wrapped object with ease later
var baseHandlers = getHandlers(obj) || proxyHandlers$1;
var observable = new Proxy(obj, _objectSpread2(_objectSpread2({}, options === null || options === void 0 ? void 0 : options.proxyHandlers), baseHandlers)); // save these to switch between the raw object and the wrapped object with ease later
rawToProxy.set(obj, observable);
proxyToRaw.set(observable, obj);
// init basic data structures to save and cleanup later (observable.prop -> reaction) connections
proxyToRaw.set(observable, obj); // add custom options to the raw object
if (options) {
rawToOptions.set(obj, options);
} // init basic data structures to save and cleanup later (observable.prop -> reaction) connections
storeObservable(obj);
return observable;
} // if observable.prop is an object, wrap it in an observable too
// this is needed to intercept property access on that object too
function observableChild(child, parent) {
if (typeof child === 'object' && child !== null || typeof child === 'function') {
// pass the parent's options to the child object
// this creates a 'deep proxy' which shares custom handlers deeply with its object children
var options = rawToOptions.get(parent);
return observable(child, options);
}
return child;
}
function isObservable(obj) {
return proxyToRaw.has(obj);
}
function raw(obj) {

@@ -520,9 +685,9 @@ return proxyToRaw.get(obj) || obj;

exports.collectionHandlers = collectionHandlers;
exports.isObservable = isObservable;
exports.observable = observable;
exports.observe = observe;
exports.proxyHandlers = proxyHandlers;
exports.raw = raw;
exports.reactionHandlers = reactionHandlers;
exports.unobserve = unobserve;
exports.observable = observable;
exports.isObservable = isObservable;
exports.raw = raw;
exports.setHandlers = setHandlers;
exports.clearHandlers = clearHandlers;
exports.defaultHandlers = defaultHandlers;

@@ -1,4 +0,3 @@

const connectionStore = new WeakMap();
const ITERATION_KEY = Symbol('iteration key');
var connectionStore = new WeakMap();
var ITERATION_KEY = Symbol('iteration key');
function storeObservable(obj) {

@@ -8,4 +7,7 @@ // this will be used to save (obj.key -> reaction) connections later

}
function registerReactionForOperation(reaction, { target, key, type }) {
function registerReactionForOperation(reaction, {
target,
key,
type
}) {
if (type === 'iterate') {

@@ -15,9 +17,11 @@ key = ITERATION_KEY;

const reactionsForObj = connectionStore.get(target);
let reactionsForKey = reactionsForObj.get(key);
var reactionsForObj = connectionStore.get(target);
var reactionsForKey = reactionsForObj.get(key);
if (!reactionsForKey) {
reactionsForKey = new Set();
reactionsForObj.set(key, reactionsForKey);
}
// save the fact that the key is used by the reaction during its current run
} // save the fact that the key is used by the reaction during its current run
if (!reactionsForKey.has(reaction)) {

@@ -28,7 +32,10 @@ reactionsForKey.add(reaction);

}
function getReactionsForOperation({
target,
key,
type
}) {
var reactionsForTarget = connectionStore.get(target);
var reactionsForKey = new Set();
function getReactionsForOperation({ target, key, type }) {
const reactionsForTarget = connectionStore.get(target);
const reactionsForKey = new Set();
if (type === 'clear') {

@@ -43,3 +50,3 @@ reactionsForTarget.forEach((_, key) => {

if (type === 'add' || type === 'delete' || type === 'clear') {
const iterationKey = Array.isArray(target) ? 'length' : ITERATION_KEY;
var iterationKey = Array.isArray(target) ? 'length' : ITERATION_KEY;
addReactionsForKey(reactionsForKey, reactionsForTarget, iterationKey);

@@ -52,3 +59,3 @@ }

function addReactionsForKey(reactionsForKey, reactionsForTarget, key) {
const reactions = reactionsForTarget.get(key);
var reactions = reactionsForTarget.get(key);
reactions && reactions.forEach(reactionsForKey.add, reactionsForKey);

@@ -61,2 +68,3 @@ }

}
reaction.cleaners = [];

@@ -69,56 +77,109 @@ }

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
// default handlers are exposed in the public API
// to allow devs to augment them instead of overwriting them
// they are frozen as they can only be used but must not be overwritten
// devs should use the setHandlers function for that
const defaultHandlers = Object.freeze({
orderReactions(reactions) {
return reactions;
},
runReaction(target, context, args) {
return Reflect.apply(target, context, args);
},
get(target, key, receiver) {
return Reflect.get(target, key, receiver);
},
has(target, key) {
return Reflect.has(target, key);
},
ownKeys(target) {
return Reflect.ownKeys(target);
},
set(target, key, value, receiver) {
return Reflect.set(target, key, value, receiver);
},
deleteProperty(target, key) {
return Reflect.deleteProperty(target, key);
return obj;
}
function ownKeys(object, enumerableOnly) {
var keys = Object.keys(object);
if (Object.getOwnPropertySymbols) {
var symbols = Object.getOwnPropertySymbols(object);
if (enumerableOnly) symbols = symbols.filter(function (sym) {
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
});
keys.push.apply(keys, symbols);
}
});
let handlers = defaultHandlers;
return keys;
}
// add the new handlers to the existing ones
function setHandlers(newHandlers) {
handlers = _extends({}, handlers, newHandlers);
function _objectSpread2(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
if (i % 2) {
ownKeys(Object(source), true).forEach(function (key) {
_defineProperty(target, key, source[key]);
});
} else if (Object.getOwnPropertyDescriptors) {
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
} else {
ownKeys(Object(source)).forEach(function (key) {
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
});
}
}
return target;
}
// reset all handlers to the default ones
function clearHandlers() {
handlers = _extends({}, defaultHandlers);
var proxyToRaw = new WeakMap();
var rawToProxy = new WeakMap(); // stores custom proxy handlers for observables
var rawToOptions = new WeakMap();
// this is a copy of the built-in Reflect object
// Reflect keys are not enumerable, so a simple { ...Reflect } spread does not work here
// we have to copy all Reflect handlers to the object instead
var proxyHandlers = Object.freeze(Object.getOwnPropertyNames(Reflect).reduce((handlers, key) => _objectSpread2(_objectSpread2({}, handlers), {}, {
[key]: Reflect[key]
}), {})); // ES6 collection method related handlers
var collectionHandlers = Object.freeze({
has: (target, ...args) => target.has(...args),
get: (target, ...args) => target.get(...args),
add: (target, ...args) => target.add(...args),
set: (target, ...args) => target.set(...args),
delete: (target, ...args) => target.delete(...args),
clear: (target, ...args) => target.clear(...args),
forEach: (target, ...args) => target.forEach(...args),
keys: (target, ...args) => target.keys(...args),
values: (target, ...args) => target.values(...args),
entries: (target, ...args) => target.entries(...args),
[Symbol.iterator]: (target, ...args) => target[Symbol.iterator](...args),
size: target => target.size
});
var reactionHandlers = Object.freeze({
// order/filter reactions triggered by an atomic observable mutation
transformReactions: (target, key, reactions) => reactions
});
var defaultHandlers = {
proxyHandlers,
collectionHandlers,
reactionHandlers
};
var runProxyHandler = (...args) => runHandler('proxyHandlers', ...args);
var runCollectionHandler = (...args) => runHandler('collectionHandlers', ...args);
var runReactionHandler = (...args) => runHandler('reactionHandlers', ...args); // runs the default or custom (user-provided) handler for the specific operation
function runHandler(handlers, name, target, ...args) {
var _options$handlers;
var options = rawToOptions.get(target);
var handler = (options === null || options === void 0 ? void 0 : (_options$handlers = options[handlers]) === null || _options$handlers === void 0 ? void 0 : _options$handlers[name]) || defaultHandlers[handlers][name];
return handler(target, ...args);
}
// reactions can call each other and form a call stack
const reactionStack = [];
let isDebugging = false;
var reactionStack = [];
var isDebugging = false;
function runAsReaction(reaction, fn, context, args) {
// do not build reactive relations, if the reaction is unobserved
if (reaction.unobserved) {
return handlers.runReaction(fn, context, args);
}
return Reflect.apply(fn, context, args);
} // only run the reaction if it is not already in the reaction stack
// TODO: improve this to allow explicitly recursive reactions
// 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) {

@@ -133,3 +194,3 @@ // release the (obj -> key -> reactions) connections

reactionStack.push(reaction);
return handlers.runReaction(fn, context, args);
return Reflect.apply(fn, context, args);
} finally {

@@ -140,8 +201,8 @@ // always remove the currently running flag from the reaction when it stops execution

}
}
} // register the currently running reaction to be queued again on obj.key mutations
// register the currently running reaction to be queued again on obj.key mutations
function registerRunningReactionForOperation(operation) {
// get the current reaction from the top of the stack
const runningReaction = reactionStack[reactionStack.length - 1];
var runningReaction = reactionStack[reactionStack.length - 1];
if (runningReaction) {

@@ -152,11 +213,13 @@ debugOperation(runningReaction, operation);

}
function queueReactionsForOperation(operation) {
// iterate and queue every reaction, which is triggered by obj.key mutation
handlers.orderReactions(getReactionsForOperation(operation)).forEach(queueReaction, operation);
var target = operation.target,
key = operation.key;
var reactions = getReactionsForOperation(operation);
runReactionHandler('transformReactions', target, key, Array.from(reactions)).forEach(queueReaction, operation);
}
function queueReaction(reaction) {
debugOperation(reaction, this);
// queue the reaction for later execution or run it immediately
debugOperation(reaction, this); // queue the reaction for later execution or run it immediately
if (typeof reaction.scheduler === 'function') {

@@ -182,25 +245,20 @@ reaction.scheduler(reaction);

function hasRunningReaction() {
return reactionStack.length > 0;
}
const IS_REACTION = Symbol('is reaction');
var IS_REACTION = Symbol('is reaction');
function observe(fn, options = {}) {
// wrap the passed function in a reaction, if it is not already one
const reaction = fn[IS_REACTION] ? fn : function reaction() {
var reaction = fn[IS_REACTION] ? fn : function reaction() {
return runAsReaction(reaction, fn, this, arguments);
};
// save the scheduler and debugger on the reaction
}; // save the scheduler and debugger on the reaction
reaction.scheduler = options.scheduler;
reaction.debugger = options.debugger;
// save the fact that this is a reaction
reaction[IS_REACTION] = true;
// run the reaction once if it is not a lazy one
reaction.debugger = options.debugger; // save the fact that this is a reaction
reaction[IS_REACTION] = true; // run the reaction once if it is not a lazy one
if (!options.lazy) {
reaction();
}
return reaction;
}
function unobserve(reaction) {

@@ -210,7 +268,8 @@ // do nothing, if the reaction is already unobserved

// indicate that the reaction should not be triggered any more
reaction.unobserved = true;
// release (obj -> key -> reaction) connections
reaction.unobserved = true; // release (obj -> key -> reaction) connections
releaseReaction(reaction);
}
// unschedule the reaction, if it is scheduled
} // unschedule the reaction, if it is scheduled
if (typeof reaction.scheduler === 'object') {

@@ -221,232 +280,305 @@ reaction.scheduler.delete(reaction);

const proxyToRaw = new WeakMap();
const rawToProxy = new WeakMap();
function patchIterator(iterator, target, isEntries) {
var originalNext = iterator.next;
const hasOwnProperty = Object.prototype.hasOwnProperty;
iterator.next = () => {
var _originalNext$call = originalNext.call(iterator),
done = _originalNext$call.done,
value = _originalNext$call.value;
function findObservable(obj) {
const observableObj = rawToProxy.get(obj);
if (hasRunningReaction() && typeof obj === 'object' && obj !== null) {
if (observableObj) {
return observableObj;
}
return observable(obj);
}
return observableObj || obj;
}
function patchIterator(iterator, isEntries) {
const originalNext = iterator.next;
iterator.next = () => {
let { done, value } = originalNext.call(iterator);
if (!done) {
if (isEntries) {
value[1] = findObservable(value[1]);
value[1] = observableChild(value[1], target);
} else {
value = findObservable(value);
value = observableChild(value, target);
}
}
return { done, value };
return {
done,
value
};
};
return iterator;
}
const instrumentations = {
var collectionHandlers$1 = {
has(key) {
const target = proxyToRaw.get(this);
const proto = Reflect.getPrototypeOf(this);
registerRunningReactionForOperation({ target, key, type: 'has' });
return proto.has.apply(target, arguments);
var target = proxyToRaw.get(this);
registerRunningReactionForOperation({
target,
key,
type: 'has'
});
return runCollectionHandler('has', target, ...arguments);
},
get(key) {
const target = proxyToRaw.get(this);
const proto = Reflect.getPrototypeOf(this);
registerRunningReactionForOperation({ target, key, type: 'get' });
return findObservable(proto.get.apply(target, arguments));
var target = proxyToRaw.get(this);
registerRunningReactionForOperation({
target,
key,
type: 'get'
});
return observableChild(runCollectionHandler('get', target, ...arguments), target);
},
add(key) {
const target = proxyToRaw.get(this);
const proto = Reflect.getPrototypeOf(this);
const hadKey = proto.has.call(target, key);
// forward the operation before queueing reactions
const result = proto.add.apply(target, arguments);
var target = proxyToRaw.get(this);
var hadKey = target.has(key); // forward the operation before queueing reactions
var result = runCollectionHandler('add', target, ...arguments);
if (!hadKey) {
queueReactionsForOperation({ target, key, value: key, type: 'add' });
queueReactionsForOperation({
target,
key,
value: key,
type: 'add'
});
}
return result;
},
set(key, value) {
const target = proxyToRaw.get(this);
const proto = Reflect.getPrototypeOf(this);
const hadKey = proto.has.call(target, key);
const oldValue = proto.get.call(target, key);
// forward the operation before queueing reactions
const result = proto.set.apply(target, arguments);
var target = proxyToRaw.get(this);
var hadKey = target.has(key);
var oldValue = target.get(key); // forward the operation before queueing reactions
var result = runCollectionHandler('set', target, ...arguments);
if (!hadKey) {
queueReactionsForOperation({ target, key, value, type: 'add' });
queueReactionsForOperation({
target,
key,
value,
type: 'add'
});
} else if (value !== oldValue) {
queueReactionsForOperation({ target, key, value, oldValue, type: 'set' });
queueReactionsForOperation({
target,
key,
value,
oldValue,
type: 'set'
});
}
return result;
},
delete(key) {
const target = proxyToRaw.get(this);
const proto = Reflect.getPrototypeOf(this);
const hadKey = proto.has.call(target, key);
const oldValue = proto.get ? proto.get.call(target, key) : undefined;
// forward the operation before queueing reactions
const result = proto.delete.apply(target, arguments);
var target = proxyToRaw.get(this);
var hadKey = target.has(key);
var oldValue = target.get ? target.get(key) : undefined; // forward the operation before queueing reactions
var result = runCollectionHandler('delete', target, ...arguments);
if (hadKey) {
queueReactionsForOperation({ target, key, oldValue, type: 'delete' });
queueReactionsForOperation({
target,
key,
oldValue,
type: 'delete'
});
}
return result;
},
clear() {
const target = proxyToRaw.get(this);
const proto = Reflect.getPrototypeOf(this);
const hadItems = target.size !== 0;
const oldTarget = target instanceof Map ? new Map(target) : new Set(target);
// forward the operation before queueing reactions
const result = proto.clear.apply(target, arguments);
var target = proxyToRaw.get(this);
var hadItems = target.size !== 0;
var oldTarget = target instanceof Map ? new Map(target) : new Set(target); // forward the operation before queueing reactions
var result = runCollectionHandler('clear', target, ...arguments);
if (hadItems) {
queueReactionsForOperation({ target, oldTarget, type: 'clear' });
queueReactionsForOperation({
target,
oldTarget,
type: 'clear'
});
}
return result;
},
forEach(cb, ...args) {
const target = proxyToRaw.get(this);
const proto = Reflect.getPrototypeOf(this);
registerRunningReactionForOperation({ target, type: 'iterate' });
// swap out the raw values with their observable pairs
forEach(callback, ...args) {
var target = proxyToRaw.get(this);
registerRunningReactionForOperation({
target,
type: 'iterate'
}); // swap out the raw values with their observable pairs
// before passing them to the callback
const wrappedCb = (value, ...rest) => cb(findObservable(value), ...rest);
return proto.forEach.call(target, wrappedCb, ...args);
var wrappedCallback = (value, ...rest) => callback(observableChild(value, target), ...rest);
return runCollectionHandler('forEach', target, wrappedCallback, ...args);
},
keys() {
const target = proxyToRaw.get(this);
const proto = Reflect.getPrototypeOf(this);
registerRunningReactionForOperation({ target, type: 'iterate' });
return proto.keys.apply(target, arguments);
var target = proxyToRaw.get(this);
registerRunningReactionForOperation({
target,
type: 'iterate'
}); // TODO: no need to patch this?
return runCollectionHandler('keys', target, ...arguments);
},
values() {
const target = proxyToRaw.get(this);
const proto = Reflect.getPrototypeOf(this);
registerRunningReactionForOperation({ target, type: 'iterate' });
const iterator = proto.values.apply(target, arguments);
return patchIterator(iterator, false);
var target = proxyToRaw.get(this);
registerRunningReactionForOperation({
target,
type: 'iterate'
});
var iterator = runCollectionHandler('values', target, ...arguments);
return patchIterator(iterator, target, false);
},
entries() {
const target = proxyToRaw.get(this);
const proto = Reflect.getPrototypeOf(this);
registerRunningReactionForOperation({ target, type: 'iterate' });
const iterator = proto.entries.apply(target, arguments);
return patchIterator(iterator, true);
var target = proxyToRaw.get(this);
registerRunningReactionForOperation({
target,
type: 'iterate'
});
var iterator = runCollectionHandler('entries', target, ...arguments);
return patchIterator(iterator, target, true);
},
[Symbol.iterator]() {
const target = proxyToRaw.get(this);
const proto = Reflect.getPrototypeOf(this);
registerRunningReactionForOperation({ target, type: 'iterate' });
const iterator = proto[Symbol.iterator].apply(target, arguments);
return patchIterator(iterator, target instanceof Map);
var target = proxyToRaw.get(this);
registerRunningReactionForOperation({
target,
type: 'iterate'
});
var iterator = runCollectionHandler(Symbol.iterator, target, ...arguments);
return patchIterator(iterator, target, target instanceof Map);
},
get size() {
const target = proxyToRaw.get(this);
const proto = Reflect.getPrototypeOf(this);
registerRunningReactionForOperation({ target, type: 'iterate' });
return Reflect.get(proto, 'size', target);
var target = proxyToRaw.get(this);
registerRunningReactionForOperation({
target,
type: 'iterate'
});
return runCollectionHandler('size', target);
}
};
var collectionHandlers = {
var collectionHandlers$2 = {
get(target, key, receiver) {
// instrument methods and property accessors to be reactive
target = hasOwnProperty.call(instrumentations, key) ? instrumentations : target;
// eslint-disable-next-line no-prototype-builtins
target = collectionHandlers$1.hasOwnProperty(key) ? collectionHandlers$1 : target;
return Reflect.get(target, key, receiver);
}
};
const globalObj =
// eslint-disable-next-line
typeof window === "object" ? window : Function("return this")();
var globalObj = // eslint-disable-next-line no-new-func
typeof window === 'object' ? window : Function('return this')(); // these stateful built-in objects can and should be wrapped by Proxies if they are part of a store
// simple ones - like arrays - ar wrapped with the normal observable Proxy
// complex ones - like Map and Set - are wrapped with a Proxy of instrumented methods
// built-in object can not be wrapped by Proxies
// their methods expect the object instance as the 'this' instead of the Proxy wrapper
// complex objects are wrapped with a Proxy of instrumented methods
// which switch the proxy to the raw object and to add reactive wiring
const handlers$1 = new Map([[Map, collectionHandlers], [Set, collectionHandlers], [WeakMap, collectionHandlers], [WeakSet, collectionHandlers], [Object, false], [Array, false], [Int8Array, false], [Uint8Array, false], [Uint8ClampedArray, false], [Int16Array, false], [Uint16Array, false], [Int32Array, false], [Uint32Array, false], [Float32Array, false], [Float64Array, false]]);
var handlers = new Map([[Map, collectionHandlers$2], [Set, collectionHandlers$2], [WeakMap, collectionHandlers$2], [WeakSet, collectionHandlers$2], [Object, false], [Array, false], [Int8Array, false], [Uint8Array, false], [Uint8ClampedArray, false], [Int16Array, false], [Uint16Array, false], [Int32Array, false], [Uint32Array, false], [Float32Array, false], [Float64Array, false]]); // some (usually stateless) built-in objects can not be and should not be wrapped by Proxies
// their methods expect the object instance as the receiver ('this') instead of the Proxy wrapper
// wrapping them and calling their methods causes erros like: "TypeError: this is not a Date object."
function shouldInstrument({ constructor }) {
const isBuiltIn = typeof constructor === 'function' && constructor.name in globalObj && globalObj[constructor.name] === constructor;
return !isBuiltIn || handlers$1.has(constructor);
function shouldInstrument(obj) {
var constructor = obj.constructor; // functions and objects in the above handlers array are safe to instrument
if (typeof obj === 'function' || handlers.has(constructor)) {
return true;
} // other built-in objects should not be implemented
var isBuiltIn = typeof constructor === 'function' && constructor.name in globalObj && globalObj[constructor.name] === constructor;
return !isBuiltIn;
}
function getHandlers(obj) {
return handlers$1.get(obj.constructor);
return handlers.get(obj.constructor);
}
var _extends$1 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var hasOwnProperty = Object.prototype.hasOwnProperty;
var wellKnownSymbols = new Set(Object.getOwnPropertyNames(Symbol).map(key => Symbol[key]).filter(value => typeof value === 'symbol')); // intercept get operations on observables to know which reaction uses their properties
const hasOwnProperty$1 = Object.prototype.hasOwnProperty;
const wellKnownSymbols = new Set(Object.getOwnPropertyNames(Symbol).map(key => Symbol[key]).filter(value => typeof value === 'symbol'));
// intercept get operations on observables to know which reaction uses their properties
function get(target, key, receiver) {
const result = handlers.get(target, key, receiver);
// do not register (observable.prop -> reaction) pairs for well known symbols
var result = runProxyHandler('get', target, key, receiver); // 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;
}
// register and save (observable.prop -> runningReaction)
registerRunningReactionForOperation({ target, key, receiver, type: 'get' });
// if we are inside a reaction and observable.prop is an object wrap it in an observable too
// this is needed to intercept property access on that object too (dynamic observable tree)
const observableResult = rawToProxy.get(result);
if (hasRunningReaction() && typeof result === 'object' && result !== null) {
if (observableResult) {
return observableResult;
}
// do not violate the none-configurable none-writable prop get handler invariant
// fall back to none reactive mode in this case, instead of letting the Proxy throw a TypeError
const descriptor = Reflect.getOwnPropertyDescriptor(target, key);
if (!descriptor || !(descriptor.writable === false && descriptor.configurable === false)) {
return observable(result);
}
}
// otherwise return the observable wrapper if it is already created and cached or the raw object
return observableResult || result;
} // register and save the (observable.prop -> runningReaction) relation
registerRunningReactionForOperation({
target,
key,
receiver,
type: 'get'
}); // do not violate the none-configurable none-writable prop get handler invariant
// fall back to none reactive mode in this case, instead of letting the Proxy throw a TypeError
var descriptor = Reflect.getOwnPropertyDescriptor(target, key);
if (descriptor && descriptor.writable === false && descriptor.configurable === false) {
return result;
} // otherwise return the observable wrapper if it is already created and cached or the raw object
return observableChild(result, target);
}
function has(target, key) {
const result = handlers.has(target, key);
// register and save (observable.prop -> runningReaction)
registerRunningReactionForOperation({ target, key, type: 'has' });
var result = runProxyHandler('has', target, key); // register and save (observable.prop -> runningReaction)
registerRunningReactionForOperation({
target,
key,
type: 'has'
});
return result;
}
function ownKeys(target) {
registerRunningReactionForOperation({ target, type: 'iterate' });
return handlers.ownKeys(target);
}
function ownKeys$1(target) {
registerRunningReactionForOperation({
target,
type: 'iterate'
});
return runProxyHandler('ownKeys', target);
} // intercept set operations on observables to know when to trigger reactions
// intercept set operations on observables to know when to trigger reactions
function set(target, key, value, receiver) {
// make sure to do not pollute the raw object with observables
if (typeof value === 'object' && value !== null) {
value = proxyToRaw.get(value) || value;
}
// save if the object had a descriptor for this key
const hadKey = hasOwnProperty$1.call(target, key);
// save if the value changed because of this set operation
const oldValue = target[key];
// execute the set operation before running any reaction
const result = handlers.set(target, key, value, receiver);
// do not queue reactions if the target of the operation is not the raw receiver
// (possible because of prototypal inheritance)
value = proxyToRaw.get(value) || value; // save if the object had a descriptor for this key
var hadKey = hasOwnProperty.call(target, key); // save if the value changed because of this set operation
var oldValue = target[key]; // execute the set operation before running any reaction
var result = runProxyHandler('set', target, key, value, receiver); // do not queue reactions if the target of the operation is not the raw receiver
// this possible because of prototypal inheritance
// when the prototype has a setter the set operation traverses the whole prototype chain
// and calls the set trap on every object until it finds the setter
// this is undesired, it is enough for us to trigger the reactions in the set trap of
// the receiver (child) object to avoid duplicate reactions
if (target !== proxyToRaw.get(receiver)) {
return result;
}
// queue a reaction if it's a new property or its value changed
} // queue a reaction if it's a new property or its value changed
if (!hadKey) {
queueReactionsForOperation({ target, key, value, receiver, type: 'add' });
queueReactionsForOperation({
target,
key,
value,
receiver,
type: 'add'
});
} else if (value !== oldValue) {

@@ -462,2 +594,3 @@ queueReactionsForOperation({

}
return result;

@@ -468,44 +601,76 @@ }

// save if the object had the key
const hadKey = hasOwnProperty$1.call(target, key);
const oldValue = target[key];
// execute the delete operation before running any reaction
const result = handlers.deleteProperty(target, key);
// only queue reactions for delete operations which resulted in an actual change
var hadKey = hasOwnProperty.call(target, key);
var oldValue = target[key]; // execute the delete operation before running any reaction
var result = runProxyHandler('deleteProperty', target, key); // only queue reactions for delete operations which resulted in an actual change
if (hadKey) {
queueReactionsForOperation({ target, key, oldValue, type: 'delete' });
queueReactionsForOperation({
target,
key,
oldValue,
type: 'delete'
});
}
return result;
} // return an observable object instance when an observable class is instantiated
function construct(target, args, newTarget) {
return observable(runProxyHandler('construct', target, args, newTarget));
}
// allow custom handlers for proxy traps that this lib does not use
// this prevents the need for double Proxy wrapping for users
// who wish to further extend JS behavior with Proxy traps
var baseHandlers = _extends$1({}, handlers, { get, has, ownKeys, set, deleteProperty });
var proxyHandlers$1 = {
get,
has,
ownKeys: ownKeys$1,
set,
deleteProperty,
construct
};
function observable(obj = {}) {
function observable(obj = {}, options) {
// if it is already an observable or it should not be wrapped, return it
if (proxyToRaw.has(obj) || !shouldInstrument(obj)) {
return obj;
}
// if it already has a cached observable wrapper, return it
} // if it already has a cached observable wrapper, return it
// otherwise create a new observable
return rawToProxy.get(obj) || createObservable(obj);
return rawToProxy.get(obj) || createObservable(obj, options);
}
function createObservable(obj) {
function createObservable(obj, options) {
// if it is a complex built-in object or a normal object, wrap it
const handlers = getHandlers(obj) || baseHandlers;
const observable = new Proxy(obj, handlers);
// save these to switch between the raw object and the wrapped object with ease later
var baseHandlers = getHandlers(obj) || proxyHandlers$1;
var observable = new Proxy(obj, _objectSpread2(_objectSpread2({}, options === null || options === void 0 ? void 0 : options.proxyHandlers), baseHandlers)); // save these to switch between the raw object and the wrapped object with ease later
rawToProxy.set(obj, observable);
proxyToRaw.set(observable, obj);
// init basic data structures to save and cleanup later (observable.prop -> reaction) connections
proxyToRaw.set(observable, obj); // add custom options to the raw object
if (options) {
rawToOptions.set(obj, options);
} // init basic data structures to save and cleanup later (observable.prop -> reaction) connections
storeObservable(obj);
return observable;
} // if observable.prop is an object, wrap it in an observable too
// this is needed to intercept property access on that object too
function observableChild(child, parent) {
if (typeof child === 'object' && child !== null || typeof child === 'function') {
// pass the parent's options to the child object
// this creates a 'deep proxy' which shares custom handlers deeply with its object children
var options = rawToOptions.get(parent);
return observable(child, options);
}
return child;
}
function isObservable(obj) {
return proxyToRaw.has(obj);
}
function raw(obj) {

@@ -515,2 +680,2 @@ return proxyToRaw.get(obj) || obj;

export { observe, unobserve, observable, isObservable, raw, setHandlers, clearHandlers, defaultHandlers };
export { collectionHandlers, isObservable, observable, observe, proxyHandlers, raw, reactionHandlers, unobserve };
{
"name": "@nx-js/observer-util",
"version": "4.3.0-alpha.0",
"version": "4.3.0-alpha.1",
"description": "Simple transparent reactivity with 100% language coverage. Made with ES6 Proxies.",

@@ -13,3 +13,3 @@ "main": "dist/cjs.es5.js",

"scripts": {
"test": "node ./scripts/test.js",
"test": "jest --config jest.config.json",
"test-builds": "node ./scripts/testBuilds.js",

@@ -20,3 +20,3 @@ "debug": "node ./scripts/debug.js",

"coveralls": "cat ./coverage/lcov.info | ./node_modules/.bin/coveralls",
"build": "node ./scripts/build.js",
"build": "rollup --config rollup.config.js",
"build-toc": "node ./scripts/buildToc.js"

@@ -48,31 +48,17 @@ },

"devDependencies": {
"babel-core": "6.26.3",
"babel-preset-es2016": "^6.24.1",
"babel-preset-es2017": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"buble": "^0.15.2",
"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.2",
"karma-mocha": "^1.3.0",
"karma-mocha-reporter": "^2.2.5",
"karma-rollup-preprocessor": "^6.0.0",
"karma-source-map-support": "^1.3.0",
"@babel/core": "^7.9.6",
"@babel/plugin-proposal-class-properties": "^7.8.3",
"@babel/preset-env": "^7.9.6",
"@babel/register": "^7.9.0",
"babel-eslint": "^10.1.0",
"coveralls": "^3.1.0",
"jest": "^26.0.1",
"markdown-toc": "^1.2.0",
"mocha": "^5.2.0",
"nyc": "12.0.2",
"pre-push": "^0.1.1",
"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.3.0",
"standard": "^11.0.1"
"prettier": "^2.0.5",
"rollup": "^2.10.4",
"rollup-plugin-auto-external": "^2.0.0",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-node-resolve": "^5.2.0",
"standard": "^14.3.4"
},

@@ -83,5 +69,6 @@ "engines": {

"standard": {
"parser": "babel-eslint",
"env": [
"browser",
"mocha"
"jest"
]

@@ -88,0 +75,0 @@ },

@@ -27,3 +27,2 @@ # The Observer Utility

* [Platform support](#platform-support)
* [Alternative builds](#alternative-builds)
* [Contributing](#contributing)

@@ -441,13 +440,2 @@

## Alternative builds
This library detects if you use ES6 or commonJS modules and serve the right format to you. The exposed bundles are transpiled to ES5 to support common tools - like UglifyJS minifying. If you would like a finer control over the provided build, you can specify them in your imports.
* `@nx-js/observer-util/dist/es.es6.js` exposes an ES6 build with ES6 modules.
* `@nx-js/observer-util/dist/es.es5.js` exposes an ES5 build with ES6 modules.
* `@nx-js/observer-util/dist/cjs.es6.js` exposes an ES6 build with commonJS modules.
* `@nx-js/observer-util/dist/cjs.es5.js` exposes an ES5 build with commonJS modules.
If you use a bundler, set up an alias for `@nx-js/observer-util` to point to your desired build. You can learn how to do it with webpack [here](https://webpack.js.org/configuration/resolve/#resolve-alias) and with rollup [here](https://github.com/rollup/rollup-plugin-alias#usage).
## Contributing

@@ -454,0 +442,0 @@

declare module '@nx-js/observer-util' {
function observable<Observable extends object>(obj?: Observable): Observable
interface ProxyHandlers {
apply?(target: Function, thisArgument: any, argumentsList: ArrayLike<any>): any;
construct?(target: Function, argumentsList: ArrayLike<any>, newTarget?: any): any;
defineProperty?(target: object, propertyKey: PropertyKey, attributes: PropertyDescriptor): boolean;
deleteProperty?(target: object, propertyKey: PropertyKey): boolean;
get?(target: object, propertyKey: PropertyKey, receiver?: any): any;
getOwnPropertyDescriptor?(target: object, propertyKey: PropertyKey): PropertyDescriptor | undefined;
getPrototypeOf?(target: object): object;
has?(target: object, propertyKey: PropertyKey): boolean;
isExtensible?(target: object): boolean;
ownKeys?(target: object): PropertyKey[];
preventExtensions?(target: object): boolean;
set?(target: object, propertyKey: PropertyKey, value: any, receiver?: any): boolean;
setPrototypeOf?(target: object, proto: any): boolean;
}
type Collection = Map<any, any> | WeakMap<any, any> | Set<any> | WeakSet<any>
interface CollectionHandlers {
add?<Target extends Collection>(target: Target, value: any): Target;
clear?(target: Collection): void;
delete?(target: Collection, key: any): boolean;
get?(target: Collection, key: any): any;
has?(target: Collection, key: any): boolean;
set?<Target extends Collection>(target: Target,key: any, value: any): Target;
size?(target: Collection): number;
forEach?(target: Collection,callbackfn: (value: any, key: any, map: Map<any, any>) => void, thisArg?: any): void;
[Symbol.iterator]?(): IterableIterator<any>;
entries?(): IterableIterator<[any, any]>;
keys?(): IterableIterator<any>;
values?(): IterableIterator<any>;
}
interface ReactionHandlers {
transformReactions?(target: any, propertyKey: PropertyKey, reactions: [Function]): [Function]
}
interface ObservableOptions {
proxyHandlers?: ProxyHandlers;
collectionHandlers?: CollectionHandlers;
reactionHandlers?: ReactionHandlers;
}
function observable<Observable extends object>(obj?: Observable, options?: ObservableOptions): Observable
function isObservable(obj: object): boolean

@@ -7,10 +51,10 @@ function raw<Observable extends object>(obj: Observable): Observable

interface Scheduler {
add: Function
delete: Function
add: Function;
delete: Function;
}
interface ObserveOptions {
scheduler?: Scheduler | Function
debugger?: Function
lazy?: boolean
scheduler?: Scheduler | Function;
debugger?: Function;
lazy?: boolean;
}

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