You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP
Socket
Book a DemoInstallSign in
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

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