Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

object-observer

Package Overview
Dependencies
Maintainers
1
Versions
95
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

object-observer - npm Package Compare versions

Comparing version 0.1.1 to 0.2.0

742

dist/object-observer.js
(function (scope) {
'use strict';
'use strict';
var api,
proxiesToTargetsMap = new WeakMap();
var proxiesToTargetsMap = new WeakMap(),
targetsToObserved = new WeakMap(),
observedToObservable = new WeakMap();
function copyShallow(target) {
var result;
if (Array.isArray(target)) {
result = target.slice();
} else {
result = Object.assign({}, target);
}
return result;
}
function copyShallow(target) {
var result;
if (Array.isArray(target)) {
result = target.slice();
} else {
result = Object.assign({}, target);
}
return result;
}
function processArraySubgraph(subGraph, observableData, basePath) {
var path, copy;
subGraph.forEach(function (element, index) {
if (element && typeof element === 'object') {
path = basePath.concat(index);
copy = copyShallow(element);
subGraph[index] = proxify(copy, observableData, path);
}
});
}
function proxiedArrayGet(target, key) {
var result,
observed = targetsToObserved.get(target),
observable = observedToObservable.get(observed.root);
if (key === 'pop') {
result = function proxiedPop() {
var poppedIndex, popResult, changes;
poppedIndex = target.length - 1;
popResult = Reflect.apply(target[key], target, arguments);
if (popResult && typeof popResult === 'object') {
popResult = proxiesToTargetsMap.get(popResult);
targetsToObserved.get(popResult).revoke();
}
changes = [new DeleteChange(observed.path.concat(poppedIndex), popResult)];
publishChanges(observable.callbacks, changes);
return popResult;
};
} else if (key === 'push') {
result = function proxiedPush() {
var pushContent, pushResult, changes = [], startingLength;
pushContent = Array.from(arguments);
startingLength = target.length;
pushContent.forEach(function (item, index) {
if (item && typeof item === 'object') {
pushContent[index] = new Observed(item, startingLength + index, observed).proxy;
}
changes.push(new InsertChange(observed.path.concat(startingLength + index), item));
});
pushResult = Reflect.apply(target[key], target, pushContent);
publishChanges(observable.callbacks, changes);
return pushResult;
};
} else if (key === 'shift') {
result = function proxiedShift() {
var shiftResult, changes, tmpObserved;
shiftResult = Reflect.apply(target[key], target, arguments);
if (shiftResult && typeof shiftResult === 'object') {
shiftResult = proxiesToTargetsMap.get(shiftResult);
targetsToObserved.get(shiftResult).revoke();
}
target.forEach(function (element, index) {
if (element && typeof element === 'object') {
tmpObserved = targetsToObserved.get(proxiesToTargetsMap.get(element));
if (tmpObserved) {
tmpObserved.ownKey = index;
} else {
console.error('failed to resolve proxy -> target -> observed');
}
}
});
changes = [new DeleteChange(observed.path.concat(0), shiftResult)];
publishChanges(observable.callbacks, changes);
return shiftResult;
};
} else if (key === 'unshift') {
result = function proxiedUnshift() {
var unshiftContent, unshiftResult, changes = [], tmpObserved;
unshiftContent = Array.from(arguments);
unshiftContent.forEach(function (item, index) {
if (item && typeof item === 'object') {
unshiftContent[index] = new Observed(item, index, observed).proxy;
}
});
unshiftResult = Reflect.apply(target[key], target, unshiftContent);
target.forEach(function (item, index) {
if (item && typeof item === 'object') {
tmpObserved = targetsToObserved.get(proxiesToTargetsMap.get(item));
if (tmpObserved) {
tmpObserved.ownKey = index;
} else {
console.error('failed to resolve proxy -> target -> observed');
}
}
});
for (var i = 0; i < unshiftContent.length; i++) {
changes.push(new InsertChange(observed.path.concat(i), target[i]));
}
publishChanges(observable.callbacks, changes);
return unshiftResult;
};
} else if (key === 'reverse') {
result = function proxiedReverse() {
var reverseResult, changes = [], tmpObserved;
reverseResult = Reflect.apply(target[key], target, arguments);
target.forEach(function (element, index) {
if (element && typeof element === 'object') {
tmpObserved = targetsToObserved.get(proxiesToTargetsMap.get(element));
if (tmpObserved) {
tmpObserved.ownKey = index;
} else {
console.error('failed to resolve proxy -> target -> observed');
}
}
});
changes.push(new ReverseChange());
publishChanges(observable.callbacks, changes);
return reverseResult;
};
} else if (key === 'sort') {
result = function proxiedSort() {
var sortResult, changes = [], tmpObserved;
sortResult = Reflect.apply(target[key], target, arguments);
target.forEach(function (element, index) {
if (element && typeof element === 'object') {
tmpObserved = targetsToObserved.get(proxiesToTargetsMap.get(element));
if (tmpObserved) {
tmpObserved.ownKey = index;
} else {
console.error('failed to resolve proxy -> target -> observed');
}
}
});
changes.push(new ShuffleChange());
publishChanges(observable.callbacks, changes);
return sortResult;
};
} else if (key === 'fill') {
result = function proxiedFill() {
var fillResult, start, end, changes = [], prev;
start = arguments.length < 2 ? 0 : (arguments[1] < 0 ? target.length + arguments[1] : arguments[1]);
end = arguments.length < 3 ? target.length : (arguments[2] < 0 ? target.length + arguments[2] : arguments[2]);
prev = target.slice();
fillResult = Reflect.apply(target[key], target, arguments);
for (var i = start; i < end; i++) {
if (target[i] && typeof target[i] === 'object') {
target[i] = new Observed(target[i], i, observed).proxy;
}
if (prev.hasOwnProperty(i)) {
changes.push(new UpdateChange(observed.path.concat(i), target[i], prev[i] && typeof prev[i] === 'object' ? proxiesToTargetsMap.get(prev[i]) : prev[i]));
if (prev[i] && typeof prev[i] === 'object') {
targetsToObserved.get(proxiesToTargetsMap.get(prev[i])).revoke();
}
} else {
changes.push(new InsertChange(observed.path.concat(i), target[i]));
}
}
publishChanges(observable.callbacks, changes);
return fillResult;
};
} else if (key === 'splice') {
result = function proxiedSplice() {
var spliceContent, spliceResult, changes = [], tmpObserved,
index, startIndex, removed, inserted;
function processObjectSubgraph(subGraph, observableData, basePath) {
var path, copy;
Reflect.ownKeys(subGraph).forEach(function (key) {
if (subGraph[key] && typeof subGraph[key] === 'object') {
path = basePath.concat(key);
copy = copyShallow(subGraph[key]);
subGraph[key] = proxify(copy, observableData, path);
}
});
}
spliceContent = Array.from(arguments);
function proxify(target, observableData, basePath) {
var proxy;
// obserify the newcomers
spliceContent.forEach(function (item, index) {
if (index > 1 && item && typeof item === 'object') {
spliceContent[index] = new Observed(item, index, observed).proxy;
}
});
function proxiedArrayGet(target, key) {
var result;
if (key === 'pop') {
result = function proxiedPop() {
var poppedIndex, popResult, changes;
poppedIndex = target.length - 1;
observableData.preventCallbacks = true;
popResult = Reflect.apply(target[key], target, arguments);
observableData.preventCallbacks = false;
changes = [new DeleteChange(basePath.concat(poppedIndex), popResult)];
publishChanges(observableData.callbacks, changes);
return popResult;
};
} else if (key === 'push') {
result = function proxiedPush() {
var pushResult, changes = [];
observableData.preventCallbacks = true;
pushResult = Reflect.apply(target[key], target, arguments);
processArraySubgraph(target, observableData, basePath);
observableData.preventCallbacks = false;
for (var i = arguments.length; i > 0; i--) {
changes.push(new InsertChange(basePath.concat(pushResult - i), target[pushResult - i]));
}
publishChanges(observableData.callbacks, changes);
return pushResult;
};
} else if (key === 'shift') {
result = function proxiedShift() {
var shiftResult, changes;
observableData.preventCallbacks = true;
shiftResult = Reflect.apply(target[key], target, arguments);
processArraySubgraph(target, observableData, basePath);
observableData.preventCallbacks = false;
changes = [new DeleteChange(basePath.concat(0), shiftResult)];
publishChanges(observableData.callbacks, changes);
return shiftResult;
};
} else if (key === 'unshift') {
result = function proxiedUnshift() {
var unshiftResult, unshiftContent = [], changes = [];
Array.from(arguments).forEach(function (arg, index) {
var pArg;
if (arg && typeof arg === 'object') {
pArg = proxify(arg, observableData, basePath.concat(index));
} else {
pArg = arg;
}
unshiftContent.push(pArg);
});
unshiftContent.forEach(function (pe, index) {
changes.push(new InsertChange(basePath.concat(index), pe));
});
unshiftResult = Reflect.apply(target[key], target, unshiftContent);
processArraySubgraph(target, observableData, basePath);
publishChanges(observableData.callbacks, changes);
return unshiftResult;
};
} else if (key === 'reverse') {
result = function proxiedReverse() {
var reverseResult, changes = [];
observableData.preventCallbacks = true;
reverseResult = Reflect.apply(target[key], target, arguments);
processArraySubgraph(target, observableData, basePath);
observableData.preventCallbacks = false;
changes.push(new ReverseChange());
publishChanges(observableData.callbacks, changes);
return reverseResult;
};
} else if (key === 'sort') {
result = function proxiedSort() {
var sortResult, changes = [];
observableData.preventCallbacks = true;
sortResult = Reflect.apply(target[key], target, arguments);
processArraySubgraph(target, observableData, basePath);
observableData.preventCallbacks = false;
changes.push(new ShuffleChange());
publishChanges(observableData.callbacks, changes);
return sortResult;
};
} else if (key === 'fill') {
result = function proxiedFill() {
var fillResult, start, end, changes = [], prev;
start = arguments.length < 2 ? 0 : (arguments[1] < 0 ? target.length + arguments[1] : arguments[1]);
end = arguments.length < 3 ? target.length : (arguments[2] < 0 ? target.length + arguments[2] : arguments[2]);
prev = target.slice(start, end);
observableData.preventCallbacks = true;
fillResult = Reflect.apply(target[key], target, arguments);
processArraySubgraph(target, observableData, basePath);
observableData.preventCallbacks = false;
for (var i = start; i < end; i++) {
if (target.hasOwnProperty(i - start)) {
changes.push(new UpdateChange(basePath.concat(i), target[i], prev[i - start]));
} else {
changes.push(new InsertChange(basePath.concat(i), target[i]));
}
}
publishChanges(observableData.callbacks, changes);
return fillResult;
};
} else if (key === 'splice') {
result = function proxiedSplice() {
var changes = [],
index,
startIndex,
removed,
inserted,
spliceResult;
observableData.preventCallbacks = true;
startIndex = arguments.length === 0 ? 0 : (arguments[0] < 0 ? target.length + arguments[0] : arguments[0]);
removed = arguments.length < 2 ? (target.length - startIndex) : arguments[1];
inserted = Math.max(arguments.length - 2, 0);
spliceResult = Reflect.apply(target[key], target, arguments);
processArraySubgraph(target, observableData, basePath);
observableData.preventCallbacks = false;
for (index = 0; index < removed; index++) {
if (index < inserted) {
changes.push(new UpdateChange(basePath.concat(startIndex + index), target[startIndex + index], spliceResult[index]));
} else {
changes.push(new DeleteChange(basePath.concat(startIndex + index), spliceResult[index]));
}
}
for (; index < inserted; index++) {
changes.push(new InsertChange(basePath.concat(startIndex + index), target[startIndex + index]));
}
// calculate pointers
startIndex = spliceContent.length === 0 ? 0 : (spliceContent[0] < 0 ? target.length + spliceContent[0] : spliceContent[0]);
removed = spliceContent.length < 2 ? target.length - startIndex : spliceContent[1];
inserted = Math.max(spliceContent.length - 2, 0);
spliceResult = Reflect.apply(target[key], target, spliceContent);
publishChanges(observableData.callbacks, changes);
return spliceResult;
};
} else {
result = Reflect.get(target, key);
}
return result;
}
// reindex the paths
target.forEach(function (element, index) {
if (element && typeof element === 'object') {
tmpObserved = targetsToObserved.get(proxiesToTargetsMap.get(element));
if (tmpObserved) {
tmpObserved.ownKey = index;
} else {
console.error('failed to resolve proxy -> target -> observed');
}
}
});
function proxiedSet(target, key, value) {
var oldValuePresent = target.hasOwnProperty(key),
oldValue = target[key],
result,
changes = Array.isArray(observableData.eventsCollector) ? observableData.eventsCollector : [],
path;
// revoke removed Observed
spliceResult.forEach(function (removed, index) {
if (removed && typeof removed === 'object') {
spliceResult[index] = proxiesToTargetsMap.get(removed);
targetsToObserved.get(spliceResult[index]).revoke();
}
});
result = Reflect.set(target, key, value);
if (observableData.callbacks.length && result && value !== oldValue) {
path = basePath.concat(key);
// publish changes
for (index = 0; index < removed; index++) {
if (index < inserted) {
changes.push(new UpdateChange(observed.path.concat(startIndex + index), target[startIndex + index], spliceResult[index]));
} else {
changes.push(new DeleteChange(observed.path.concat(startIndex + index), spliceResult[index]));
}
}
for (; index < inserted; index++) {
changes.push(new InsertChange(observed.path.concat(startIndex + index), target[startIndex + index]));
}
publishChanges(observable.callbacks, changes);
if (typeof oldValue === 'object' && oldValue) {
if (proxiesToTargetsMap.has(oldValue)) {
proxiesToTargetsMap.delete(oldValue);
}
}
if (typeof value === 'object' && value) {
target[key] = proxify(value, observableData, path);
}
if (oldValuePresent) {
changes.push(new UpdateChange(path, value, oldValue));
} else {
changes.push(new InsertChange(path, value));
}
if (!observableData.preventCallbacks) {
publishChanges(observableData.callbacks, changes);
}
}
return result;
}
return spliceResult;
};
} else {
result = Reflect.get(target, key);
}
return result;
}
function proxiedDelete(target, key) {
var oldValue = target[key],
result,
changes = Array.isArray(observableData.eventsCollector) ? observableData.eventsCollector : [],
path;
function proxiedSet(target, key, value) {
var oldValuePresent = target.hasOwnProperty(key),
oldValue = target[key],
result,
observed = targetsToObserved.get(target),
observable = observedToObservable.get(observed.root),
changes = [],
path;
result = Reflect.deleteProperty(target, key);
if (observableData.callbacks.length && result) {
if (typeof oldValue === 'object' && oldValue) {
if (proxiesToTargetsMap.has(oldValue)) {
proxiesToTargetsMap.delete(oldValue);
}
}
path = basePath.concat(key);
changes.push(new DeleteChange(path, oldValue));
if (!observableData.preventCallbacks) {
publishChanges(observableData.callbacks, changes);
}
}
return result;
}
result = Reflect.set(target, key, value);
if (observable.callbacks.length && result && value !== oldValue) {
path = observed.path.concat(key);
if (proxiesToTargetsMap.has(target)) {
var tmp = target;
target = proxiesToTargetsMap.get(target);
proxiesToTargetsMap.delete(tmp);
}
if (Array.isArray(target)) {
processArraySubgraph(target, observableData, basePath);
proxy = new Proxy(target, {
get: proxiedArrayGet,
set: proxiedSet,
deleteProperty: proxiedDelete
});
} else {
processObjectSubgraph(target, observableData, basePath);
proxy = new Proxy(target, {
set: proxiedSet,
deleteProperty: proxiedDelete
});
}
proxiesToTargetsMap.set(proxy, target);
if (oldValue && typeof oldValue === 'object') {
targetsToObserved.get(proxiesToTargetsMap.get(oldValue)).revoke();
if (proxiesToTargetsMap.has(oldValue)) {
proxiesToTargetsMap.delete(oldValue);
}
}
if (value && typeof value === 'object') {
target[key] = new Observed(value, key, observed).proxy;
}
if (oldValuePresent) {
changes.push(new UpdateChange(path, value, oldValue));
} else {
changes.push(new InsertChange(path, value));
}
if (!observed.preventCallbacks) {
publishChanges(observable.callbacks, changes);
}
}
return result;
}
return proxy;
}
function proxiedDelete(target, key) {
var oldValue = target[key],
result,
observed = targetsToObserved.get(target),
observable = observedToObservable.get(observed.root),
changes = [],
path;
function ObservableData(target) {
var proxy,
callbacks = [],
eventsCollector,
preventCallbacks = false;
result = Reflect.deleteProperty(target, key);
if (observable.callbacks.length && result) {
if (typeof oldValue === 'object' && oldValue) {
if (proxiesToTargetsMap.has(oldValue)) {
proxiesToTargetsMap.delete(oldValue);
}
}
path = observed.path.concat(key);
changes.push(new DeleteChange(path, oldValue));
if (!observed.preventCallbacks) {
publishChanges(observable.callbacks, changes);
}
}
return result;
}
function observe(callback) {
if (typeof callback !== 'function') { throw new Error('callback parameter MUST be a function'); }
function processArraySubgraph(graph, parentObserved) {
graph.forEach(function (element, index) {
if (element && typeof element === 'object') {
graph[index] = new Observed(element, index, parentObserved).proxy;
}
});
}
if (callbacks.indexOf(callback) < 0) {
callbacks.push(callback);
} else {
console.info('observer callback may be bound only once for an observable');
}
}
function processObjectSubgraph(graph, parentObserved) {
Reflect.ownKeys(graph).forEach(function (key) {
if (graph[key] && typeof graph[key] === 'object') {
graph[key] = new Observed(graph[key], key, parentObserved).proxy;
}
});
}
function unobserve() {
if (arguments.length) {
Array.from(arguments).forEach(function (argument) {
var i = callbacks.indexOf(argument);
if (i) {
callbacks.splice(i, 1);
}
});
} else {
callbacks.splice(0, callbacks.length);
}
}
function Observed(origin, ownKey, parent) {
var targetClone, revokableProxy;
proxy = proxify(copyShallow(target), this, []);
Reflect.defineProperty(proxy, 'observe', { value: observe });
Reflect.defineProperty(proxy, 'unobserve', { value: unobserve });
if (!origin || typeof origin !== 'object') {
throw new Error('Observed MUST be created from a non null object origin');
}
if (parent && (typeof ownKey === 'undefined' || ownKey === null)) {
throw new Error('any non-root (parent-less) Observed MUST have an own path; now parent is ' + parent + '; key is ' + ownKey);
}
if (parent && !(parent instanceof Observed)) {
throw new Error('parent, when supplied, MUST be an instance of Observed');
}
Reflect.defineProperty(this, 'callbacks', { get: function () { return callbacks.slice(); } });
Reflect.defineProperty(this, 'eventsCollector', { value: eventsCollector, writable: true });
Reflect.defineProperty(this, 'preventCallbacks', { value: preventCallbacks, writable: true });
Reflect.defineProperty(this, 'proxy', { value: proxy });
}
targetClone = copyShallow(origin);
function InsertChange(path, value) {
Reflect.defineProperty(this, 'type', { value: 'insert' });
Reflect.defineProperty(this, 'path', { value: path });
Reflect.defineProperty(this, 'value', { value: value });
}
function UpdateChange(path, value, oldValue) {
Reflect.defineProperty(this, 'type', { value: 'update' });
Reflect.defineProperty(this, 'path', { value: path });
Reflect.defineProperty(this, 'value', { value: value });
Reflect.defineProperty(this, 'oldValue', { value: oldValue });
}
function DeleteChange(path, oldValue) {
Reflect.defineProperty(this, 'type', { value: 'delete' });
Reflect.defineProperty(this, 'path', { value: path });
Reflect.defineProperty(this, 'oldValue', { value: oldValue });
}
function ReverseChange() {
Reflect.defineProperty(this, 'type', { value: 'reverse' });
}
function ShuffleChange() {
Reflect.defineProperty(this, 'type', { value: 'shuffle' });
}
if (Array.isArray(targetClone)) {
processArraySubgraph(targetClone, this);
revokableProxy = Proxy.revocable(targetClone, {
set: proxiedSet,
get: proxiedArrayGet,
deleteProperty: proxiedDelete
});
} else {
processObjectSubgraph(targetClone, this);
revokableProxy = Proxy.revocable(targetClone, {
set: proxiedSet,
deleteProperty: proxiedDelete
});
}
function publishChanges(callbacks, changes) {
for (var i = 0; i < callbacks.length; i++) {
try {
callbacks[i](changes);
} catch (e) {
console.error(e);
}
}
}
targetsToObserved.set(targetClone, this);
proxiesToTargetsMap.set(revokableProxy.proxy, targetClone);
Reflect.defineProperty(this, 'revokable', { value: revokableProxy });
Reflect.defineProperty(this, 'proxy', { value: revokableProxy.proxy });
Reflect.defineProperty(this, 'parent', { value: parent });
Reflect.defineProperty(this, 'ownKey', { value: ownKey, writable: true });
}
api = {};
Reflect.defineProperty(Observed.prototype, 'root', {
get: function () {
var result = this;
while (result.parent) {
result = result.parent;
}
return result;
}
});
Reflect.defineProperty(Observed.prototype, 'path', {
get: function () {
var result = [], pointer = this;
while (typeof pointer.ownKey !== 'undefined') {
result.push(pointer.ownKey);
pointer = pointer.parent;
}
return result.reverse();
}
});
Reflect.defineProperty(Observed.prototype, 'revoke', {
value: function () {
var proxy = this.proxy;
Reflect.ownKeys(proxy).forEach(function (key) {
var child = proxy[key];
if (child && typeof child === 'object') {
targetsToObserved.get(proxiesToTargetsMap.get(child)).revoke();
proxiesToTargetsMap.get(proxy)[key] = proxiesToTargetsMap.get(child);
}
});
this.revokable.revoke();
// TODO: ensure if there are any other cleanups to do here (probably remove observed?)
}
})
Reflect.defineProperty(api, 'from', {
value: function (target) {
if (!target || typeof target !== 'object') {
throw new Error('observable MAY ONLY be created from non-null object only');
} else if ('observe' in target || 'unobserve' in target) {
throw new Error('target object MUST NOT have not own nor inherited properties "observe" and/or "unobserve"');
}
var observableData = new ObservableData(target);
return observableData.proxy;
}
});
function Observable(observed) {
var isRevoked = false, callbacks = [];
Reflect.defineProperty(scope, 'Observable', { value: api });
function observe(callback) {
if (isRevoked) { throw new TypeError('revoked Observable MAY NOT be observed anymore'); }
if (typeof callback !== 'function') { throw new Error('observer (callback) parameter MUST be a function'); }
if (callbacks.indexOf(callback) < 0) {
callbacks.push(callback);
} else {
console.info('observer (callback) may be bound to an observable only once');
}
}
function unobserve() {
if (isRevoked) { throw new TypeError('revoked Observable MAY NOT be unobserved amymore'); }
if (arguments.length) {
Array.from(arguments).forEach(function (argument) {
var i = callbacks.indexOf(argument);
if (i >= 0) {
callbacks.splice(i, 1);
}
});
} else {
callbacks.splice(0, callbacks.length);
}
}
function revoke() {
if (!isRevoked) {
isRevoked = true;
observed.revoke();
} else {
console.log('revokation of Observable have an effect only once');
}
}
Reflect.defineProperty(observed.proxy, 'observe', { value: observe });
Reflect.defineProperty(observed.proxy, 'unobserve', { value: unobserve });
Reflect.defineProperty(observed.proxy, 'revoke', { value: revoke });
Reflect.defineProperty(this, 'callbacks', { value: callbacks });
}
function InsertChange(path, value) {
Reflect.defineProperty(this, 'type', { value: 'insert' });
Reflect.defineProperty(this, 'path', { value: path });
Reflect.defineProperty(this, 'value', { value: value });
}
function UpdateChange(path, value, oldValue) {
Reflect.defineProperty(this, 'type', { value: 'update' });
Reflect.defineProperty(this, 'path', { value: path });
Reflect.defineProperty(this, 'value', { value: value });
Reflect.defineProperty(this, 'oldValue', { value: oldValue });
}
function DeleteChange(path, oldValue) {
Reflect.defineProperty(this, 'type', { value: 'delete' });
Reflect.defineProperty(this, 'path', { value: path });
Reflect.defineProperty(this, 'oldValue', { value: oldValue });
}
function ReverseChange() {
Reflect.defineProperty(this, 'type', { value: 'reverse' });
}
function ShuffleChange() {
Reflect.defineProperty(this, 'type', { value: 'shuffle' });
}
function publishChanges(callbacks, changes) {
for (var i = 0; i < callbacks.length; i++) {
try {
callbacks[i](changes);
} catch (e) {
console.error(e);
}
}
}
Reflect.defineProperty(Observable, 'from', {
value: function (target) {
if (!target || typeof target !== 'object') {
throw new Error('observable MAY ONLY be created from non-null object only');
} else if ('observe' in target || 'unobserve' in target || 'revoke' in target) {
throw new Error('target object MUST NOT have nor own neither inherited properties from the following list: "observe", "unobserve", "revoke"');
}
var observed = new Observed(target),
observable = new Observable(observed);
observedToObservable.set(observed, observable);
return observed.proxy;
}
});
Reflect.defineProperty(scope, 'Observable', { value: Observable });
})(this);

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

!function(a){"use strict";function b(a){var b;return b=Array.isArray(a)?a.slice():Object.assign({},a)}function c(a,c,d){var f,g;a.forEach(function(h,i){h&&"object"==typeof h&&(f=d.concat(i),g=b(h),a[i]=e(g,c,f))})}function d(a,c,d){var f,g;Reflect.ownKeys(a).forEach(function(h){a[h]&&"object"==typeof a[h]&&(f=d.concat(h),g=b(a[h]),a[h]=e(g,c,f))})}function e(a,b,f){function m(a,d){var m;return m="pop"===d?function(){var c,e,g;return c=a.length-1,b.preventCallbacks=!0,e=Reflect.apply(a[d],a,arguments),b.preventCallbacks=!1,g=[new i(f.concat(c),e)],l(b.callbacks,g),e}:"push"===d?function(){var e,h=[];b.preventCallbacks=!0,e=Reflect.apply(a[d],a,arguments),c(a,b,f),b.preventCallbacks=!1;for(var i=arguments.length;i>0;i--)h.push(new g(f.concat(e-i),a[e-i]));return l(b.callbacks,h),e}:"shift"===d?function(){var e,g;return b.preventCallbacks=!0,e=Reflect.apply(a[d],a,arguments),c(a,b,f),b.preventCallbacks=!1,g=[new i(f.concat(0),e)],l(b.callbacks,g),e}:"unshift"===d?function(){var h,i=[],j=[];return Array.from(arguments).forEach(function(a,c){var d;d=a&&"object"==typeof a?e(a,b,f.concat(c)):a,i.push(d)}),i.forEach(function(a,b){j.push(new g(f.concat(b),a))}),h=Reflect.apply(a[d],a,i),c(a,b,f),l(b.callbacks,j),h}:"reverse"===d?function(){var e,g=[];return b.preventCallbacks=!0,e=Reflect.apply(a[d],a,arguments),c(a,b,f),b.preventCallbacks=!1,g.push(new j),l(b.callbacks,g),e}:"sort"===d?function(){var e,g=[];return b.preventCallbacks=!0,e=Reflect.apply(a[d],a,arguments),c(a,b,f),b.preventCallbacks=!1,g.push(new k),l(b.callbacks,g),e}:"fill"===d?function(){var e,i,j,k,m=[];i=arguments.length<2?0:arguments[1]<0?a.length+arguments[1]:arguments[1],j=arguments.length<3?a.length:arguments[2]<0?a.length+arguments[2]:arguments[2],k=a.slice(i,j),b.preventCallbacks=!0,e=Reflect.apply(a[d],a,arguments),c(a,b,f),b.preventCallbacks=!1;for(var n=i;j>n;n++)a.hasOwnProperty(n-i)?m.push(new h(f.concat(n),a[n],k[n-i])):m.push(new g(f.concat(n),a[n]));return l(b.callbacks,m),e}:"splice"===d?function(){var e,j,k,m,n,o=[];for(b.preventCallbacks=!0,j=0===arguments.length?0:arguments[0]<0?a.length+arguments[0]:arguments[0],k=arguments.length<2?a.length-j:arguments[1],m=Math.max(arguments.length-2,0),n=Reflect.apply(a[d],a,arguments),c(a,b,f),b.preventCallbacks=!1,e=0;k>e;e++)m>e?o.push(new h(f.concat(j+e),a[j+e],n[e])):o.push(new i(f.concat(j+e),n[e]));for(;m>e;e++)o.push(new g(f.concat(j+e),a[j+e]));return l(b.callbacks,o),n}:Reflect.get(a,d)}function o(a,c,d){var i,j,k=a.hasOwnProperty(c),m=a[c],o=Array.isArray(b.eventsCollector)?b.eventsCollector:[];return i=Reflect.set(a,c,d),b.callbacks.length&&i&&d!==m&&(j=f.concat(c),"object"==typeof m&&m&&n.has(m)&&n.delete(m),"object"==typeof d&&d&&(a[c]=e(d,b,j)),k?o.push(new h(j,d,m)):o.push(new g(j,d)),b.preventCallbacks||l(b.callbacks,o)),i}function p(a,c){var d,e,g=a[c],h=Array.isArray(b.eventsCollector)?b.eventsCollector:[];return d=Reflect.deleteProperty(a,c),b.callbacks.length&&d&&("object"==typeof g&&g&&n.has(g)&&n.delete(g),e=f.concat(c),h.push(new i(e,g)),b.preventCallbacks||l(b.callbacks,h)),d}var q;if(n.has(a)){var r=a;a=n.get(a),n.delete(r)}return Array.isArray(a)?(c(a,b,f),q=new Proxy(a,{get:m,set:o,deleteProperty:p})):(d(a,b,f),q=new Proxy(a,{set:o,deleteProperty:p})),n.set(q,a),q}function f(a){function c(a){if("function"!=typeof a)throw new Error("callback parameter MUST be a function");h.indexOf(a)<0?h.push(a):console.info("observer callback may be bound only once for an observable")}function d(){arguments.length?Array.from(arguments).forEach(function(a){var b=h.indexOf(a);b&&h.splice(b,1)}):h.splice(0,h.length)}var f,g,h=[],i=!1;f=e(b(a),this,[]),Reflect.defineProperty(f,"observe",{value:c}),Reflect.defineProperty(f,"unobserve",{value:d}),Reflect.defineProperty(this,"callbacks",{get:function(){return h.slice()}}),Reflect.defineProperty(this,"eventsCollector",{value:g,writable:!0}),Reflect.defineProperty(this,"preventCallbacks",{value:i,writable:!0}),Reflect.defineProperty(this,"proxy",{value:f})}function g(a,b){Reflect.defineProperty(this,"type",{value:"insert"}),Reflect.defineProperty(this,"path",{value:a}),Reflect.defineProperty(this,"value",{value:b})}function h(a,b,c){Reflect.defineProperty(this,"type",{value:"update"}),Reflect.defineProperty(this,"path",{value:a}),Reflect.defineProperty(this,"value",{value:b}),Reflect.defineProperty(this,"oldValue",{value:c})}function i(a,b){Reflect.defineProperty(this,"type",{value:"delete"}),Reflect.defineProperty(this,"path",{value:a}),Reflect.defineProperty(this,"oldValue",{value:b})}function j(){Reflect.defineProperty(this,"type",{value:"reverse"})}function k(){Reflect.defineProperty(this,"type",{value:"shuffle"})}function l(a,b){for(var c=0;c<a.length;c++)try{a[c](b)}catch(a){console.error(a)}}var m,n=new WeakMap;m={},Reflect.defineProperty(m,"from",{value:function(a){if(!a||"object"!=typeof a)throw new Error("observable MAY ONLY be created from non-null object only");if("observe"in a||"unobserve"in a)throw new Error('target object MUST NOT have not own nor inherited properties "observe" and/or "unobserve"');var b=new f(a);return b.proxy}}),Reflect.defineProperty(a,"Observable",{value:m})}(this);
!function(a){"use strict";function b(a){var b;return b=Array.isArray(a)?a.slice():Object.assign({},a)}function c(a,b){var c,d=q.get(a),e=r.get(d.root);return c="pop"===b?function(){var c,f,g;return c=a.length-1,f=Reflect.apply(a[b],a,arguments),f&&"object"==typeof f&&(f=p.get(f),q.get(f).revoke()),g=[new l(d.path.concat(c),f)],o(e.callbacks,g),f}:"push"===b?function(){var c,f,g,i=[];return c=Array.from(arguments),g=a.length,c.forEach(function(a,b){a&&"object"==typeof a&&(c[b]=new h(a,g+b,d).proxy),i.push(new j(d.path.concat(g+b),a))}),f=Reflect.apply(a[b],a,c),o(e.callbacks,i),f}:"shift"===b?function(){var c,f,g;return c=Reflect.apply(a[b],a,arguments),c&&"object"==typeof c&&(c=p.get(c),q.get(c).revoke()),a.forEach(function(a,b){a&&"object"==typeof a&&(g=q.get(p.get(a)),g?g.ownKey=b:console.error("failed to resolve proxy -> target -> observed"))}),f=[new l(d.path.concat(0),c)],o(e.callbacks,f),c}:"unshift"===b?function(){var c,f,g,i=[];c=Array.from(arguments),c.forEach(function(a,b){a&&"object"==typeof a&&(c[b]=new h(a,b,d).proxy)}),f=Reflect.apply(a[b],a,c),a.forEach(function(a,b){a&&"object"==typeof a&&(g=q.get(p.get(a)),g?g.ownKey=b:console.error("failed to resolve proxy -> target -> observed"))});for(var k=0;k<c.length;k++)i.push(new j(d.path.concat(k),a[k]));return o(e.callbacks,i),f}:"reverse"===b?function(){var c,d,f=[];return c=Reflect.apply(a[b],a,arguments),a.forEach(function(a,b){a&&"object"==typeof a&&(d=q.get(p.get(a)),d?d.ownKey=b:console.error("failed to resolve proxy -> target -> observed"))}),f.push(new m),o(e.callbacks,f),c}:"sort"===b?function(){var c,d,f=[];return c=Reflect.apply(a[b],a,arguments),a.forEach(function(a,b){a&&"object"==typeof a&&(d=q.get(p.get(a)),d?d.ownKey=b:console.error("failed to resolve proxy -> target -> observed"))}),f.push(new n),o(e.callbacks,f),c}:"fill"===b?function(){var c,f,g,i,l=[];f=arguments.length<2?0:arguments[1]<0?a.length+arguments[1]:arguments[1],g=arguments.length<3?a.length:arguments[2]<0?a.length+arguments[2]:arguments[2],i=a.slice(),c=Reflect.apply(a[b],a,arguments);for(var m=f;m<g;m++)a[m]&&"object"==typeof a[m]&&(a[m]=new h(a[m],m,d).proxy),i.hasOwnProperty(m)?(l.push(new k(d.path.concat(m),a[m],i[m]&&"object"==typeof i[m]?p.get(i[m]):i[m])),i[m]&&"object"==typeof i[m]&&q.get(p.get(i[m])).revoke()):l.push(new j(d.path.concat(m),a[m]));return o(e.callbacks,l),c}:"splice"===b?function(){var c,f,g,i,m,n,r,s=[];for(c=Array.from(arguments),c.forEach(function(a,b){b>1&&a&&"object"==typeof a&&(c[b]=new h(a,b,d).proxy)}),m=0===c.length?0:c[0]<0?a.length+c[0]:c[0],n=c.length<2?a.length-m:c[1],r=Math.max(c.length-2,0),f=Reflect.apply(a[b],a,c),a.forEach(function(a,b){a&&"object"==typeof a&&(g=q.get(p.get(a)),g?g.ownKey=b:console.error("failed to resolve proxy -> target -> observed"))}),f.forEach(function(a,b){a&&"object"==typeof a&&(f[b]=p.get(a),q.get(f[b]).revoke())}),i=0;i<n;i++)i<r?s.push(new k(d.path.concat(m+i),a[m+i],f[i])):s.push(new l(d.path.concat(m+i),f[i]));for(;i<r;i++)s.push(new j(d.path.concat(m+i),a[m+i]));return o(e.callbacks,s),f}:Reflect.get(a,b)}function d(a,b,c){var d,e,f=a.hasOwnProperty(b),g=a[b],i=q.get(a),l=r.get(i.root),m=[];return d=Reflect.set(a,b,c),l.callbacks.length&&d&&c!==g&&(e=i.path.concat(b),g&&"object"==typeof g&&(q.get(p.get(g)).revoke(),p.has(g)&&p.delete(g)),c&&"object"==typeof c&&(a[b]=new h(c,b,i).proxy),f?m.push(new k(e,c,g)):m.push(new j(e,c)),i.preventCallbacks||o(l.callbacks,m)),d}function e(a,b){var c,d,e=a[b],f=q.get(a),g=r.get(f.root),h=[];return c=Reflect.deleteProperty(a,b),g.callbacks.length&&c&&("object"==typeof e&&e&&p.has(e)&&p.delete(e),d=f.path.concat(b),h.push(new l(d,e)),f.preventCallbacks||o(g.callbacks,h)),c}function f(a,b){a.forEach(function(c,d){c&&"object"==typeof c&&(a[d]=new h(c,d,b).proxy)})}function g(a,b){Reflect.ownKeys(a).forEach(function(c){a[c]&&"object"==typeof a[c]&&(a[c]=new h(a[c],c,b).proxy)})}function h(a,i,j){var k,l;if(!a||"object"!=typeof a)throw new Error("Observed MUST be created from a non null object origin");if(j&&("undefined"==typeof i||null===i))throw new Error("any non-root (parent-less) Observed MUST have an own path; now parent is "+j+"; key is "+i);if(j&&!(j instanceof h))throw new Error("parent, when supplied, MUST be an instance of Observed");k=b(a),Array.isArray(k)?(f(k,this),l=Proxy.revocable(k,{set:d,get:c,deleteProperty:e})):(g(k,this),l=Proxy.revocable(k,{set:d,deleteProperty:e})),q.set(k,this),p.set(l.proxy,k),Reflect.defineProperty(this,"revokable",{value:l}),Reflect.defineProperty(this,"proxy",{value:l.proxy}),Reflect.defineProperty(this,"parent",{value:j}),Reflect.defineProperty(this,"ownKey",{value:i,writable:!0})}function i(a){function b(a){if(e)throw new TypeError("revoked Observable MAY NOT be observed anymore");if("function"!=typeof a)throw new Error("observer (callback) parameter MUST be a function");f.indexOf(a)<0?f.push(a):console.info("observer (callback) may be bound to an observable only once")}function c(){if(e)throw new TypeError("revoked Observable MAY NOT be unobserved amymore");arguments.length?Array.from(arguments).forEach(function(a){var b=f.indexOf(a);b>=0&&f.splice(b,1)}):f.splice(0,f.length)}function d(){e?console.log("revokation of Observable have an effect only once"):(e=!0,a.revoke())}var e=!1,f=[];Reflect.defineProperty(a.proxy,"observe",{value:b}),Reflect.defineProperty(a.proxy,"unobserve",{value:c}),Reflect.defineProperty(a.proxy,"revoke",{value:d}),Reflect.defineProperty(this,"callbacks",{value:f})}function j(a,b){Reflect.defineProperty(this,"type",{value:"insert"}),Reflect.defineProperty(this,"path",{value:a}),Reflect.defineProperty(this,"value",{value:b})}function k(a,b,c){Reflect.defineProperty(this,"type",{value:"update"}),Reflect.defineProperty(this,"path",{value:a}),Reflect.defineProperty(this,"value",{value:b}),Reflect.defineProperty(this,"oldValue",{value:c})}function l(a,b){Reflect.defineProperty(this,"type",{value:"delete"}),Reflect.defineProperty(this,"path",{value:a}),Reflect.defineProperty(this,"oldValue",{value:b})}function m(){Reflect.defineProperty(this,"type",{value:"reverse"})}function n(){Reflect.defineProperty(this,"type",{value:"shuffle"})}function o(a,b){for(var c=0;c<a.length;c++)try{a[c](b)}catch(a){console.error(a)}}var p=new WeakMap,q=new WeakMap,r=new WeakMap;Reflect.defineProperty(h.prototype,"root",{get:function(){for(var a=this;a.parent;)a=a.parent;return a}}),Reflect.defineProperty(h.prototype,"path",{get:function(){for(var a=[],b=this;"undefined"!=typeof b.ownKey;)a.push(b.ownKey),b=b.parent;return a.reverse()}}),Reflect.defineProperty(h.prototype,"revoke",{value:function(){var a=this.proxy;Reflect.ownKeys(a).forEach(function(b){var c=a[b];c&&"object"==typeof c&&(q.get(p.get(c)).revoke(),p.get(a)[b]=p.get(c))}),this.revokable.revoke()}}),Reflect.defineProperty(i,"from",{value:function(a){if(!a||"object"!=typeof a)throw new Error("observable MAY ONLY be created from non-null object only");if("observe"in a||"unobserve"in a||"revoke"in a)throw new Error('target object MUST NOT have nor own neither inherited properties from the following list: "observe", "unobserve", "revoke"');var b=new h(a),c=new i(b);return r.set(b,c),b.proxy}}),Reflect.defineProperty(a,"Observable",{value:i})}(this);
{
"name": "object-observer",
"version": "0.1.01",
"version": "0.2.0",
"homepage": "https://github.com/gullerya/object-observer-js/README.md",

@@ -14,4 +14,8 @@ "author": {

"grunt-cli": "~1.2.0",
"grunt-contrib-jshint": "~1.0.0",
"grunt-contrib-uglify": "~1.0.1"
"grunt-contrib-uglify": "^2.0.0",
"grunt-karma": "~2.0.0",
"babel-eslint": "6.1.2",
"eslint-plugin-react": "6.1.2",
"gruntify-eslint": "^3.1.0",
"karma": "~0.13.0"
},

@@ -33,4 +37,3 @@ "keywords": [

"files": [
"dist/object-observer.js",
"dist/object-observer.min.js"
"dist"
],

@@ -45,5 +48,5 @@ "scripts": {

"bugs": {
"url": "https://github.com/gullerya/data-tier/issues",
"url": "https://github.com/gullerya/object-observer-js/issues",
"email": "gullerya@gmail.com"
}
}

@@ -11,3 +11,3 @@ [![npm version](https://badge.fury.io/js/object-observer.svg)](https://badge.fury.io/js/object-observer)

Present library attempts to provide this functionality in a most clean and performant way. Main aspects:
- Implementation relies on __Proxy__ mechanism
- Implementation relies on __Proxy__ mechanism (specifically, revokable Proxy)
- Observation is 'deep', yielding changes from a __sub-graphs__ too

@@ -28,9 +28,17 @@ - Changes delivered in a __synchronous__ way

#### Backlog:
- Optimization for the cases of Array massive mutations
- Add `readPath` and `writePath` utility methods in `DataPath` object (part of change data)?
- Create build process including test automation on CI and probably minification/reorg of a consumable code
- Changes, probably based on my own consumption of this library in [data-tier](https://github.com/gullerya/data-tier) module and/or community feedback
- ~~Optimization for the cases of Array massive mutations~~ __Status__: done, any array change that previously was recalculating the whole array graph including all sub-graphs, now just updates the immediate indices of the changed array
- Add `readPath` and `writePath` utility methods in `DataPath` object (part of change data)? __Status__: NA
- Create build process including test automation on CI and probably minification/reorg of a consumable code. __Status__: added eslinting, minification as part of the build
- Changes, probably based on my own consumption of this library in [data-tier](https://github.com/gullerya/data-tier) module and/or community feedback. __Status__: in progress
- Consider adding support for a Symbol defined object properties. __Status__: in progress
- Consider adding support for special native objects Map/WeakMap/Set/WeakSet (track this [issue](https://github.com/gullerya/object-observer-js/issues/1)). __Status__: in progress
#### Versions
- 0.1.0
- __0.2.0__
- Tech: moved proxy implementation to revokable
- Tech: refactored algorithm of sub-graphs indexing and management; speed and memory improved, arrays massive changes improved significantly
- API: added revokability to an Observable
- 'detached' (`pop`, `shift`, `splice` actions on arrays) and replaced (simple update on objects and arrays, `fill` on arrays) observed sub-graphs are being revoked as well
- results of 'detach' actions (`pop`, `shift`, `splice`) are turned back to the plain object (yet having all of the changes done to the observable) when returned by APIs
- __0.1.0__
- First stable API release

@@ -117,2 +125,9 @@

- __`revoke`__ - parameterless. All of the proxies along the observed graph will be revoked and thus become unusable. `observe` and `unobserve` methods will mimic the revoked `Proxy` behaviour and throw `TypeError` if used on the revoked `Observable`. Subsequent `revoke` invokations will have no effect:
```javascript
...
observablePerson.revoke();
...
```
# Examples

@@ -190,3 +205,2 @@

Arrays notes:
- Some of array operations are effectively moving/reindexing the whole rest of an array (shift, unshift, splice, reverse, sort). In cases of massive changes touching presumable the whole array I took pessimistic approach and opt for a special non-detailed event: 'reverse' for `reverse` and 'shuffle' for `sort`. The rest of these methods I'm handling in optimistic way opting to deliver the changes that directly related to the method invokation, while leaving out the implicit outcomes like reindexing of the rest of the Array.
- am I missed something?
- Some of array operations are effectively moving/reindexing the whole array (shift, unshift, splice, reverse, sort). In cases of massive changes touching presumably the whole array I took a pessimistic approach with a special non-detailed events: 'reverse' for `reverse`, 'shuffle' for `sort`. The rest of these methods I'm handling in an optimistic way delivering the changes that are directly related to the method invokation, while leaving out the implicit outcomes like reindexing of the rest of the Array.
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