npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

json-patch-extended

v0.1.2

Published

Starcounter-Jack's JSON-Patch with additional capabilities

Downloads

519

Readme

JSON-Patch Extended

Includes everything from Starcounter-Jack's JSON-Patch:

  • apply patches
  • validate a sequence of patches
  • observe for changes (and generate patches when a change is detected)
  • compare two objects (to obtain the difference)

Plus addtional features:

  • reverse to reverse the effects of a sequence of patches
  • Simplified by being TypeScript free and packaged in one flavor

Does this follow standards?

JSON-Patch (RFC6902) is a standard format that allows you to update a JSON document by sending the changes rather than the whole document.

This repo deviates just a bit from that standard, but only with additions. The additions are as follows:

  • During generation of patches, all remove ops include a value property and all replace ops include a old property. In both cases, the additional property stores the old value at the path. This is an aide for the new reverse method.

Install

Install the current version (and save it as a dependency):

npm

$ npm install json-patch-extended --save

bower

$ bower install json-patch-extended --save

Adding to your project

In a web browser

Include dist/json-patch-extended.min.js

In Node.js

Call require to get the instance:

var jsonpatch = require('json-patch-extended')

Or use import in ES6:

import jsonpatch from 'json-patch-extended'

Usage

Applying patches:

var myobj = { firstName:"Albert", contactDetails: { phoneNumbers: [ ] } };
var patches = [
   {op:"replace", path:"/firstName", value:"Joachim" },
   {op:"add", path:"/lastName", value:"Wester" },
   {op:"add", path:"/contactDetails/phoneNumbers/0", value:{ number:"555-123" }  }
   ];
jsonpatch.apply( myobj, patches );
// myobj == { firstName:"Joachim", lastName:"Wester", contactDetails:{ phoneNumbers[ {number:"555-123"} ] } };

Generating patches:

var myobj = { firstName:"Joachim", lastName:"Wester", contactDetails: { phoneNumbers: [ { number:"555-123" }] } };
var observer = jsonpatch.observe( myobj );
myobj.firstName = "Albert";
myobj.contactDetails.phoneNumbers[0].number = "123";
myobj.contactDetails.phoneNumbers.push({number:"456"});
var patches = jsonpatch.generate(observer);
// patches  == [
//   { op:"replace", path="/firstName", value:"Albert", old:"Joachim"},
//   { op:"replace", path="/contactDetails/phoneNumbers/0/number", value:"123", old:"555-123"},
//   { op:"add", path="/contactDetails/phoneNumbers/1", value:{number:"456"}}];

Comparing two object trees:

var objA = {user: {firstName: "Albert", lastName: "Einstein"}};
var objB = {user: {firstName: "Albert", lastName: "Collins"}};
var diff = jsonpatch.compare(objA, objB));
//diff == [{op: "replace", path: "/user/lastName", value: "Collins", old: "Einstein"}]

Validating a sequence of patches:

var obj = {user: {firstName: "Albert"}};
var patches = [{op: "replace", path: "/user/firstName", value: "Albert"}, {op: "replace", path: "/user/lastName", value: "Einstein"}];
var errors = jsonpatch.validate(patches, obj);
if (errors.length == 0) {
 //there are no errors!
}
else {
  for (var i=0; i < errors.length; i++) {
    if (!errors[i]) {
      console.log("Valid patch at index", i, patches[i]);
    }
    else {
      console.error("Invalid patch at index", i, errors[i], patches[i]);
    }
  }
}

Reversing patches:

var patches = [
   {op:"replace", path:"/firstName", value:"Joachim", old:"Albert" },
   {op:"add", path:"/lastName", value:"Wester" },
   {op:"remove", path:"/contactDetails/phoneNumbers/0", value:{ number:"555-123" }  }
   ];
jsonpatch.reverse( patches );
// myobj == [
//   {op:"replace", path:"/firstName", value:"Albert", old:"Joachim" },
//   {op:"remove", path:"/lastName", value:"Wester" },
//   {op:"add", path:"/contactDetails/phoneNumbers/0", value:{ number:"555-123" }  }
//   ];

API

jsonpatch.apply (obj Object, patches Array, validate Boolean) : boolean

Applies patches array on obj.

If the validate parameter is set to true, the patch is extensively validated before applying. An invalid patch results in throwing an error (see jsonpatch.validate for more information about the error object).

Returns an array of results - one item for each item in patches. The type of each item depends on type of operation applied

  • test - boolean result of the test
  • remove, replace and move - original object that has been removed
  • add (only when adding to an array) - index at which item has been inserted (useful when using - alias)

jsonpatch.observe (obj Object, callback Function (optional)) : observer Object

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

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 (length 0).

jsonpatch.unobserve (obj Object, observer Object) : void

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.

jsonpatch.compare (obj1 Object, obj2 Object) : patches Array

Compares object trees obj1 and obj2 and returns the difference relative to obj1 as a patches array.

If there are no differences, returns an empty array (length 0).

jsonpatch.reverse (patches Array) : patches Array

Reverses a patches array. (Pass result to jsonpatch.apply to apply to an object).

Patches are reversed according to the following:

  • add - becomes remove
  • remove - becomes add
  • replace - old and value are switched
  • copy, move, and test - ignored

jsonpatch.validate (patches Array, tree Object (optional)) : error JsonPatchError

Validates a sequence of operations. If tree parameter is provided, the sequence is additionally validated against the object tree.

If there are no errors, returns undefined. If there is an errors, returns a JsonPatchError object with the following properties:

  • name String - short error code
  • message String - long human readable error message
  • index Number - index of the operation in the sequence
  • operation Object - reference to the operation
  • tree Object - reference to the tree

Possible errors:

Error name | Error message ------------------------------|------------ SEQUENCE_NOT_AN_ARRAY | Patch sequence must be an array OPERATION_NOT_AN_OBJECT | Operation is not an object OPERATION_OP_INVALID | Operation op property is not one of operations defined in RFC-6902 OPERATION_PATH_INVALID | Operation path property is not a valid string OPERATION_FROM_REQUIRED | Operation from property is not present (applicable in move and copy operations) OPERATION_VALUE_REQUIRED | Operation value property is not present, or undefined (applicable in add, replace and test operations) OPERATION_VALUE_CANNOT_CONTAIN_UNDEFINED | Operation value property object has at least one undefined value (applicable in add, replace and test operations) OPERATION_PATH_CANNOT_ADD | Cannot perform an add operation at the desired path OPERATION_PATH_UNRESOLVABLE | Cannot perform the operation at a path that does not exist OPERATION_FROM_UNRESOLVABLE | Cannot perform the operation from a path that does not exist OPERATION_PATH_ILLEGAL_ARRAY_INDEX | Expected an unsigned base-10 integer value, making the new referenced value the array element with the zero-based index OPERATION_VALUE_OUT_OF_BOUNDS | The specified index MUST NOT be greater than the number of elements in the array

undefineds (JS to JSON projection)

As undefined type does not exist in JSON, it's also not a valid value of JSON Patch operation. Therefore jsonpatch will not generate JSON Patches that sets anything to undefined.

Whenever a value is set to undefined in JS, JSON-Patch methods generate and compare will treat it similarly to how JavaScript method JSON.stringify (MDN) treats them:

If undefined (...) is encountered during conversion it is either omitted (when it is found in an object) or censored to null (when it is found in an array).

See the ECMAScript spec for details.

License

MIT