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

fast-json-patch

Package Overview
Dependencies
Maintainers
1
Versions
46
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fast-json-patch - npm Package Compare versions

Comparing version 0.0.2 to 0.3.5

.idea/libraries/Generated_files.xml

33

package.json
{
"name": "fast-json-patch",
"version": "0.0.2",
"version": "0.3.5",
"description": "JSON-Patch allows you to update a JSON document by sending the changes rather than the whole document.",
"homepage": "https://github.com/Starcounter-Jack/JSON-Patch",
"keywords": [
"json",
"patch",
"http",
"rest"
],
"keywords": ["json", "patch", "http", "rest"],
"repository": {

@@ -19,17 +14,13 @@ "type": "git",

},
"author": "Joachim Wester <joachimwester@me.com> (http://www.starcounter.com/)",
"licenses": [
{
"type": "MIT",
"url": "http://www.opensource.org/licenses/MIT"
}
],
"author": {
"name": "Joachim Wester",
"email": "joachimwester@me.com",
"url": "http://www.starcounter.com/"
},
"licenses": [ {
"type": "MIT",
"url": "http://www.opensource.org/licenses/MIT"
} ],
"main": "./src/json-patch-duplex",
"engines": {
"node": ">= 0.4.0"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"license": "MIT"
"engines": { "node": ">= 0.4.0" }
}
JSON-Patch
==========
===============

@@ -26,2 +26,3 @@ A leaner and meaner implementation of JSON-Patch. Small footprint. High performance.

* ES6/7 Object.observe() is used when available.
* Tested in IE 8-10, Firefox, Chrome and Node.js

@@ -42,4 +43,10 @@ ## Roadmap

Add `fast-json-patch` to dependencies list in your project's `package.json`, then run `npm install`. After installation, you are ready to go with require:
Install the current version (and save it as a dependency in package.json):
```
$ npm install fast-json-patch --save
```
Call require to get the instance:
```js

@@ -49,2 +56,5 @@ var jsonpatch = require('fast-json-patch')

:bulb: Node.js supports native `Object.observe` in preview release 0.11.x (and only when started with `--harmony_observation` flag). With stable versions of Node, a shimmed version of `Object.observe` is used.
## Usage

@@ -98,1 +108,63 @@

- Run command `jasmine-node --matchall --config duplex yes src/test.js src/test-duplex.js`
## API
#### jsonpatch.apply (`obj` Object, `patches` Array) : boolean
Available in *json-patch.js* and *json-patch-duplex.js*
Applies `patches` array on `obj`.
If patch was succesfully applied, returns `true`. Otherwise returns `false`.
If there was a `test` patch in `patches` array, returns the result of the test.
If there was more then one patch in the array, the result of the last patch is returned.
#### jsonpatch.observe (`obj` Object, `callback` Function (optional)) : `observer` Object
Available in *json-patch-duplex.js*
Sets up an deep observer on `obj` that listens for changes in object tree. When changes are detected, the optional
callback is called with the generated patches array as the parameter.
Returns `observer`.
#### jsonpatch.generate (`obj` Object, `observer` Object) : `patches` Array
Available in *json-patch-duplex.js*
If there are pending changes in `obj`, returns them synchronously. If a `callback` was defined in `observe`
method, it will be triggered synchronously as well.
If there are no pending changes in `obj`, returns an empty array.
#### jsonpatch.unobserve (`obj` Object, `observer` Object) : void
Available in *json-patch-duplex.js*
Destroys the observer set up on `obj`.
Any remaining changes are delivered synchronously (as in `jsonpatch.generate`). Note: this is different that ES6/7 `Object.unobserve`, which delivers remaining changes asynchronously.
## Changelog
#### 0.3.5 (Oct 28, 2013)
Bugfix:
- issues with calling observe/unobserve method on an object multiple times in Chrome (native Object.observe) ([#20](https://github.com/Starcounter-Jack/JSON-Patch/issues/20))
#### 0.3.4 (Oct 16, 2013)
Bugfix:
- generate array item `remove` patches in reverse order, so they can be correctly applied in order they were generated ([#16](https://github.com/Starcounter-Jack/JSON-Patch/issues/16))
#### 0.3.3 (Oct 11, 2013)
Bugfixes:
- properly escape `~` and `/` characters in poiner paths ([#19](https://github.com/Starcounter-Jack/JSON-Patch/pull/19))
- generated patch contained array `length` (only in native Object.observe version) ([#14](https://github.com/Starcounter-Jack/JSON-Patch/issues/14))
- `jsonpatch.unobserve` now delivers pending changes immediately (previously last-minute changes could be lost)
- stability fixes for browsers with native `Object.observe` (Chrome)
- code cleanup
- removed sourcemap reference from output js file

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

// json-patch-duplex.js 0.3.5
// (c) 2013 Joachim Wester
// MIT license
var jsonpatch;

@@ -17,39 +20,18 @@ (function (jsonpatch) {

move: function (obj, key, tree) {
var temp = {
op: "_get",
path: this.from
};
var temp = { op: "_get", path: this.from };
apply(tree, [temp]);
apply(tree, [
temp
{ op: "remove", path: this.from }
]);
apply(tree, [
{
op: "remove",
path: this.from
}
{ op: "add", path: this.path, value: temp.value }
]);
apply(tree, [
{
op: "add",
path: this.path,
value: temp.value
}
]);
return true;
},
copy: function (obj, key, tree) {
var temp = {
op: "_get",
path: this.from
};
var temp = { op: "_get", path: this.from };
apply(tree, [temp]);
apply(tree, [
temp
{ op: "add", path: this.path, value: temp.value }
]);
apply(tree, [
{
op: "add",
path: this.path,
value: temp.value
}
]);
return true;

@@ -64,11 +46,15 @@ },

};
var arrOps = {
add: function (arr, i) {
arr.splice(i, 0, this.value);
return true;
},
remove: function (arr, i) {
arr.splice(i, 1);
return true;
},
replace: function (arr, i) {
arr[i] = this.value;
return true;
},

@@ -80,8 +66,8 @@ move: objOps.move,

};
var observeOps = {
'new': function (patches, path) {
//single quotes needed because 'new' is a keyword in IE8
var patch = {
op: "add",
path: path + "/" + this.name,
path: path + escapePathComponent(this.name),
value: this.object[this.name]

@@ -94,3 +80,3 @@ };

op: "remove",
path: path + "/" + this.name
path: path + escapePathComponent(this.name)
};

@@ -102,3 +88,3 @@ patches.push(patch);

op: "replace",
path: path + "/" + this.name,
path: path + escapePathComponent(this.name),
value: this.object[this.name]

@@ -109,51 +95,130 @@ };

};
// ES6 symbols are not here yet. Used to calculate the json pointer to each object
function markPaths(observer, node) {
for(var key in node) {
if(node.hasOwnProperty(key)) {
var kid = node[key];
if(kid instanceof Object) {
Object.unobserve(kid, observer);
kid.____Path = node.____Path + "/" + key;
markPaths(observer, kid);
function escapePathComponent(str) {
if (str.indexOf('/') === -1 && str.indexOf('~') === -1)
return str;
return str.replace(/~/g, '~0').replace(/\//g, '~1');
}
function _getPathRecursive(root, obj) {
var found;
for (var key in root) {
if (root.hasOwnProperty(key)) {
if (root[key] === obj) {
return escapePathComponent(key) + '/';
} else if (typeof root[key] === 'object') {
found = _getPathRecursive(root[key], obj);
if (found != '') {
return escapePathComponent(key) + '/' + found;
}
}
}
}
return '';
}
// Detach poor mans ES6 symbols
function clearPaths(observer, node) {
delete node.____Path;
Object.observe(node, observer);
for(var key in node) {
if(node.hasOwnProperty(key)) {
var kid = node[key];
if(kid instanceof Object) {
clearPaths(observer, kid);
}
}
function getPath(root, obj) {
if (root === obj) {
return '/';
}
var path = _getPathRecursive(root, obj);
if (path === '') {
throw new Error("Object not found in root");
}
return '/' + path;
}
var beforeDict = [];
//var callbacks = []; this has no purpose
jsonpatch.intervals;
var Mirror = (function () {
function Mirror(obj) {
this.observers = [];
this.obj = obj;
}
return Mirror;
})();
var ObserverInfo = (function () {
function ObserverInfo(callback, observer) {
this.callback = callback;
this.observer = observer;
}
return ObserverInfo;
})();
function getMirror(obj) {
for (var i = 0, ilen = beforeDict.length; i < ilen; i++) {
if (beforeDict[i].obj === obj) {
return beforeDict[i];
}
}
}
function getObserverFromMirror(mirror, callback) {
for (var j = 0, jlen = mirror.observers.length; j < jlen; j++) {
if (mirror.observers[j].callback === callback) {
return mirror.observers[j].observer;
}
}
}
function removeObserverFromMirror(mirror, observer) {
for (var j = 0, jlen = mirror.observers.length; j < jlen; j++) {
if (mirror.observers[j].observer === observer) {
mirror.observers.splice(j, 1);
return;
}
}
}
function unobserve(root, observer) {
generate(observer);
if (Object.observe) {
_unobserve(observer, root);
} else {
clearTimeout(observer.next);
}
var mirror = getMirror(root);
removeObserverFromMirror(mirror, observer);
}
jsonpatch.unobserve = unobserve;
function observe(obj, callback) {
var patches = [];
var root = obj;
if(Object.observe) {
var observer = function (arr) {
if(!root.___Path) {
Object.unobserve(root, observer);
root.____Path = "";
markPaths(observer, root);
var a = 0, alen = arr.length;
while(a < alen) {
if(arr[a].name != "____Path") {
observeOps[arr[a].type].call(arr[a], patches, arr[a].object.____Path);
}
a++;
var observer;
var mirror = getMirror(obj);
if (!mirror) {
mirror = new Mirror(obj);
beforeDict.push(mirror);
} else {
observer = getObserverFromMirror(mirror, callback);
}
if (observer) {
return observer;
}
if (Object.observe) {
observer = function (arr) {
//This "refresh" is needed to begin observing new object properties
_unobserve(observer, obj);
_observe(observer, obj);
var a = 0, alen = arr.length;
while (a < alen) {
if (!(arr[a].name === 'length' && _isArray(arr[a].object)) && !(arr[a].name === '__Jasmine_been_here_before__')) {
observeOps[arr[a].type].call(arr[a], patches, getPath(root, arr[a].object));
}
clearPaths(observer, root);
a++;
}
if(callback) {
callback(patches);
if (patches) {
if (callback) {
callback(patches);
}
}

@@ -164,30 +229,13 @@ observer.patches = patches;

} else {
observer = {
};
var mirror;
for(var i = 0, ilen = beforeDict.length; i < ilen; i++) {
if(beforeDict[i].obj === obj) {
mirror = beforeDict[i];
break;
}
}
if(!mirror) {
mirror = {
obj: obj
};
beforeDict.push(mirror);
}
mirror.value = JSON.parse(JSON.stringify(obj))// Faster than ES5 clone - http://jsperf.com/deep-cloning-of-objects/5
;
if(callback) {
observer = {};
mirror.value = JSON.parse(JSON.stringify(obj));
if (callback) {
//callbacks.push(callback); this has no purpose
observer.callback = callback;
var next;
var intervals = this.intervals || [
100,
1000,
10000,
60000
];
observer.next = null;
var intervals = this.intervals || [100, 1000, 10000, 60000];
var currentInterval = 0;
var dirtyCheck = function () {

@@ -197,7 +245,7 @@ generate(observer);

var fastCheck = function () {
clearTimeout(next);
next = setTimeout(function () {
clearTimeout(observer.next);
observer.next = setTimeout(function () {
dirtyCheck();
currentInterval = 0;
next = setTimeout(slowCheck, intervals[currentInterval++]);
observer.next = setTimeout(slowCheck, intervals[currentInterval++]);
}, 0);

@@ -207,11 +255,8 @@ };

dirtyCheck();
if(currentInterval == intervals.length) {
if (currentInterval == intervals.length)
currentInterval = intervals.length - 1;
}
next = setTimeout(slowCheck, intervals[currentInterval++]);
observer.next = setTimeout(slowCheck, intervals[currentInterval++]);
};
if(typeof window !== 'undefined') {
//not Node
if(window.addEventListener) {
//standards
if (typeof window !== 'undefined') {
if (window.addEventListener) {
window.addEventListener('mousedown', fastCheck);

@@ -221,3 +266,2 @@ window.addEventListener('mouseup', fastCheck);

} else {
//IE8
window.attachEvent('onmousedown', fastCheck);

@@ -228,3 +272,3 @@ window.attachEvent('onmouseup', fastCheck);

}
next = setTimeout(slowCheck, intervals[currentInterval++]);
observer.next = setTimeout(slowCheck, intervals[currentInterval++]);
}

@@ -234,15 +278,18 @@ }

observer.object = obj;
return _observe(observer, obj, patches);
mirror.observers.push(new ObserverInfo(callback, observer));
return _observe(observer, obj);
}
jsonpatch.observe = observe;
/// Listen to changes on an object tree, accumulate patches
function _observe(observer, obj, patches) {
if(Object.observe) {
function _observe(observer, obj) {
if (Object.observe) {
Object.observe(obj, observer);
for(var key in obj) {
if(obj.hasOwnProperty(key)) {
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
var v = obj[key];
if(v && typeof (v) === "object") {
_observe(observer, v, patches)//path+key);
;
if (v && typeof (v) === "object") {
_observe(observer, v);
}

@@ -254,9 +301,25 @@ }

}
function _unobserve(observer, obj) {
if (Object.observe) {
Object.unobserve(obj, observer);
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
var v = obj[key];
if (v && typeof (v) === "object") {
_unobserve(observer, v);
}
}
}
}
return observer;
}
function generate(observer) {
if(Object.observe) {
if (Object.observe) {
Object.deliverChangeRecords(observer);
} else {
var mirror;
for(var i = 0, ilen = beforeDict.length; i < ilen; i++) {
if(beforeDict[i].obj === observer.object) {
for (var i = 0, ilen = beforeDict.length; i < ilen; i++) {
if (beforeDict[i].obj === observer.object) {
mirror = beforeDict[i];

@@ -269,5 +332,5 @@ break;

var temp = observer.patches;
if(temp.length > 0) {
if (temp.length > 0) {
observer.patches = [];
if(observer.callback) {
if (observer.callback) {
observer.callback(temp);

@@ -279,12 +342,11 @@ }

jsonpatch.generate = generate;
var _objectKeys;
if(Object.keys) {
//standards
if (Object.keys) {
_objectKeys = Object.keys;
} else {
//IE8 shim
_objectKeys = function (obj) {
var keys = [];
for(var o in obj) {
if(obj.hasOwnProperty(o)) {
for (var o in obj) {
if (obj.hasOwnProperty(o)) {
keys.push(o);

@@ -296,2 +358,3 @@ }

}
// Dirty check if obj is different from mirror, generate patches and update mirror

@@ -303,17 +366,14 @@ function _generate(mirror, obj, patches, path) {

var deleted = false;
for(var t = 0; t < oldKeys.length; t++) {
for (var t = oldKeys.length - 1; t >= 0; t--) {
var key = oldKeys[t];
var oldVal = mirror[key];
if(obj.hasOwnProperty(key)) {
if (obj.hasOwnProperty(key)) {
var newVal = obj[key];
if(oldVal instanceof Object) {
_generate(oldVal, newVal, patches, path + "/" + key);
if (oldVal instanceof Object) {
_generate(oldVal, newVal, patches, path + "/" + escapePathComponent(key));
} else {
if(oldVal != newVal) {
if (oldVal != newVal) {
changed = true;
patches.push({
op: "replace",
path: path + "/" + key,
value: newVal
});
patches.push({ op: "replace", path: path + "/" + escapePathComponent(key), value: newVal });
mirror[key] = newVal;

@@ -323,30 +383,25 @@ }

} else {
patches.push({
op: "remove",
path: path + "/" + key
});
deleted = true// property has been deleted
;
patches.push({ op: "remove", path: path + "/" + escapePathComponent(key) });
delete mirror[key];
deleted = true;
}
}
if(!deleted && newKeys.length == oldKeys.length) {
if (!deleted && newKeys.length == oldKeys.length) {
return;
}
for(var t = 0; t < newKeys.length; t++) {
for (var t = 0; t < newKeys.length; t++) {
var key = newKeys[t];
if(!mirror.hasOwnProperty(key)) {
patches.push({
op: "add",
path: path + "/" + key,
value: obj[key]
});
if (!mirror.hasOwnProperty(key)) {
patches.push({ op: "add", path: path + "/" + escapePathComponent(key), value: obj[key] });
mirror[key] = JSON.parse(JSON.stringify(obj[key]));
}
}
}
var _isArray;
if(Array.isArray) {
//standards; http://jsperf.com/isarray-shim/4
if (Array.isArray) {
_isArray = Array.isArray;
} else {
//IE8 shim
_isArray = function (obj) {

@@ -356,20 +411,20 @@ return obj.push && typeof obj.length === 'number';

}
/// Apply a json-patch operation on an object tree
function apply(tree, patches, listen) {
function apply(tree, patches) {
var result = false, p = 0, plen = patches.length, patch;
while(p < plen) {
while (p < plen) {
patch = patches[p];
// Find the object
var keys = patch.path.split('/');
var obj = tree;
var t = 1;//skip empty element - http://jsperf.com/to-shift-or-not-to-shift
var t = 1;
var len = keys.length;
while(true) {
if(_isArray(obj)) {
while (true) {
if (_isArray(obj)) {
var index = parseInt(keys[t], 10);
t++;
if(t >= len) {
result = arrOps[patch.op].call(patch, obj, index, tree)// Apply patch
;
if (t >= len) {
result = arrOps[patch.op].call(patch, obj, index, tree);
break;

@@ -380,10 +435,7 @@ }

var key = keys[t];
if(key.indexOf('~') != -1) {
key = key.replace('~1', '/').replace('~0', '~');
}// escape chars
if (key.indexOf('~') != -1)
key = key.replace(/~1/g, '/').replace(/~0/g, '~');
t++;
if(t >= len) {
result = objOps[patch.op].call(patch, obj, key, tree)// Apply patch
;
if (t >= len) {
result = objOps[patch.op].call(patch, obj, key, tree);
break;

@@ -400,7 +452,8 @@ }

})(jsonpatch || (jsonpatch = {}));
if(typeof exports !== "undefined") {
if (typeof exports !== "undefined") {
exports.apply = jsonpatch.apply;
exports.observe = jsonpatch.observe;
exports.unobserve = jsonpatch.unobserve;
exports.generate = jsonpatch.generate;
}
//@ sourceMappingURL=json-patch-duplex.js.map

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

// json-patch-duplex.js 0.3
// json-patch-duplex.js 0.3.5
// (c) 2013 Joachim Wester

@@ -56,8 +56,11 @@ // MIT license

arr.splice(i, 0, this.value);
return true;
},
remove: function (arr, i) {
arr.splice(i, 1);
return true;
},
replace: function (arr, i) {
arr[i] = this.value;
return true;
},

@@ -74,3 +77,3 @@ move: objOps.move,

op: "add",
path: path + "/" + this.name,
path: path + escapePathComponent(this.name),
value: this.object[this.name]};

@@ -82,3 +85,3 @@ patches.push(patch);

op: "remove",
path: path + "/" + this.name
path: path + escapePathComponent(this.name)
};

@@ -90,3 +93,3 @@ patches.push(patch);

op: "replace",
path: path + "/" + this.name,
path: path + escapePathComponent(this.name),
value: this.object[this.name]

@@ -98,81 +101,146 @@ };

// ES6 symbols are not here yet. Used to calculate the json pointer to each object
function markPaths(observer, node) {
for (var key in node) {
if (node.hasOwnProperty(key)) {
var kid = node[key];
if (kid instanceof Object) {
Object.unobserve(kid, observer);
kid.____Path = node.____Path + "/" + key;
markPaths(observer, kid);
function escapePathComponent (str) {
if (str.indexOf('/') === -1 && str.indexOf('~') === -1) return str;
return str.replace(/~/g, '~0').replace(/\//g, '~1');
}
function _getPathRecursive(root:Object, obj:Object):string {
var found;
for (var key in root) {
if (root.hasOwnProperty(key)) {
if (root[key] === obj) {
return escapePathComponent(key) + '/';
}
else if (typeof root[key] === 'object') {
found = _getPathRecursive(root[key], obj);
if (found != '') {
return escapePathComponent(key) + '/' + found;
}
}
}
}
return '';
}
// Detach poor mans ES6 symbols
function clearPaths(observer, node) {
delete node.____Path;
Object.observe(node, observer);
for (var key in node) {
if (node.hasOwnProperty(key)) {
var kid = node[key];
if (kid instanceof Object) {
clearPaths(observer, kid);
}
}
function getPath(root:Object, obj:Object):string {
if (root === obj) {
return '/';
}
var path = _getPathRecursive(root, obj);
if (path === '') {
throw new Error("Object not found in root");
}
return '/' + path;
}
var beforeDict = [];
//var callbacks = []; this has no purpose
export var intervals;
class Mirror {
obj: any;
observers = [];
constructor(obj:any){
this.obj = obj;
}
}
class ObserverInfo {
callback: any;
observer: any;
constructor(callback, observer){
this.callback = callback;
this.observer = observer;
}
}
function getMirror(obj:any):any {
for (var i = 0, ilen = beforeDict.length; i < ilen; i++) {
if (beforeDict[i].obj === obj) {
return beforeDict[i];
}
}
}
function getObserverFromMirror(mirror:any, callback):any {
for (var j = 0, jlen = mirror.observers.length; j < jlen; j++) {
if (mirror.observers[j].callback === callback) {
return mirror.observers[j].observer;
}
}
}
function removeObserverFromMirror(mirror:any, observer):any {
for (var j = 0, jlen = mirror.observers.length; j < jlen; j++) {
if (mirror.observers[j].observer === observer) {
mirror.observers.splice(j, 1);
return;
}
}
}
export function unobserve(root, observer) {
generate(observer);
if(Object.observe) {
_unobserve(observer, root);
}
else {
clearTimeout(observer.next);
}
var mirror = getMirror(root);
removeObserverFromMirror(mirror, observer);
}
export function observe(obj:any, callback):any {
var patches = [];
var root = obj;
if (Object.observe) {
var observer = function (arr) {
var observer;
var mirror = getMirror(obj);
if (!root.___Path) {
if (!mirror) {
mirror = new Mirror(obj);
beforeDict.push(mirror);
} else {
observer = getObserverFromMirror(mirror, callback);
}
Object.unobserve(root, observer);
root.____Path = "";
markPaths(observer, root);
if(observer){
return observer;
}
var a = 0
, alen = arr.length;
while (a < alen) {
if (arr[a].name != "____Path") {
observeOps[arr[a].type].call(arr[a], patches, arr[a].object.____Path);
}
a++;
if (Object.observe) {
observer = function (arr) {
//This "refresh" is needed to begin observing new object properties
_unobserve(observer, obj);
_observe(observer, obj);
var a = 0
, alen = arr.length;
while (a < alen) {
if (
!(arr[a].name === 'length' && _isArray(arr[a].object))
&& !(arr[a].name === '__Jasmine_been_here_before__')
) {
observeOps[arr[a].type].call(arr[a], patches, getPath(root, arr[a].object));
}
a++;
}
clearPaths(observer, root);
if (patches) {
if (callback) {
callback(patches);
}
}
if (callback) {
callback(patches);
}
observer.patches = patches;
patches = [];
};
}
else {
} else {
observer = {};
var mirror;
for (var i = 0, ilen = beforeDict.length; i < ilen; i++) {
if (beforeDict[i].obj === obj) {
mirror = beforeDict[i];
break;
}
}
if (!mirror) {
mirror = {obj: obj};
beforeDict.push(mirror);
}
mirror.value = JSON.parse(JSON.stringify(obj)); // Faster than ES5 clone - http://jsperf.com/deep-cloning-of-objects/5

@@ -183,3 +251,3 @@

observer.callback = callback;
var next;
observer.next = null;
var intervals = this.intervals || [100, 1000, 10000, 60000];

@@ -192,7 +260,7 @@ var currentInterval = 0;

var fastCheck = function () {
clearTimeout(next);
next = setTimeout(function () {
clearTimeout(observer.next);
observer.next = setTimeout(function () {
dirtyCheck();
currentInterval = 0;
next = setTimeout(slowCheck, intervals[currentInterval++]);
observer.next = setTimeout(slowCheck, intervals[currentInterval++]);
}, 0);

@@ -204,3 +272,3 @@ };

currentInterval = intervals.length - 1;
next = setTimeout(slowCheck, intervals[currentInterval++]);
observer.next = setTimeout(slowCheck, intervals[currentInterval++]);
};

@@ -219,3 +287,3 @@ if (typeof window !== 'undefined') { //not Node

}
next = setTimeout(slowCheck, intervals[currentInterval++]);
observer.next = setTimeout(slowCheck, intervals[currentInterval++]);
}

@@ -225,7 +293,10 @@ }

observer.object = obj;
return _observe(observer, obj, patches);
mirror.observers.push(new ObserverInfo(callback, observer));
return _observe(observer, obj);
}
/// Listen to changes on an object tree, accumulate patches
function _observe(observer:any, obj:any, patches:any[]):any {
function _observe(observer:any, obj:any):any {
if (Object.observe) {

@@ -237,3 +308,3 @@ Object.observe(obj, observer);

if (v && typeof (v) === "object") {
_observe(observer, v, patches); //path+key);
_observe(observer, v);
}

@@ -246,2 +317,17 @@ }

function _unobserve(observer:any, obj:any):any {
if (Object.observe) {
Object.unobserve(obj, observer);
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
var v:any = obj[key];
if (v && typeof (v) === "object") {
_unobserve(observer, v);
}
}
}
}
return observer;
}
export function generate(observer) {

@@ -294,3 +380,5 @@ if (Object.observe) {

for (var t = 0; t < oldKeys.length; t++) {
//if ever "move" operation is implemented here, make sure this test runs OK: "should not generate the same patch twice (move)"
for (var t = oldKeys.length - 1; t >= 0; t--) {
var key = oldKeys[t];

@@ -301,3 +389,3 @@ var oldVal = mirror[key];

if (oldVal instanceof Object) {
_generate(oldVal, newVal, patches, path + "/" + key);
_generate(oldVal, newVal, patches, path + "/" + escapePathComponent(key));
}

@@ -307,3 +395,3 @@ else {

changed = true;
patches.push({op: "replace", path: path + "/" + key, value: newVal});
patches.push({op: "replace", path: path + "/" + escapePathComponent(key), value: newVal});
mirror[key] = newVal;

@@ -314,3 +402,4 @@ }

else {
patches.push({op: "remove", path: path + "/" + key});
patches.push({op: "remove", path: path + "/" + escapePathComponent(key)});
delete mirror[key];
deleted = true; // property has been deleted

@@ -327,3 +416,4 @@ }

if (!mirror.hasOwnProperty(key)) {
patches.push({op: "add", path: path + "/" + key, value: obj[key]});
patches.push({op: "add", path: path + "/" + escapePathComponent(key), value: obj[key]});
mirror[key] = JSON.parse(JSON.stringify(obj[key]));
}

@@ -344,3 +434,3 @@ }

/// Apply a json-patch operation on an object tree
export function apply(tree:any, patches:any[], listen?:any):bool {
export function apply(tree:any, patches:any[]):boolean {
var result = false

@@ -370,3 +460,3 @@ , p = 0

if (key.indexOf('~') != -1)
key = key.replace('~1', '/').replace('~0', '~'); // escape chars
key = key.replace(/~1/g, '/').replace(/~0/g, '~'); // escape chars
t++;

@@ -391,3 +481,4 @@ if (t >= len) {

exports.observe = jsonpatch.observe;
exports.unobserve = jsonpatch.unobserve;
exports.generate = jsonpatch.generate;
}

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

// json-patch.js 0.3
// json-patch.js 0.3.5
// (c) 2013 Joachim Wester

@@ -20,39 +20,18 @@ // MIT license

move: function (obj, key, tree) {
var temp = {
op: "_get",
path: this.from
};
var temp = { op: "_get", path: this.from };
apply(tree, [temp]);
apply(tree, [
temp
{ op: "remove", path: this.from }
]);
apply(tree, [
{
op: "remove",
path: this.from
}
{ op: "add", path: this.path, value: temp.value }
]);
apply(tree, [
{
op: "add",
path: this.path,
value: temp.value
}
]);
return true;
},
copy: function (obj, key, tree) {
var temp = {
op: "_get",
path: this.from
};
var temp = { op: "_get", path: this.from };
apply(tree, [temp]);
apply(tree, [
temp
{ op: "add", path: this.path, value: temp.value }
]);
apply(tree, [
{
op: "add",
path: this.path,
value: temp.value
}
]);
return true;

@@ -67,11 +46,15 @@ },

};
var arrOps = {
add: function (arr, i) {
arr.splice(i, 0, this.value);
return true;
},
remove: function (arr, i) {
arr.splice(i, 1);
return true;
},
replace: function (arr, i) {
arr[i] = this.value;
return true;
},

@@ -83,8 +66,7 @@ move: objOps.move,

};
var _isArray;
if(Array.isArray) {
//standards; http://jsperf.com/isarray-shim/4
if (Array.isArray) {
_isArray = Array.isArray;
} else {
//IE8 shim
_isArray = function (obj) {

@@ -94,20 +76,20 @@ return obj.push && typeof obj.length === 'number';

}
/// Apply a json-patch operation on an object tree
function apply(tree, patches, listen) {
function apply(tree, patches) {
var result = false, p = 0, plen = patches.length, patch;
while(p < plen) {
while (p < plen) {
patch = patches[p];
// Find the object
var keys = patch.path.split('/');
var obj = tree;
var t = 1;//skip empty element - http://jsperf.com/to-shift-or-not-to-shift
var t = 1;
var len = keys.length;
while(true) {
if(_isArray(obj)) {
while (true) {
if (_isArray(obj)) {
var index = parseInt(keys[t], 10);
t++;
if(t >= len) {
result = arrOps[patch.op].call(patch, obj, index, tree)// Apply patch
;
if (t >= len) {
result = arrOps[patch.op].call(patch, obj, index, tree);
break;

@@ -118,10 +100,7 @@ }

var key = keys[t];
if(key.indexOf('~') != -1) {
key = key.replace('~1', '/').replace('~0', '~');
}// escape chars
if (key.indexOf('~') != -1)
key = key.replace(/~1/g, '/').replace(/~0/g, '~');
t++;
if(t >= len) {
result = objOps[patch.op].call(patch, obj, key, tree)// Apply patch
;
if (t >= len) {
result = objOps[patch.op].call(patch, obj, key, tree);
break;

@@ -138,5 +117,5 @@ }

})(jsonpatch || (jsonpatch = {}));
if(typeof exports !== "undefined") {
if (typeof exports !== "undefined") {
exports.apply = jsonpatch.apply;
}
//@ sourceMappingURL=json-patch.js.map

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

// json-patch.js 0.3
// json-patch.js 0.3.5
// (c) 2013 Joachim Wester

@@ -50,8 +50,11 @@ // MIT license

arr.splice(i, 0, this.value);
return true;
},
remove: function (arr, i) {
arr.splice(i, 1);
return true;
},
replace: function (arr, i) {
arr[i] = this.value;
return true;
},

@@ -65,3 +68,3 @@ move: objOps.move,

var _isArray;
if(Array.isArray) { //standards; http://jsperf.com/isarray-shim/4
if (Array.isArray) { //standards; http://jsperf.com/isarray-shim/4
_isArray = Array.isArray;

@@ -76,3 +79,3 @@ }

/// Apply a json-patch operation on an object tree
export function apply(tree:any, patches:any[], listen?:any):bool {
export function apply(tree:any, patches:any[]):boolean {
var result = false

@@ -82,3 +85,3 @@ , p = 0

, patch;
while(p < plen) {
while (p < plen) {
patch = patches[p];

@@ -103,3 +106,3 @@ // Find the object

if (key.indexOf('~') != -1)
key = key.replace('~1', '/').replace('~0', '~'); // escape chars
key = key.replace(/~1/g, '/').replace(/~0/g, '~'); // escape chars
t++;

@@ -119,3 +122,3 @@ if (t >= len) {

declare var exports: any;
declare var exports:any;

@@ -122,0 +125,0 @@ if (typeof exports !== "undefined") {

@@ -12,2 +12,5 @@ var obj, obj2, patches;

describe("JSON-Patch-Duplex", function () {
beforeEach(function () {
this.addMatchers({
/**

@@ -18,7 +21,8 @@ * This matcher is only needed in Chrome 28 (Chrome 28 cannot successfully compare observed objects immediately after they have been changed. Chrome 30 is unaffected)

*/
jasmine.Matchers.prototype.toEqualInJSON = function(obj) {
return JSON.stringify(this.actual) == JSON.stringify(obj);
};
toEqualInJson: function (expected) {
return JSON.stringify(this.actual) == JSON.stringify(expected);
}
});
});
describe("JSON-Patch-Duplex", function () {
describe("generate", function () {

@@ -43,2 +47,20 @@ it('should generate replace', function() {

it('should generate replace (escaped chars)', function() {
obj = { "/name/first":"Albert", "/name/last":"Einstein",
"~phone~/numbers":[ {number:"12345"}, {number:"45353"} ]};
var observer = jsonpatch.observe(obj);
obj['/name/first'] = "Joachim";
obj['/name/last'] = "Wester";
obj['~phone~/numbers'][0].number = "123";
obj['~phone~/numbers'][1].number = "456";
var patches = jsonpatch.generate(observer);
obj2 = { "/name/first":"Albert", "/name/last":"Einstein",
"~phone~/numbers":[ {number:"12345"}, {number:"45353"} ]};
jsonpatch.apply(obj2,patches);
expect(obj2).toEqual(obj);
});
it('should generate replace (2 observers)', function() {

@@ -97,2 +119,50 @@ var person1 = {firstName: "Alexandra", lastName: "Galbreath"};

it('should generate replace (changes in new array cell, primitive values)', function() {
arr = [1];
var observer = jsonpatch.observe(arr);
arr.push(2);
var patches = jsonpatch.generate(observer);
expect(patches).toEqual([{op: 'add', path: '/1', value: 2}]);
arr[0] = 3;
var patches = jsonpatch.generate(observer);
expect(patches).toEqual([{op: 'replace', path: '/0', value: 3}]);
arr[1] = 4;
var patches = jsonpatch.generate(observer);
expect(patches).toEqual([{op: 'replace', path: '/1', value: 4}]);
});
it('should generate replace (changes in new array cell, complex values)', function() {
arr = [
{
id: 1,
name: 'Ted'
}
];
var observer = jsonpatch.observe(arr);
arr.push({id: 2, name: 'Jerry'});
var patches = jsonpatch.generate(observer);
expect(patches).toEqual([{op: 'add', path: '/1', value: {id: 2, name: 'Jerry'}}]);
arr[0].id = 3;
var patches = jsonpatch.generate(observer);
expect(patches).toEqual([{op: 'replace', path: '/0/id', value: 3}]);
arr[1].id = 4;
var patches = jsonpatch.generate(observer);
expect(patches).toEqual([{op: 'replace', path: '/1/id', value: 4}]);
});
it('should generate add', function() {

@@ -113,6 +183,6 @@ obj = { lastName:"Einstein",

jsonpatch.apply(obj2,patches);
expect(obj2).toEqualInJSON(obj);
expect(obj2).toEqualInJson(obj);
});
it('should generate delete', function() {
it('should generate remove', function() {
obj = { lastName:"Einstein", firstName:"Albert",

@@ -132,4 +202,114 @@ phoneNumbers:[ {number:"12345"}, {number:"4234"} ]};

jsonpatch.apply(obj2,patches);
expect(obj2).toEqualInJSON(obj);
expect(obj2).toEqualInJson(obj);
});
it('should generate remove (array indexes should be sorted descending)', function() {
obj = { items: ["a", "b", "c"]};
var observer = jsonpatch.observe(obj);
obj.items.pop();
obj.items.pop();
patches = jsonpatch.generate(observer);
//array indexes must be sorted descending, otherwise there is an index collision in apply
expect(patches).toEqual([
{ op: 'remove', path: '/items/2' },
{ op: 'remove', path: '/items/1' }
]);
obj2 = { items: ["a", "b", "c"]};
jsonpatch.apply(obj2,patches);
expect(obj).toEqualInJson(obj2);
});
it('should not generate the same patch twice (replace)', function() {
obj = { lastName:"Einstein" };
var observer = jsonpatch.observe(obj);
obj.lastName = "Wester";
patches = jsonpatch.generate(observer);
expect(patches).toEqual([
{ op: 'replace', path: '/lastName', value: 'Wester' }
]);
patches = jsonpatch.generate(observer);
expect(patches).toEqual([]);
});
it('should not generate the same patch twice (add)', function() {
obj = { lastName:"Einstein" };
var observer = jsonpatch.observe(obj);
obj.firstName = "Albert";
patches = jsonpatch.generate(observer);
expect(patches).toEqual([
{ op: 'add', path: '/firstName', value: 'Albert' }
]);
patches = jsonpatch.generate(observer);
expect(patches).toEqual([]);
});
it('should not generate the same patch twice (remove)', function() {
obj = { lastName:"Einstein" };
var observer = jsonpatch.observe(obj);
delete obj.lastName;
patches = jsonpatch.generate(observer);
expect(patches).toEqual([
{ op: 'remove', path: '/lastName' }
]);
patches = jsonpatch.generate(observer);
expect(patches).toEqual([]);
});
//related issue: https://github.com/Starcounter-Jack/JSON-Patch/issues/14
it('should generate the same patch using Object.observe and shim', function() {
var arr1 = [
["Albert", "Einstein"],
["Erwin", "Shrodinger"]
];
var arr2 = arr1.slice();
var newRecord = ['Niels', 'Bohr'];
var observer1 = jsonpatch.observe(arr1);
arr1.push(newRecord);
var objectObservePatches = jsonpatch.generate(observer1);
var _observe = Object.observe;
Object.observe = undefined;
var observer2 = jsonpatch.observe(arr2);
arr2.push(newRecord);
var shimPatches = jsonpatch.generate(observer2);
expect(objectObservePatches).toEqual(shimPatches);
Object.observe = _observe;
});
/*it('should not generate the same patch twice (move)', function() { //"move" is not implemented yet in jsonpatch.generate
obj = { lastName: {str: "Einstein"} };
var observer = jsonpatch.observe(obj);
obj.lastName2 = obj.lastName;
delete obj.lastName;
patches = jsonpatch.generate(observer);
expect(patches).toEqual([
{ op: 'move', from: '/lastName', to: '/lastName2' }
]);
patches = jsonpatch.generate(observer);
expect(patches).toEqual([]);
});*/
});

@@ -269,3 +449,224 @@

});
it('should unobserve then observe again', function() {
var called = 0;
obj = { firstName:"Albert", lastName:"Einstein",
phoneNumbers:[ {number:"12345"}, {number:"45353"} ]};
jsonpatch.intervals = [10];
var observer = jsonpatch.observe(obj, function(patches) {
called++;
});
obj.firstName = 'Malvin';
waits(20);
runs(function(){
expect(called).toEqual(1);
jsonpatch.unobserve(obj, observer);
obj.firstName = 'Wilfred';
});
waits(20);
runs(function(){
expect(called).toEqual(1);
observer = jsonpatch.observe(obj, function(patches) {
called++;
});
obj.firstName = 'Megan';
});
waits(20);
runs(function(){
expect(called).toEqual(2);
});
});
it('should unobserve then observe again (deep value)', function() {
var called = 0;
obj = { firstName:"Albert", lastName:"Einstein",
phoneNumbers:[ {number:"12345"}, {number:"45353"} ]};
jsonpatch.intervals = [10];
var observer = jsonpatch.observe(obj, function(patches) {
called++;
});
obj.phoneNumbers[1].number = '555';
waits(20);
runs(function(){
expect(called).toEqual(1);
jsonpatch.unobserve(obj, observer);
obj.phoneNumbers[1].number = '556';
});
waits(20);
runs(function(){
expect(called).toEqual(1);
observer = jsonpatch.observe(obj, function(patches) {
called++;
});
obj.phoneNumbers[1].number = '557';
});
waits(20);
runs(function(){
expect(called).toEqual(2);
});
});
it('calling unobserve should deliver pending changes synchronously', function() {
var lastPatches = '';
obj = { firstName: "Albert", lastName: "Einstein",
phoneNumbers: [
{number: "12345"},
{number: "45353"}
]};
jsonpatch.intervals = [10];
var observer = jsonpatch.observe(obj, function (patches) {
lastPatches = patches;
});
obj.firstName = 'Malvin';
jsonpatch.unobserve(obj, observer);
expect(lastPatches[0].value).toBe('Malvin');
obj.firstName = 'Jonathan';
waits(20);
runs(function () {
expect(lastPatches[0].value).toBe('Malvin');
});
});
it("should handle callbacks that calls observe() and unobserve() internally", function () {
var obj = {
foo: 'bar'
};
var observer;
var callback = jasmine.createSpy('callback');
callback.plan = function(){
jsonpatch.unobserve(obj, observer);
jsonpatch.observe(obj, callback);
};
observer = jsonpatch.observe(obj, callback);
expect(callback.calls.length).toEqual(0);
obj.foo = 'bazz';
waitsFor(function () {
return callback.calls.length > 0;
}, 'callback calls', 1000);
runs(function () {
expect(callback.calls.length).toEqual(1);
callback.reset();
obj.foo = 'bazinga';
});
waitsFor(function () {
return callback.calls.length > 0;
}, 'callback calls', 1000);
runs(function () {
expect(callback.calls.length).toEqual(1);
});
});
});
describe("Registering multiple observers with the same callback", function () {
it("should register only one observer", function () {
var obj = {
foo: 'bar'
};
var callback = jasmine.createSpy('callback');
jsonpatch.observe(obj, callback);
jsonpatch.observe(obj, callback);
expect(callback.calls.length).toEqual(0);
obj.foo = 'bazz';
waitsFor(function () {
return callback.calls.length > 0;
}, 'callback call', 1000);
runs(function () {
expect(callback.calls.length).toEqual(1);
});
});
it("should return the same observer if callback has been already registered)", function () {
var obj = {
foo: 'bar'
};
var callback = jasmine.createSpy('callback');
var observer1 = jsonpatch.observe(obj, callback);
var observer2 = jsonpatch.observe(obj, callback);
expect(observer1).toBe(observer2);
});
it("should return a different observer if callback has been unregistered and registered again", function () {
var obj = {
foo: 'bar'
};
var callback = jasmine.createSpy('callback');
var observer1 = jsonpatch.observe(obj, callback);
jsonpatch.unobserve(obj, observer1);
var observer2 = jsonpatch.observe(obj, callback);
expect(observer1).not.toBe(observer2);
});
});
});

@@ -272,0 +673,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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