diff --git a/.gitignore b/.gitignore
index 540ff0e6..05939c84 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,12 +9,8 @@ npm-debug.log
.idea
# Typescript
-*.d.ts
+commonjs/*.d.ts
test/spec/typings/typingsSpec.js
-# compiled files
-src/*.js
-lib/*
-
# SauceLabs logs
*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index 7c35fe92..1950c4ba 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,6 @@
language: node_js
dist: trusty
-node_js: lts/*
+node_js: node
before_script:
- npm install
- npm run serve &
diff --git a/README.md b/README.md
index e1e9f262..404021fc 100644
--- a/README.md
+++ b/README.md
@@ -6,14 +6,12 @@ JSON-Patch
[](https://travis-ci.org/Starcounter-Jack/JSON-Patch)
With JSON-Patch, you can:
-- **applyPatch** to apply patches
-- **applyOperation** to apply single operations
+- **apply** patches (arrays) and single operations on JS object
- **validate** a sequence of patches
-- **observe** for changes (and generate patches when a change is detected)
-- **compare** two objects (to obtain the difference).
+- **observe** for changes and **generate** patches when a change is detected
+- **compare** two objects to obtain the difference
-
-[](https://travis-ci.org/Starcounter-Jack/JSON-Patch)
+Tested in IE11, Firefox, Chrome, Safari and Node.js
## Why you should use JSON-Patch
@@ -24,195 +22,70 @@ JSON Patch plays well with the HTTP PATCH verb (method) and REST style programmi
Mark Nottingham has a [nice blog]( http://www.mnot.net/blog/2012/09/05/patch) about it.
-## Footprint
-4 KB minified and gzipped (12 KB minified)
-
-## Performance
-
-##### [`add` benchmark](https://run.perf.zone/view/JSON-Patch-Add-Operation-1535541298893)
-
-
-
-##### [`replace` benchmark](https://run.perf.zone/view/JSON-Patch-Replace-Operation-1535540952263)
-
-
-
-Tested on 29.08.2018. Compared libraries:
-
-- [Starcounter-Jack/JSON-Patch](https://www.npmjs.com/package/fast-json-patch) 2.0.6
-- [bruth/jsonpatch-js](https://www.npmjs.com/package/json-patch) 0.7.0
-- [dharmafly/jsonpatch.js](https://www.npmjs.com/package/jsonpatch) 3.0.1
-- [jiff](https://www.npmjs.com/package/jiff) 0.7.3
-- [RFC6902](https://www.npmjs.com/package/rfc6902) 2.4.0
-
-We aim the tests to be fair. Our library puts performance as the #1 priority, while other libraries can have different priorities. If you'd like to update the benchmarks or add a library, please fork the [perf.zone](https://perf.zone) benchmarks linked above and open an issue to include new results.
-
-## Features
-* Allows you to apply patches on object trees for incoming traffic.
-* Allows you to freely manipulate object trees and then generate patches for outgoing traffic.
-* Tested in IE11, Firefox, Chrome, Safari and Node.js
-
## Install
-Install the current version (and save it as a dependency):
-
-### npm
+[Download as ZIP](https://github.com/Starcounter-Jack/JSON-Patch/archive/master.zip) or install the current version using a package manager (and save it as a dependency):
```sh
-$ npm install fast-json-patch --save
-```
-### bower
+# NPM
+npm install fast-json-patch --save
-```sh
-$ bower install fast-json-patch --save
+# or Bower
+bower install fast-json-patch --save
```
-### [download as ZIP](https://github.com/Starcounter-Jack/JSON-Patch/archive/master.zip)
-
## Adding to your project
### In a web browser
-Include `dist/fast-json-patch.js`.
+Load the bundled distribution script:
-### In Node.js
-
-Call require to get the instance:
-
-```js
-var jsonpatch = require('fast-json-patch')
+```html
+
```
-Or use ES6 style:
+In [browsers that support ECMAScript modules](https://caniuse.com/#feat=es6-module), the below code uses this library as a module:
-```js
-import { applyOperation } from 'fast-json-patch'
-```
-
-You can also require all API functions individually, all jsonpatch functions can be used as pure functions:
-
-```js
-const { applyOperation } = require('fast-json-patch');
-```
-
-## Usage
-
-#### Applying patches:
-
-```js
-var document = { firstName: "Albert", contactDetails: { phoneNumbers: [] } };
-var patch = [
- { op: "replace", path: "/firstName", value: "Joachim" },
- { op: "add", path: "/lastName", value: "Wester" },
- { op: "add", path: "/contactDetails/phoneNumbers/0", value: { number: "555-123" } }
-];
-document = jsonpatch.applyPatch(document, patch).newDocument;
-// document == { firstName: "Joachim", lastName: "Wester", contactDetails: { phoneNumbers: [{number:"555-123"}] } };
-```
-
-##### For apply individual operations you can use `applyOperation`
-
-`jsonpatch.applyOperation` accepts a single operation object instead of a sequence, and returns the object after applying the operation. It works with all the standard JSON patch operations (`add, replace, move, test, remove and copy`).
-
-```js
-var document = { firstName: "Albert", contactDetails: { phoneNumbers: [] } };
-var operation = { op: "replace", path: "/firstName", value: "Joachim" };
-document = jsonpatch.applyOperation(document, operation).newDocument;
-// document == { firstName: "Joachim", contactDetails: { phoneNumbers: [] }}
+```html
+
```
-#### Using `applyReducer` with `reduce`
-
-If you have an array of operations, you can simple reduce them using `applyReducer` as your reducer:
-
-```js
-var document = { firstName: "Albert", contactDetails: { phoneNumbers: [ ] } };
-var patch = [
- { op:"replace", path: "/firstName", value: "Joachim" },
- { op:"add", path: "/lastName", value: "Wester" },
- { op:"add", path: "/contactDetails/phoneNumbers/0", value: { number: "555-123" } }
-];
-var updatedDocument = patch.reduce(applyReducer, document);
-// updatedDocument == { firstName:"Joachim", lastName:"Wester", contactDetails:{ phoneNumbers[ {number:"555-123"} ] } };
-```
+### In Node.js
-Generating patches:
+In Node 12+ with `--experimental-modules` flag, the below code uses this library as an ECMAScript module:
```js
-var document = { firstName: "Joachim", lastName: "Wester", contactDetails: { phoneNumbers: [ { number:"555-123" }] } };
-var observer = jsonpatch.observe(document);
-document.firstName = "Albert";
-document.contactDetails.phoneNumbers[0].number = "123";
-document.contactDetails.phoneNumbers.push({ number:"456" });
-var patch = jsonpatch.generate(observer);
-// patch == [
-// { op: "replace", path: "/firstName", value: "Albert"},
-// { op: "replace", path: "/contactDetails/phoneNumbers/0/number", value: "123" },
-// { op: "add", path: "/contactDetails/phoneNumbers/1", value: {number:"456"}}
-// ];
+import * as jsonpatch from 'fast-json-patch/index.mjs';
+import { applyOperation } from 'fast-json-patch/index.mjs';
```
-Generating patches with test operations for values in the first object:
+In Webpack (and most surely other bundlers based on Babel), the below code uses this library as an ECMAScript module:
```js
-var document = { firstName: "Joachim", lastName: "Wester", contactDetails: { phoneNumbers: [ { number:"555-123" }] } };
-var observer = jsonpatch.observe(document);
-document.firstName = "Albert";
-document.contactDetails.phoneNumbers[0].number = "123";
-document.contactDetails.phoneNumbers.push({ number:"456" });
-var patch = jsonpatch.generate(observer, true);
-// patch == [
-// { op: "test", path: "/firstName", value: "Joachim"},
-// { op: "replace", path: "/firstName", value: "Albert"},
-// { op: "test", path: "/contactDetails/phoneNumbers/0/number", value: "555-123" },
-// { op: "replace", path: "/contactDetails/phoneNumbers/0/number", value: "123" },
-// { op: "add", path: "/contactDetails/phoneNumbers/1", value: {number:"456"}}
-// ];
+import * as jsonpatch from 'fast-json-patch';
+import { applyOperation } from 'fast-json-patch';
```
-Comparing two object trees:
+In standard Node, the below code uses this library as a CommonJS module:
```js
-var documentA = {user: {firstName: "Albert", lastName: "Einstein"}};
-var documentB = {user: {firstName: "Albert", lastName: "Collins"}};
-var diff = jsonpatch.compare(documentA, documentB);
-//diff == [{op: "replace", path: "/user/lastName", value: "Collins"}]
+const { applyOperation } = require('fast-json-patch');
+const applyOperation = require('fast-json-patch').applyOperation;
```
-Comparing two object trees with test operations for values in the first object:
+## Directories
-```js
-var documentA = {user: {firstName: "Albert", lastName: "Einstein"}};
-var documentB = {user: {firstName: "Albert", lastName: "Collins"}};
-var diff = jsonpatch.compare(documentA, documentB, true);
-//diff == [
-// {op: "test", path: "/user/lastName", value: "Einstein"},
-// {op: "replace", path: "/user/lastName", value: "Collins"}
-// ];
-```
+Directories used in this package:
-Validating a sequence of patches:
-
-```js
-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]);
- }
- }
-}
-```
+- `dist/` - contains ES5 files for a Web browser
+- `commonjs/` - contains CommonJS module and typings
+- `module/` - contains ECMAScript module and typings
+- `src/` - contains TypeScript source files
## API
@@ -243,6 +116,19 @@ Returns an array of [`OperationResult`](#operationresult-type) objects - one ite
- See [Validation notes](#validation-notes).
+Example:
+
+```js
+var document = { firstName: "Albert", contactDetails: { phoneNumbers: [] } };
+var patch = [
+ { op: "replace", path: "/firstName", value: "Joachim" },
+ { op: "add", path: "/lastName", value: "Wester" },
+ { op: "add", path: "/contactDetails/phoneNumbers/0", value: { number: "555-123" } }
+];
+document = jsonpatch.applyPatch(document, patch).newDocument;
+// document == { firstName: "Joachim", lastName: "Wester", contactDetails: { phoneNumbers: [{number:"555-123"}] } };
+```
+
#### `function applyOperation(document: T, operation: Operation, validateOperation: boolean | Validator = false, mutateDocument: boolean = true, banPrototypeModifications: boolean = true, index: number = 0): OperationResult`
Applies single operation object `operation` on `document`.
@@ -264,6 +150,15 @@ Returns an [`OperationResult`](#operationresult-type) object `{newDocument: any,
- See [Validation notes](#validation-notes).
+Example:
+
+```js
+var document = { firstName: "Albert", contactDetails: { phoneNumbers: [] } };
+var operation = { op: "replace", path: "/firstName", value: "Joachim" };
+document = jsonpatch.applyOperation(document, operation).newDocument;
+// document == { firstName: "Joachim", contactDetails: { phoneNumbers: [] }}
+```
+
#### `jsonpatch.applyReducer(document: T, operation: Operation, index: number): T`
**Ideal for `patch.reduce(jsonpatch.applyReducer, document)`**.
@@ -274,6 +169,19 @@ Returns the a modified document.
Note: It throws `TEST_OPERATION_FAILED` error if `test` operation fails.
+Example:
+
+```js
+var document = { firstName: "Albert", contactDetails: { phoneNumbers: [ ] } };
+var patch = [
+ { op:"replace", path: "/firstName", value: "Joachim" },
+ { op:"add", path: "/lastName", value: "Wester" },
+ { op:"add", path: "/contactDetails/phoneNumbers/0", value: { number: "555-123" } }
+];
+var updatedDocument = patch.reduce(applyReducer, document);
+// updatedDocument == { firstName:"Joachim", lastName:"Wester", contactDetails:{ phoneNumbers[ {number:"555-123"} ] } };
+```
+
#### `jsonpatch.deepClone(value: any): any`
Returns deeply cloned value.
@@ -306,6 +214,40 @@ method, it will be triggered synchronously as well. If `invertible` is true, the
If there are no pending changes in `obj`, returns an empty array (length 0).
+Example:
+
+```js
+var document = { firstName: "Joachim", lastName: "Wester", contactDetails: { phoneNumbers: [ { number:"555-123" }] } };
+var observer = jsonpatch.observe(document);
+document.firstName = "Albert";
+document.contactDetails.phoneNumbers[0].number = "123";
+document.contactDetails.phoneNumbers.push({ number:"456" });
+var patch = jsonpatch.generate(observer);
+// patch == [
+// { op: "replace", path: "/firstName", value: "Albert"},
+// { op: "replace", path: "/contactDetails/phoneNumbers/0/number", value: "123" },
+// { op: "add", path: "/contactDetails/phoneNumbers/1", value: {number:"456"}}
+// ];
+```
+
+Example of generating patches with test operations for values in the first object:
+
+```js
+var document = { firstName: "Joachim", lastName: "Wester", contactDetails: { phoneNumbers: [ { number:"555-123" }] } };
+var observer = jsonpatch.observe(document);
+document.firstName = "Albert";
+document.contactDetails.phoneNumbers[0].number = "123";
+document.contactDetails.phoneNumbers.push({ number:"456" });
+var patch = jsonpatch.generate(observer, true);
+// patch == [
+// { op: "test", path: "/firstName", value: "Joachim"},
+// { op: "replace", path: "/firstName", value: "Albert"},
+// { op: "test", path: "/contactDetails/phoneNumbers/0/number", value: "555-123" },
+// { op: "replace", path: "/contactDetails/phoneNumbers/0/number", value: "123" },
+// { op: "add", path: "/contactDetails/phoneNumbers/1", value: {number:"456"}}
+// ];
+```
+
#### `jsonpatch.unobserve(document: any, observer: Observer): void`
Destroys the observer set up on `document`.
@@ -318,6 +260,27 @@ Compares object trees `document1` and `document2` and returns the difference rel
If there are no differences, returns an empty array (length 0).
+Example:
+
+```js
+var documentA = {user: {firstName: "Albert", lastName: "Einstein"}};
+var documentB = {user: {firstName: "Albert", lastName: "Collins"}};
+var diff = jsonpatch.compare(documentA, documentB);
+//diff == [{op: "replace", path: "/user/lastName", value: "Collins"}]
+```
+
+Example of comparing two object trees with test operations for values in the first object:
+
+```js
+var documentA = {user: {firstName: "Albert", lastName: "Einstein"}};
+var documentB = {user: {firstName: "Albert", lastName: "Collins"}};
+var diff = jsonpatch.compare(documentA, documentB, true);
+//diff == [
+// {op: "test", path: "/user/lastName", value: "Einstein"},
+// {op: "replace", path: "/user/lastName", value: "Collins"}
+// ];
+```
+
#### `jsonpatch.validate(patch: Operation[], document?: any, validator?: Function): JsonPatchError`
See [Validation notes](#validation-notes)
@@ -350,6 +313,27 @@ OPERATION_PATH_ILLEGAL_ARRAY_INDEX | Expected an unsigned base-10 integer value,
OPERATION_VALUE_OUT_OF_BOUNDS | The specified index MUST NOT be greater than the number of elements in the array
TEST_OPERATION_FAILED | When operation is `test` and the test fails, applies to `applyReducer`.
+Example:
+
+```js
+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]);
+ }
+ }
+}
+```
+
## `OperationResult` Type
Functions `applyPatch` and `applyOperation` both return `OperationResult` object. This object is:
@@ -404,6 +388,29 @@ See the [ECMAScript spec](http://www.ecma-international.org/ecma-262/6.0/index.h
To see the list of recent changes, see [Releases](https://github.com/Starcounter-Jack/JSON-Patch/releases).
+## Footprint
+4 KB minified and gzipped (12 KB minified)
+
+## Performance
+
+##### [`add` benchmark](https://run.perf.zone/view/JSON-Patch-Add-Operation-1535541298893)
+
+
+
+##### [`replace` benchmark](https://run.perf.zone/view/JSON-Patch-Replace-Operation-1535540952263)
+
+
+
+Tested on 29.08.2018. Compared libraries:
+
+- [Starcounter-Jack/JSON-Patch](https://www.npmjs.com/package/fast-json-patch) 2.0.6
+- [bruth/jsonpatch-js](https://www.npmjs.com/package/json-patch) 0.7.0
+- [dharmafly/jsonpatch.js](https://www.npmjs.com/package/jsonpatch) 3.0.1
+- [jiff](https://www.npmjs.com/package/jiff) 0.7.3
+- [RFC6902](https://www.npmjs.com/package/rfc6902) 2.4.0
+
+We aim the tests to be fair. Our library puts performance as the #1 priority, while other libraries can have different priorities. If you'd like to update the benchmarks or add a library, please fork the [perf.zone](https://perf.zone) benchmarks linked above and open an issue to include new results.
+
## License
MIT
diff --git a/commonjs/core.js b/commonjs/core.js
new file mode 100644
index 00000000..8e13ca8c
--- /dev/null
+++ b/commonjs/core.js
@@ -0,0 +1,448 @@
+Object.defineProperty(exports, "__esModule", { value: true });
+var helpers_js_1 = require("./helpers.js");
+exports.JsonPatchError = helpers_js_1.PatchError;
+exports.deepClone = helpers_js_1._deepClone;
+/* We use a Javascript hash to store each
+ function. Each hash entry (property) uses
+ the operation identifiers specified in rfc6902.
+ In this way, we can map each patch operation
+ to its dedicated function in efficient way.
+ */
+/* The operations applicable to an object */
+var objOps = {
+ add: function (obj, key, document) {
+ obj[key] = this.value;
+ return { newDocument: document };
+ },
+ remove: function (obj, key, document) {
+ var removed = obj[key];
+ delete obj[key];
+ return { newDocument: document, removed: removed };
+ },
+ replace: function (obj, key, document) {
+ var removed = obj[key];
+ obj[key] = this.value;
+ return { newDocument: document, removed: removed };
+ },
+ move: function (obj, key, document) {
+ /* in case move target overwrites an existing value,
+ return the removed value, this can be taxing performance-wise,
+ and is potentially unneeded */
+ var removed = getValueByPointer(document, this.path);
+ if (removed) {
+ removed = helpers_js_1._deepClone(removed);
+ }
+ var originalValue = applyOperation(document, { op: "remove", path: this.from }).removed;
+ applyOperation(document, { op: "add", path: this.path, value: originalValue });
+ return { newDocument: document, removed: removed };
+ },
+ copy: function (obj, key, document) {
+ var valueToCopy = getValueByPointer(document, this.from);
+ // enforce copy by value so further operations don't affect source (see issue #177)
+ applyOperation(document, { op: "add", path: this.path, value: helpers_js_1._deepClone(valueToCopy) });
+ return { newDocument: document };
+ },
+ test: function (obj, key, document) {
+ return { newDocument: document, test: _areEquals(obj[key], this.value) };
+ },
+ _get: function (obj, key, document) {
+ this.value = obj[key];
+ return { newDocument: document };
+ }
+};
+/* The operations applicable to an array. Many are the same as for the object */
+var arrOps = {
+ add: function (arr, i, document) {
+ if (helpers_js_1.isInteger(i)) {
+ arr.splice(i, 0, this.value);
+ }
+ else { // array props
+ arr[i] = this.value;
+ }
+ // this may be needed when using '-' in an array
+ return { newDocument: document, index: i };
+ },
+ remove: function (arr, i, document) {
+ var removedList = arr.splice(i, 1);
+ return { newDocument: document, removed: removedList[0] };
+ },
+ replace: function (arr, i, document) {
+ var removed = arr[i];
+ arr[i] = this.value;
+ return { newDocument: document, removed: removed };
+ },
+ move: objOps.move,
+ copy: objOps.copy,
+ test: objOps.test,
+ _get: objOps._get
+};
+/**
+ * Retrieves a value from a JSON document by a JSON pointer.
+ * Returns the value.
+ *
+ * @param document The document to get the value from
+ * @param pointer an escaped JSON pointer
+ * @return The retrieved value
+ */
+function getValueByPointer(document, pointer) {
+ if (pointer == '') {
+ return document;
+ }
+ var getOriginalDestination = { op: "_get", path: pointer };
+ applyOperation(document, getOriginalDestination);
+ return getOriginalDestination.value;
+}
+exports.getValueByPointer = getValueByPointer;
+/**
+ * Apply a single JSON Patch Operation on a JSON document.
+ * Returns the {newDocument, result} of the operation.
+ * It modifies the `document` and `operation` objects - it gets the values by reference.
+ * If you would like to avoid touching your values, clone them:
+ * `jsonpatch.applyOperation(document, jsonpatch._deepClone(operation))`.
+ *
+ * @param document The document to patch
+ * @param operation The operation to apply
+ * @param validateOperation `false` is without validation, `true` to use default jsonpatch's validation, or you can pass a `validateOperation` callback to be used for validation.
+ * @param mutateDocument Whether to mutate the original document or clone it before applying
+ * @param banPrototypeModifications Whether to ban modifications to `__proto__`, defaults to `true`.
+ * @return `{newDocument, result}` after the operation
+ */
+function applyOperation(document, operation, validateOperation, mutateDocument, banPrototypeModifications, index) {
+ if (validateOperation === void 0) { validateOperation = false; }
+ if (mutateDocument === void 0) { mutateDocument = true; }
+ if (banPrototypeModifications === void 0) { banPrototypeModifications = true; }
+ if (index === void 0) { index = 0; }
+ if (validateOperation) {
+ if (typeof validateOperation == 'function') {
+ validateOperation(operation, 0, document, operation.path);
+ }
+ else {
+ validator(operation, 0);
+ }
+ }
+ /* ROOT OPERATIONS */
+ if (operation.path === "") {
+ var returnValue = { newDocument: document };
+ if (operation.op === 'add') {
+ returnValue.newDocument = operation.value;
+ return returnValue;
+ }
+ else if (operation.op === 'replace') {
+ returnValue.newDocument = operation.value;
+ returnValue.removed = document; //document we removed
+ return returnValue;
+ }
+ else if (operation.op === 'move' || operation.op === 'copy') { // it's a move or copy to root
+ returnValue.newDocument = getValueByPointer(document, operation.from); // get the value by json-pointer in `from` field
+ if (operation.op === 'move') { // report removed item
+ returnValue.removed = document;
+ }
+ return returnValue;
+ }
+ else if (operation.op === 'test') {
+ returnValue.test = _areEquals(document, operation.value);
+ if (returnValue.test === false) {
+ throw new exports.JsonPatchError("Test operation failed", 'TEST_OPERATION_FAILED', index, operation, document);
+ }
+ returnValue.newDocument = document;
+ return returnValue;
+ }
+ else if (operation.op === 'remove') { // a remove on root
+ returnValue.removed = document;
+ returnValue.newDocument = null;
+ return returnValue;
+ }
+ else if (operation.op === '_get') {
+ operation.value = document;
+ return returnValue;
+ }
+ else { /* bad operation */
+ if (validateOperation) {
+ throw new exports.JsonPatchError('Operation `op` property is not one of operations defined in RFC-6902', 'OPERATION_OP_INVALID', index, operation, document);
+ }
+ else {
+ return returnValue;
+ }
+ }
+ } /* END ROOT OPERATIONS */
+ else {
+ if (!mutateDocument) {
+ document = helpers_js_1._deepClone(document);
+ }
+ var path = operation.path || "";
+ var keys = path.split('/');
+ var obj = document;
+ var t = 1; //skip empty element - http://jsperf.com/to-shift-or-not-to-shift
+ var len = keys.length;
+ var existingPathFragment = undefined;
+ var key = void 0;
+ var validateFunction = void 0;
+ if (typeof validateOperation == 'function') {
+ validateFunction = validateOperation;
+ }
+ else {
+ validateFunction = validator;
+ }
+ while (true) {
+ key = keys[t];
+ if (banPrototypeModifications && key == '__proto__') {
+ throw new TypeError('JSON-Patch: modifying `__proto__` prop is banned for security reasons, if this was on purpose, please set `banPrototypeModifications` flag false and pass it to this function. More info in fast-json-patch README');
+ }
+ if (validateOperation) {
+ if (existingPathFragment === undefined) {
+ if (obj[key] === undefined) {
+ existingPathFragment = keys.slice(0, t).join('/');
+ }
+ else if (t == len - 1) {
+ existingPathFragment = operation.path;
+ }
+ if (existingPathFragment !== undefined) {
+ validateFunction(operation, 0, document, existingPathFragment);
+ }
+ }
+ }
+ t++;
+ if (Array.isArray(obj)) {
+ if (key === '-') {
+ key = obj.length;
+ }
+ else {
+ if (validateOperation && !helpers_js_1.isInteger(key)) {
+ throw new exports.JsonPatchError("Expected an unsigned base-10 integer value, making the new referenced value the array element with the zero-based index", "OPERATION_PATH_ILLEGAL_ARRAY_INDEX", index, operation, document);
+ } // only parse key when it's an integer for `arr.prop` to work
+ else if (helpers_js_1.isInteger(key)) {
+ key = ~~key;
+ }
+ }
+ if (t >= len) {
+ if (validateOperation && operation.op === "add" && key > obj.length) {
+ throw new exports.JsonPatchError("The specified index MUST NOT be greater than the number of elements in the array", "OPERATION_VALUE_OUT_OF_BOUNDS", index, operation, document);
+ }
+ var returnValue = arrOps[operation.op].call(operation, obj, key, document); // Apply patch
+ if (returnValue.test === false) {
+ throw new exports.JsonPatchError("Test operation failed", 'TEST_OPERATION_FAILED', index, operation, document);
+ }
+ return returnValue;
+ }
+ }
+ else {
+ if (key && key.indexOf('~') != -1) {
+ key = helpers_js_1.unescapePathComponent(key);
+ }
+ if (t >= len) {
+ var returnValue = objOps[operation.op].call(operation, obj, key, document); // Apply patch
+ if (returnValue.test === false) {
+ throw new exports.JsonPatchError("Test operation failed", 'TEST_OPERATION_FAILED', index, operation, document);
+ }
+ return returnValue;
+ }
+ }
+ obj = obj[key];
+ }
+ }
+}
+exports.applyOperation = applyOperation;
+/**
+ * Apply a full JSON Patch array on a JSON document.
+ * Returns the {newDocument, result} of the patch.
+ * It modifies the `document` object and `patch` - it gets the values by reference.
+ * If you would like to avoid touching your values, clone them:
+ * `jsonpatch.applyPatch(document, jsonpatch._deepClone(patch))`.
+ *
+ * @param document The document to patch
+ * @param patch The patch to apply
+ * @param validateOperation `false` is without validation, `true` to use default jsonpatch's validation, or you can pass a `validateOperation` callback to be used for validation.
+ * @param mutateDocument Whether to mutate the original document or clone it before applying
+ * @param banPrototypeModifications Whether to ban modifications to `__proto__`, defaults to `true`.
+ * @return An array of `{newDocument, result}` after the patch
+ */
+function applyPatch(document, patch, validateOperation, mutateDocument, banPrototypeModifications) {
+ if (mutateDocument === void 0) { mutateDocument = true; }
+ if (banPrototypeModifications === void 0) { banPrototypeModifications = true; }
+ if (validateOperation) {
+ if (!Array.isArray(patch)) {
+ throw new exports.JsonPatchError('Patch sequence must be an array', 'SEQUENCE_NOT_AN_ARRAY');
+ }
+ }
+ if (!mutateDocument) {
+ document = helpers_js_1._deepClone(document);
+ }
+ var results = new Array(patch.length);
+ for (var i = 0, length_1 = patch.length; i < length_1; i++) {
+ // we don't need to pass mutateDocument argument because if it was true, we already deep cloned the object, we'll just pass `true`
+ results[i] = applyOperation(document, patch[i], validateOperation, true, banPrototypeModifications, i);
+ document = results[i].newDocument; // in case root was replaced
+ }
+ results.newDocument = document;
+ return results;
+}
+exports.applyPatch = applyPatch;
+/**
+ * Apply a single JSON Patch Operation on a JSON document.
+ * Returns the updated document.
+ * Suitable as a reducer.
+ *
+ * @param document The document to patch
+ * @param operation The operation to apply
+ * @return The updated document
+ */
+function applyReducer(document, operation, index) {
+ var operationResult = applyOperation(document, operation);
+ if (operationResult.test === false) { // failed test
+ throw new exports.JsonPatchError("Test operation failed", 'TEST_OPERATION_FAILED', index, operation, document);
+ }
+ return operationResult.newDocument;
+}
+exports.applyReducer = applyReducer;
+/**
+ * Validates a single operation. Called from `jsonpatch.validate`. Throws `JsonPatchError` in case of an error.
+ * @param {object} operation - operation object (patch)
+ * @param {number} index - index of operation in the sequence
+ * @param {object} [document] - object where the operation is supposed to be applied
+ * @param {string} [existingPathFragment] - comes along with `document`
+ */
+function validator(operation, index, document, existingPathFragment) {
+ if (typeof operation !== 'object' || operation === null || Array.isArray(operation)) {
+ throw new exports.JsonPatchError('Operation is not an object', 'OPERATION_NOT_AN_OBJECT', index, operation, document);
+ }
+ else if (!objOps[operation.op]) {
+ throw new exports.JsonPatchError('Operation `op` property is not one of operations defined in RFC-6902', 'OPERATION_OP_INVALID', index, operation, document);
+ }
+ else if (typeof operation.path !== 'string') {
+ throw new exports.JsonPatchError('Operation `path` property is not a string', 'OPERATION_PATH_INVALID', index, operation, document);
+ }
+ else if (operation.path.indexOf('/') !== 0 && operation.path.length > 0) {
+ // paths that aren't empty string should start with "/"
+ throw new exports.JsonPatchError('Operation `path` property must start with "/"', 'OPERATION_PATH_INVALID', index, operation, document);
+ }
+ else if ((operation.op === 'move' || operation.op === 'copy') && typeof operation.from !== 'string') {
+ throw new exports.JsonPatchError('Operation `from` property is not present (applicable in `move` and `copy` operations)', 'OPERATION_FROM_REQUIRED', index, operation, document);
+ }
+ else if ((operation.op === 'add' || operation.op === 'replace' || operation.op === 'test') && operation.value === undefined) {
+ throw new exports.JsonPatchError('Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)', 'OPERATION_VALUE_REQUIRED', index, operation, document);
+ }
+ else if ((operation.op === 'add' || operation.op === 'replace' || operation.op === 'test') && helpers_js_1.hasUndefined(operation.value)) {
+ throw new exports.JsonPatchError('Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)', 'OPERATION_VALUE_CANNOT_CONTAIN_UNDEFINED', index, operation, document);
+ }
+ else if (document) {
+ if (operation.op == "add") {
+ var pathLen = operation.path.split("/").length;
+ var existingPathLen = existingPathFragment.split("/").length;
+ if (pathLen !== existingPathLen + 1 && pathLen !== existingPathLen) {
+ throw new exports.JsonPatchError('Cannot perform an `add` operation at the desired path', 'OPERATION_PATH_CANNOT_ADD', index, operation, document);
+ }
+ }
+ else if (operation.op === 'replace' || operation.op === 'remove' || operation.op === '_get') {
+ if (operation.path !== existingPathFragment) {
+ throw new exports.JsonPatchError('Cannot perform the operation at a path that does not exist', 'OPERATION_PATH_UNRESOLVABLE', index, operation, document);
+ }
+ }
+ else if (operation.op === 'move' || operation.op === 'copy') {
+ var existingValue = { op: "_get", path: operation.from, value: undefined };
+ var error = validate([existingValue], document);
+ if (error && error.name === 'OPERATION_PATH_UNRESOLVABLE') {
+ throw new exports.JsonPatchError('Cannot perform the operation from a path that does not exist', 'OPERATION_FROM_UNRESOLVABLE', index, operation, document);
+ }
+ }
+ }
+}
+exports.validator = validator;
+/**
+ * Validates a sequence of operations. If `document` parameter is provided, the sequence is additionally validated against the object document.
+ * If error is encountered, returns a JsonPatchError object
+ * @param sequence
+ * @param document
+ * @returns {JsonPatchError|undefined}
+ */
+function validate(sequence, document, externalValidator) {
+ try {
+ if (!Array.isArray(sequence)) {
+ throw new exports.JsonPatchError('Patch sequence must be an array', 'SEQUENCE_NOT_AN_ARRAY');
+ }
+ if (document) {
+ //clone document and sequence so that we can safely try applying operations
+ applyPatch(helpers_js_1._deepClone(document), helpers_js_1._deepClone(sequence), externalValidator || true);
+ }
+ else {
+ externalValidator = externalValidator || validator;
+ for (var i = 0; i < sequence.length; i++) {
+ externalValidator(sequence[i], i, document, undefined);
+ }
+ }
+ }
+ catch (e) {
+ if (e instanceof exports.JsonPatchError) {
+ return e;
+ }
+ else {
+ throw e;
+ }
+ }
+}
+exports.validate = validate;
+// based on https://github.com/epoberezkin/fast-deep-equal
+// MIT License
+// Copyright (c) 2017 Evgeny Poberezkin
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+function _areEquals(a, b) {
+ if (a === b)
+ return true;
+ if (a && b && typeof a == 'object' && typeof b == 'object') {
+ var arrA = Array.isArray(a), arrB = Array.isArray(b), i, length, key;
+ if (arrA && arrB) {
+ length = a.length;
+ if (length != b.length)
+ return false;
+ for (i = length; i-- !== 0;)
+ if (!_areEquals(a[i], b[i]))
+ return false;
+ return true;
+ }
+ if (arrA != arrB)
+ return false;
+ var keys = Object.keys(a);
+ length = keys.length;
+ if (length !== Object.keys(b).length)
+ return false;
+ for (i = length; i-- !== 0;)
+ if (!b.hasOwnProperty(keys[i]))
+ return false;
+ for (i = length; i-- !== 0;) {
+ key = keys[i];
+ if (!_areEquals(a[key], b[key]))
+ return false;
+ }
+ return true;
+ }
+ return a !== a && b !== b;
+}
+exports._areEquals = _areEquals;
+;
+/**
+ * Default export for backwards compat
+ */
+exports.default = {
+ JsonPatchError: exports.JsonPatchError,
+ deepClone: exports.deepClone,
+ getValueByPointer: getValueByPointer,
+ applyOperation: applyOperation,
+ applyPatch: applyPatch,
+ applyReducer: applyReducer,
+ validator: validator,
+ validate: validate,
+ _areEquals: _areEquals
+};
diff --git a/commonjs/duplex.js b/commonjs/duplex.js
new file mode 100644
index 00000000..569b23f0
--- /dev/null
+++ b/commonjs/duplex.js
@@ -0,0 +1,207 @@
+var __assign = (this && this.__assign) || function () {
+ __assign = Object.assign || function(t) {
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
+ s = arguments[i];
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
+ t[p] = s[p];
+ }
+ return t;
+ };
+ return __assign.apply(this, arguments);
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+/*!
+ * https://github.com/Starcounter-Jack/JSON-Patch
+ * (c) 2017 Joachim Wester
+ * MIT license
+ */
+var helpers_js_1 = require("./helpers.js");
+var core_js_1 = require("./core.js");
+var beforeDict = new WeakMap();
+var Mirror = /** @class */ (function () {
+ function Mirror(obj) {
+ this.observers = new Map();
+ this.obj = obj;
+ }
+ return Mirror;
+}());
+var ObserverInfo = /** @class */ (function () {
+ function ObserverInfo(callback, observer) {
+ this.callback = callback;
+ this.observer = observer;
+ }
+ return ObserverInfo;
+}());
+function getMirror(obj) {
+ return beforeDict.get(obj);
+}
+function getObserverFromMirror(mirror, callback) {
+ return mirror.observers.get(callback);
+}
+function removeObserverFromMirror(mirror, observer) {
+ mirror.observers.delete(observer.callback);
+}
+/**
+ * Detach an observer from an object
+ */
+function unobserve(root, observer) {
+ observer.unobserve();
+}
+exports.unobserve = unobserve;
+/**
+ * Observes changes made to an object, which can then be retrieved using generate
+ */
+function observe(obj, callback) {
+ var patches = [];
+ var observer;
+ var mirror = getMirror(obj);
+ if (!mirror) {
+ mirror = new Mirror(obj);
+ beforeDict.set(obj, mirror);
+ }
+ else {
+ var observerInfo = getObserverFromMirror(mirror, callback);
+ observer = observerInfo && observerInfo.observer;
+ }
+ if (observer) {
+ return observer;
+ }
+ observer = {};
+ mirror.value = helpers_js_1._deepClone(obj);
+ if (callback) {
+ observer.callback = callback;
+ observer.next = null;
+ var dirtyCheck = function () {
+ generate(observer);
+ };
+ var fastCheck = function () {
+ clearTimeout(observer.next);
+ observer.next = setTimeout(dirtyCheck);
+ };
+ if (typeof window !== 'undefined') { //not Node
+ window.addEventListener('mouseup', fastCheck);
+ window.addEventListener('keyup', fastCheck);
+ window.addEventListener('mousedown', fastCheck);
+ window.addEventListener('keydown', fastCheck);
+ window.addEventListener('change', fastCheck);
+ }
+ }
+ observer.patches = patches;
+ observer.object = obj;
+ observer.unobserve = function () {
+ generate(observer);
+ clearTimeout(observer.next);
+ removeObserverFromMirror(mirror, observer);
+ if (typeof window !== 'undefined') {
+ window.removeEventListener('mouseup', fastCheck);
+ window.removeEventListener('keyup', fastCheck);
+ window.removeEventListener('mousedown', fastCheck);
+ window.removeEventListener('keydown', fastCheck);
+ window.removeEventListener('change', fastCheck);
+ }
+ };
+ mirror.observers.set(callback, new ObserverInfo(callback, observer));
+ return observer;
+}
+exports.observe = observe;
+/**
+ * Generate an array of patches from an observer
+ */
+function generate(observer, invertible) {
+ if (invertible === void 0) { invertible = false; }
+ var mirror = beforeDict.get(observer.object);
+ _generate(mirror.value, observer.object, observer.patches, "", invertible);
+ if (observer.patches.length) {
+ core_js_1.applyPatch(mirror.value, observer.patches);
+ }
+ var temp = observer.patches;
+ if (temp.length > 0) {
+ observer.patches = [];
+ if (observer.callback) {
+ observer.callback(temp);
+ }
+ }
+ return temp;
+}
+exports.generate = generate;
+// Dirty check if obj is different from mirror, generate patches and update mirror
+function _generate(mirror, obj, patches, path, invertible) {
+ if (obj === mirror) {
+ return;
+ }
+ if (typeof obj.toJSON === "function") {
+ obj = obj.toJSON();
+ }
+ var newKeys = helpers_js_1._objectKeys(obj);
+ var oldKeys = helpers_js_1._objectKeys(mirror);
+ var changed = false;
+ var deleted = false;
+ //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];
+ var oldVal = mirror[key];
+ if (helpers_js_1.hasOwnProperty(obj, key) && !(obj[key] === undefined && oldVal !== undefined && Array.isArray(obj) === false)) {
+ var newVal = obj[key];
+ if (typeof oldVal == "object" && oldVal != null && typeof newVal == "object" && newVal != null) {
+ _generate(oldVal, newVal, patches, path + "/" + helpers_js_1.escapePathComponent(key), invertible);
+ }
+ else {
+ if (oldVal !== newVal) {
+ changed = true;
+ if (invertible) {
+ patches.push({ op: "test", path: path + "/" + helpers_js_1.escapePathComponent(key), value: helpers_js_1._deepClone(oldVal) });
+ }
+ patches.push({ op: "replace", path: path + "/" + helpers_js_1.escapePathComponent(key), value: helpers_js_1._deepClone(newVal) });
+ }
+ }
+ }
+ else if (Array.isArray(mirror) === Array.isArray(obj)) {
+ if (invertible) {
+ patches.push({ op: "test", path: path + "/" + helpers_js_1.escapePathComponent(key), value: helpers_js_1._deepClone(oldVal) });
+ }
+ patches.push({ op: "remove", path: path + "/" + helpers_js_1.escapePathComponent(key) });
+ deleted = true; // property has been deleted
+ }
+ else {
+ if (invertible) {
+ patches.push({ op: "test", path: path, value: mirror });
+ }
+ patches.push({ op: "replace", path: path, value: obj });
+ changed = true;
+ }
+ }
+ if (!deleted && newKeys.length == oldKeys.length) {
+ return;
+ }
+ for (var t = 0; t < newKeys.length; t++) {
+ var key = newKeys[t];
+ if (!helpers_js_1.hasOwnProperty(mirror, key) && obj[key] !== undefined) {
+ patches.push({ op: "add", path: path + "/" + helpers_js_1.escapePathComponent(key), value: helpers_js_1._deepClone(obj[key]) });
+ }
+ }
+}
+/**
+ * Create an array of patches from the differences in two objects
+ */
+function compare(tree1, tree2, invertible) {
+ if (invertible === void 0) { invertible = false; }
+ var patches = [];
+ _generate(tree1, tree2, patches, '', invertible);
+ return patches;
+}
+exports.compare = compare;
+/**
+ * Default export for backwards compat
+ */
+// import just to re-export as default
+var core = require("./core.js");
+var helpers_js_2 = require("./helpers.js");
+exports.default = __assign({}, core, {
+ // duplex
+ unobserve: unobserve,
+ observe: observe,
+ generate: generate,
+ compare: compare,
+ // helpers
+ JsonPatchError: helpers_js_2.PatchError, deepClone: helpers_js_1._deepClone, escapePathComponent: helpers_js_1.escapePathComponent,
+ unescapePathComponent: helpers_js_2.unescapePathComponent });
diff --git a/commonjs/helpers.js b/commonjs/helpers.js
new file mode 100644
index 00000000..0ac28b4d
--- /dev/null
+++ b/commonjs/helpers.js
@@ -0,0 +1,181 @@
+/*!
+ * https://github.com/Starcounter-Jack/JSON-Patch
+ * (c) 2017 Joachim Wester
+ * MIT license
+ */
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = function (d, b) {
+ extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return extendStatics(d, b);
+ };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+var _hasOwnProperty = Object.prototype.hasOwnProperty;
+function hasOwnProperty(obj, key) {
+ return _hasOwnProperty.call(obj, key);
+}
+exports.hasOwnProperty = hasOwnProperty;
+function _objectKeys(obj) {
+ if (Array.isArray(obj)) {
+ var keys = new Array(obj.length);
+ for (var k = 0; k < keys.length; k++) {
+ keys[k] = "" + k;
+ }
+ return keys;
+ }
+ if (Object.keys) {
+ return Object.keys(obj);
+ }
+ var keys = [];
+ for (var i in obj) {
+ if (hasOwnProperty(obj, i)) {
+ keys.push(i);
+ }
+ }
+ return keys;
+}
+exports._objectKeys = _objectKeys;
+;
+/**
+* Deeply clone the object.
+* https://jsperf.com/deep-copy-vs-json-stringify-json-parse/25 (recursiveDeepCopy)
+* @param {any} obj value to clone
+* @return {any} cloned obj
+*/
+function _deepClone(obj) {
+ switch (typeof obj) {
+ case "object":
+ return JSON.parse(JSON.stringify(obj)); //Faster than ES5 clone - http://jsperf.com/deep-cloning-of-objects/5
+ case "undefined":
+ return null; //this is how JSON.stringify behaves for array items
+ default:
+ return obj; //no need to clone primitives
+ }
+}
+exports._deepClone = _deepClone;
+//3x faster than cached /^\d+$/.test(str)
+function isInteger(str) {
+ var i = 0;
+ var len = str.length;
+ var charCode;
+ while (i < len) {
+ charCode = str.charCodeAt(i);
+ if (charCode >= 48 && charCode <= 57) {
+ i++;
+ continue;
+ }
+ return false;
+ }
+ return true;
+}
+exports.isInteger = isInteger;
+/**
+* Escapes a json pointer path
+* @param path The raw pointer
+* @return the Escaped path
+*/
+function escapePathComponent(path) {
+ if (path.indexOf('/') === -1 && path.indexOf('~') === -1)
+ return path;
+ return path.replace(/~/g, '~0').replace(/\//g, '~1');
+}
+exports.escapePathComponent = escapePathComponent;
+/**
+ * Unescapes a json pointer path
+ * @param path The escaped pointer
+ * @return The unescaped path
+ */
+function unescapePathComponent(path) {
+ return path.replace(/~1/g, '/').replace(/~0/g, '~');
+}
+exports.unescapePathComponent = unescapePathComponent;
+function _getPathRecursive(root, obj) {
+ var found;
+ for (var key in root) {
+ if (hasOwnProperty(root, 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 '';
+}
+exports._getPathRecursive = _getPathRecursive;
+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;
+}
+exports.getPath = getPath;
+/**
+* Recursively checks whether an object has any undefined values inside.
+*/
+function hasUndefined(obj) {
+ if (obj === undefined) {
+ return true;
+ }
+ if (obj) {
+ if (Array.isArray(obj)) {
+ for (var i = 0, len = obj.length; i < len; i++) {
+ if (hasUndefined(obj[i])) {
+ return true;
+ }
+ }
+ }
+ else if (typeof obj === "object") {
+ var objKeys = _objectKeys(obj);
+ var objKeysLength = objKeys.length;
+ for (var i = 0; i < objKeysLength; i++) {
+ if (hasUndefined(obj[objKeys[i]])) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+exports.hasUndefined = hasUndefined;
+function patchErrorMessageFormatter(message, args) {
+ var messageParts = [message];
+ for (var key in args) {
+ var value = typeof args[key] === 'object' ? JSON.stringify(args[key], null, 2) : args[key]; // pretty print
+ if (typeof value !== 'undefined') {
+ messageParts.push(key + ": " + value);
+ }
+ }
+ return messageParts.join('\n');
+}
+var PatchError = /** @class */ (function (_super) {
+ __extends(PatchError, _super);
+ function PatchError(message, name, index, operation, tree) {
+ var _newTarget = this.constructor;
+ var _this = _super.call(this, patchErrorMessageFormatter(message, { name: name, index: index, operation: operation, tree: tree })) || this;
+ _this.name = name;
+ _this.index = index;
+ _this.operation = operation;
+ _this.tree = tree;
+ Object.setPrototypeOf(_this, _newTarget.prototype); // restore prototype chain, see https://stackoverflow.com/a/48342359
+ _this.message = patchErrorMessageFormatter(message, { name: name, index: index, operation: operation, tree: tree });
+ return _this;
+ }
+ return PatchError;
+}(Error));
+exports.PatchError = PatchError;
diff --git a/dist/fast-json-patch.js b/dist/fast-json-patch.js
index 4c120aae..4cd50e28 100644
--- a/dist/fast-json-patch.js
+++ b/dist/fast-json-patch.js
@@ -278,10 +278,9 @@ exports.PatchError = PatchError;
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
-var areEquals = __webpack_require__(3);
-var helpers_1 = __webpack_require__(0);
-exports.JsonPatchError = helpers_1.PatchError;
-exports.deepClone = helpers_1._deepClone;
+var helpers_js_1 = __webpack_require__(0);
+exports.JsonPatchError = helpers_js_1.PatchError;
+exports.deepClone = helpers_js_1._deepClone;
/* We use a Javascript hash to store each
function. Each hash entry (property) uses
the operation identifiers specified in rfc6902.
@@ -310,7 +309,7 @@ var objOps = {
and is potentially unneeded */
var removed = getValueByPointer(document, this.path);
if (removed) {
- removed = helpers_1._deepClone(removed);
+ removed = helpers_js_1._deepClone(removed);
}
var originalValue = applyOperation(document, { op: "remove", path: this.from }).removed;
applyOperation(document, { op: "add", path: this.path, value: originalValue });
@@ -319,11 +318,11 @@ var objOps = {
copy: function (obj, key, document) {
var valueToCopy = getValueByPointer(document, this.from);
// enforce copy by value so further operations don't affect source (see issue #177)
- applyOperation(document, { op: "add", path: this.path, value: helpers_1._deepClone(valueToCopy) });
+ applyOperation(document, { op: "add", path: this.path, value: helpers_js_1._deepClone(valueToCopy) });
return { newDocument: document };
},
test: function (obj, key, document) {
- return { newDocument: document, test: areEquals(obj[key], this.value) };
+ return { newDocument: document, test: _areEquals(obj[key], this.value) };
},
_get: function (obj, key, document) {
this.value = obj[key];
@@ -333,7 +332,7 @@ var objOps = {
/* The operations applicable to an array. Many are the same as for the object */
var arrOps = {
add: function (arr, i, document) {
- if (helpers_1.isInteger(i)) {
+ if (helpers_js_1.isInteger(i)) {
arr.splice(i, 0, this.value);
}
else { // array props
@@ -420,7 +419,7 @@ function applyOperation(document, operation, validateOperation, mutateDocument,
return returnValue;
}
else if (operation.op === 'test') {
- returnValue.test = areEquals(document, operation.value);
+ returnValue.test = _areEquals(document, operation.value);
if (returnValue.test === false) {
throw new exports.JsonPatchError("Test operation failed", 'TEST_OPERATION_FAILED', index, operation, document);
}
@@ -447,7 +446,7 @@ function applyOperation(document, operation, validateOperation, mutateDocument,
} /* END ROOT OPERATIONS */
else {
if (!mutateDocument) {
- document = helpers_1._deepClone(document);
+ document = helpers_js_1._deepClone(document);
}
var path = operation.path || "";
var keys = path.split('/');
@@ -487,10 +486,10 @@ function applyOperation(document, operation, validateOperation, mutateDocument,
key = obj.length;
}
else {
- if (validateOperation && !helpers_1.isInteger(key)) {
+ if (validateOperation && !helpers_js_1.isInteger(key)) {
throw new exports.JsonPatchError("Expected an unsigned base-10 integer value, making the new referenced value the array element with the zero-based index", "OPERATION_PATH_ILLEGAL_ARRAY_INDEX", index, operation, document);
} // only parse key when it's an integer for `arr.prop` to work
- else if (helpers_1.isInteger(key)) {
+ else if (helpers_js_1.isInteger(key)) {
key = ~~key;
}
}
@@ -507,7 +506,7 @@ function applyOperation(document, operation, validateOperation, mutateDocument,
}
else {
if (key && key.indexOf('~') != -1) {
- key = helpers_1.unescapePathComponent(key);
+ key = helpers_js_1.unescapePathComponent(key);
}
if (t >= len) {
var returnValue = objOps[operation.op].call(operation, obj, key, document); // Apply patch
@@ -545,7 +544,7 @@ function applyPatch(document, patch, validateOperation, mutateDocument, banProto
}
}
if (!mutateDocument) {
- document = helpers_1._deepClone(document);
+ document = helpers_js_1._deepClone(document);
}
var results = new Array(patch.length);
for (var i = 0, length_1 = patch.length; i < length_1; i++) {
@@ -601,7 +600,7 @@ function validator(operation, index, document, existingPathFragment) {
else if ((operation.op === 'add' || operation.op === 'replace' || operation.op === 'test') && operation.value === undefined) {
throw new exports.JsonPatchError('Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)', 'OPERATION_VALUE_REQUIRED', index, operation, document);
}
- else if ((operation.op === 'add' || operation.op === 'replace' || operation.op === 'test') && helpers_1.hasUndefined(operation.value)) {
+ else if ((operation.op === 'add' || operation.op === 'replace' || operation.op === 'test') && helpers_js_1.hasUndefined(operation.value)) {
throw new exports.JsonPatchError('Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)', 'OPERATION_VALUE_CANNOT_CONTAIN_UNDEFINED', index, operation, document);
}
else if (document) {
@@ -641,7 +640,7 @@ function validate(sequence, document, externalValidator) {
}
if (document) {
//clone document and sequence so that we can safely try applying operations
- applyPatch(helpers_1._deepClone(document), helpers_1._deepClone(sequence), externalValidator || true);
+ applyPatch(helpers_js_1._deepClone(document), helpers_js_1._deepClone(sequence), externalValidator || true);
}
else {
externalValidator = externalValidator || validator;
@@ -660,6 +659,58 @@ function validate(sequence, document, externalValidator) {
}
}
exports.validate = validate;
+// based on https://github.com/epoberezkin/fast-deep-equal
+// MIT License
+// Copyright (c) 2017 Evgeny Poberezkin
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+function _areEquals(a, b) {
+ if (a === b)
+ return true;
+ if (a && b && typeof a == 'object' && typeof b == 'object') {
+ var arrA = Array.isArray(a), arrB = Array.isArray(b), i, length, key;
+ if (arrA && arrB) {
+ length = a.length;
+ if (length != b.length)
+ return false;
+ for (i = length; i-- !== 0;)
+ if (!_areEquals(a[i], b[i]))
+ return false;
+ return true;
+ }
+ if (arrA != arrB)
+ return false;
+ var keys = Object.keys(a);
+ length = keys.length;
+ if (length !== Object.keys(b).length)
+ return false;
+ for (i = length; i-- !== 0;)
+ if (!b.hasOwnProperty(keys[i]))
+ return false;
+ for (i = length; i-- !== 0;) {
+ key = keys[i];
+ if (!_areEquals(a[key], b[key]))
+ return false;
+ }
+ return true;
+ }
+ return a !== a && b !== b;
+}
+exports._areEquals = _areEquals;
+;
/**
* Default export for backwards compat
*/
@@ -671,7 +722,8 @@ exports.default = {
applyPatch: applyPatch,
applyReducer: applyReducer,
validator: validator,
- validate: validate
+ validate: validate,
+ _areEquals: _areEquals
};
@@ -679,6 +731,23 @@ exports.default = {
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
+var core = __webpack_require__(1);
+Object.assign(exports, core);
+
+var duplex = __webpack_require__(3);
+Object.assign(exports, duplex);
+
+var helpers = __webpack_require__(0);
+exports.JsonPatchError = helpers.PatchError;
+exports.deepClone = helpers._deepClone;
+exports.escapePathComponent = helpers.escapePathComponent;
+exports.unescapePathComponent = helpers.unescapePathComponent;
+
+
+/***/ }),
+/* 3 */
+/***/ (function(module, exports, __webpack_require__) {
+
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
@@ -696,22 +765,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
* (c) 2017 Joachim Wester
* MIT license
*/
-var helpers_1 = __webpack_require__(0);
-var core_1 = __webpack_require__(1);
-/* export all core functions and types */
-var core_2 = __webpack_require__(1);
-exports.applyOperation = core_2.applyOperation;
-exports.applyPatch = core_2.applyPatch;
-exports.applyReducer = core_2.applyReducer;
-exports.getValueByPointer = core_2.getValueByPointer;
-exports.validate = core_2.validate;
-exports.validator = core_2.validator;
-/* export some helpers */
-var helpers_2 = __webpack_require__(0);
-exports.JsonPatchError = helpers_2.PatchError;
-exports.deepClone = helpers_2._deepClone;
-exports.escapePathComponent = helpers_2.escapePathComponent;
-exports.unescapePathComponent = helpers_2.unescapePathComponent;
+var helpers_js_1 = __webpack_require__(0);
+var core_js_1 = __webpack_require__(1);
var beforeDict = new WeakMap();
var Mirror = /** @class */ (function () {
function Mirror(obj) {
@@ -762,7 +817,7 @@ function observe(obj, callback) {
return observer;
}
observer = {};
- mirror.value = helpers_1._deepClone(obj);
+ mirror.value = helpers_js_1._deepClone(obj);
if (callback) {
observer.callback = callback;
observer.next = null;
@@ -807,7 +862,7 @@ function generate(observer, invertible) {
var mirror = beforeDict.get(observer.object);
_generate(mirror.value, observer.object, observer.patches, "", invertible);
if (observer.patches.length) {
- core_1.applyPatch(mirror.value, observer.patches);
+ core_js_1.applyPatch(mirror.value, observer.patches);
}
var temp = observer.patches;
if (temp.length > 0) {
@@ -827,34 +882,34 @@ function _generate(mirror, obj, patches, path, invertible) {
if (typeof obj.toJSON === "function") {
obj = obj.toJSON();
}
- var newKeys = helpers_1._objectKeys(obj);
- var oldKeys = helpers_1._objectKeys(mirror);
+ var newKeys = helpers_js_1._objectKeys(obj);
+ var oldKeys = helpers_js_1._objectKeys(mirror);
var changed = false;
var deleted = false;
//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];
var oldVal = mirror[key];
- if (helpers_1.hasOwnProperty(obj, key) && !(obj[key] === undefined && oldVal !== undefined && Array.isArray(obj) === false)) {
+ if (helpers_js_1.hasOwnProperty(obj, key) && !(obj[key] === undefined && oldVal !== undefined && Array.isArray(obj) === false)) {
var newVal = obj[key];
if (typeof oldVal == "object" && oldVal != null && typeof newVal == "object" && newVal != null) {
- _generate(oldVal, newVal, patches, path + "/" + helpers_1.escapePathComponent(key), invertible);
+ _generate(oldVal, newVal, patches, path + "/" + helpers_js_1.escapePathComponent(key), invertible);
}
else {
if (oldVal !== newVal) {
changed = true;
if (invertible) {
- patches.push({ op: "test", path: path + "/" + helpers_1.escapePathComponent(key), value: helpers_1._deepClone(oldVal) });
+ patches.push({ op: "test", path: path + "/" + helpers_js_1.escapePathComponent(key), value: helpers_js_1._deepClone(oldVal) });
}
- patches.push({ op: "replace", path: path + "/" + helpers_1.escapePathComponent(key), value: helpers_1._deepClone(newVal) });
+ patches.push({ op: "replace", path: path + "/" + helpers_js_1.escapePathComponent(key), value: helpers_js_1._deepClone(newVal) });
}
}
}
else if (Array.isArray(mirror) === Array.isArray(obj)) {
if (invertible) {
- patches.push({ op: "test", path: path + "/" + helpers_1.escapePathComponent(key), value: helpers_1._deepClone(oldVal) });
+ patches.push({ op: "test", path: path + "/" + helpers_js_1.escapePathComponent(key), value: helpers_js_1._deepClone(oldVal) });
}
- patches.push({ op: "remove", path: path + "/" + helpers_1.escapePathComponent(key) });
+ patches.push({ op: "remove", path: path + "/" + helpers_js_1.escapePathComponent(key) });
deleted = true; // property has been deleted
}
else {
@@ -870,8 +925,8 @@ function _generate(mirror, obj, patches, path, invertible) {
}
for (var t = 0; t < newKeys.length; t++) {
var key = newKeys[t];
- if (!helpers_1.hasOwnProperty(mirror, key) && obj[key] !== undefined) {
- patches.push({ op: "add", path: path + "/" + helpers_1.escapePathComponent(key), value: helpers_1._deepClone(obj[key]) });
+ if (!helpers_js_1.hasOwnProperty(mirror, key) && obj[key] !== undefined) {
+ patches.push({ op: "add", path: path + "/" + helpers_js_1.escapePathComponent(key), value: helpers_js_1._deepClone(obj[key]) });
}
}
}
@@ -890,7 +945,7 @@ exports.compare = compare;
*/
// import just to re-export as default
var core = __webpack_require__(1);
-var helpers_3 = __webpack_require__(0);
+var helpers_js_2 = __webpack_require__(0);
exports.default = __assign({}, core, {
// duplex
unobserve: unobserve,
@@ -898,70 +953,8 @@ exports.default = __assign({}, core, {
generate: generate,
compare: compare,
// helpers
- JsonPatchError: helpers_3.PatchError, deepClone: helpers_1._deepClone, escapePathComponent: helpers_1.escapePathComponent,
- unescapePathComponent: helpers_3.unescapePathComponent });
-
-
-/***/ }),
-/* 3 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-var isArray = Array.isArray;
-var keyList = Object.keys;
-var hasProp = Object.prototype.hasOwnProperty;
-
-module.exports = function equal(a, b) {
- if (a === b) return true;
-
- if (a && b && typeof a == 'object' && typeof b == 'object') {
- var arrA = isArray(a)
- , arrB = isArray(b)
- , i
- , length
- , key;
-
- if (arrA && arrB) {
- length = a.length;
- if (length != b.length) return false;
- for (i = length; i-- !== 0;)
- if (!equal(a[i], b[i])) return false;
- return true;
- }
-
- if (arrA != arrB) return false;
-
- var dateA = a instanceof Date
- , dateB = b instanceof Date;
- if (dateA != dateB) return false;
- if (dateA && dateB) return a.getTime() == b.getTime();
-
- var regexpA = a instanceof RegExp
- , regexpB = b instanceof RegExp;
- if (regexpA != regexpB) return false;
- if (regexpA && regexpB) return a.toString() == b.toString();
-
- var keys = keyList(a);
- length = keys.length;
-
- if (length !== keyList(b).length)
- return false;
-
- for (i = length; i-- !== 0;)
- if (!hasProp.call(b, keys[i])) return false;
-
- for (i = length; i-- !== 0;) {
- key = keys[i];
- if (!equal(a[key], b[key])) return false;
- }
-
- return true;
- }
-
- return a!==a && b!==b;
-};
+ JsonPatchError: helpers_js_2.PatchError, deepClone: helpers_js_1._deepClone, escapePathComponent: helpers_js_1.escapePathComponent,
+ unescapePathComponent: helpers_js_2.unescapePathComponent });
/***/ })
diff --git a/dist/fast-json-patch.min.js b/dist/fast-json-patch.min.js
index aaf25009..89646f44 100644
--- a/dist/fast-json-patch.min.js
+++ b/dist/fast-json-patch.min.js
@@ -5,10 +5,10 @@ var jsonpatch=function(e){var t={};function r(n){if(t[n])return t[n].exports;var
* (c) 2017 Joachim Wester
* MIT license
*/
-var r,n=this&&this.__extends||(r=function(e,t){return(r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r])})(e,t)},function(e,t){function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)});Object.defineProperty(t,"__esModule",{value:!0});var o=Object.prototype.hasOwnProperty;function a(e,t){return o.call(e,t)}function i(e){if(Array.isArray(e)){for(var t=new Array(e.length),r=0;r=48&&t<=57))return!1;r++}return!0},t.escapePathComponent=p,t.unescapePathComponent=function(e){return e.replace(/~1/g,"/").replace(/~0/g,"~")},t._getPathRecursive=u,t.getPath=function(e,t){if(e===t)return"/";var r=u(e,t);if(""===r)throw new Error("Object not found in root");return"/"+r},t.hasUndefined=function e(t){if(void 0===t)return!0;if(t)if(Array.isArray(t)){for(var r=0,n=t.length;r=w){if(u&&"add"===r.op&&O>v.length)throw new t.JsonPatchError("The specified index MUST NOT be greater than the number of elements in the array","OPERATION_VALUE_OUT_OF_BOUNDS",l,r,e);if(!1===(h=i[r.op].call(r,v,O,e)).test)throw new t.JsonPatchError("Test operation failed","TEST_OPERATION_FAILED",l,r,e);return h}}else if(O&&-1!=O.indexOf("~")&&(O=o.unescapePathComponent(O)),y>=w){if(!1===(h=a[r.op].call(r,v,O,e)).test)throw new t.JsonPatchError("Test operation failed","TEST_OPERATION_FAILED",l,r,e);return h}v=v[O]}}function s(e,r,n,a,i){if(void 0===a&&(a=!0),void 0===i&&(i=!0),n&&!Array.isArray(r))throw new t.JsonPatchError("Patch sequence must be an array","SEQUENCE_NOT_AN_ARRAY");a||(e=o._deepClone(e));for(var p=new Array(r.length),s=0,c=r.length;s0)throw new t.JsonPatchError('Operation `path` property must start with "/"',"OPERATION_PATH_INVALID",r,e,n);if(("move"===e.op||"copy"===e.op)&&"string"!=typeof e.from)throw new t.JsonPatchError("Operation `from` property is not present (applicable in `move` and `copy` operations)","OPERATION_FROM_REQUIRED",r,e,n);if(("add"===e.op||"replace"===e.op||"test"===e.op)&&void 0===e.value)throw new t.JsonPatchError("Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)","OPERATION_VALUE_REQUIRED",r,e,n);if(("add"===e.op||"replace"===e.op||"test"===e.op)&&o.hasUndefined(e.value))throw new t.JsonPatchError("Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)","OPERATION_VALUE_CANNOT_CONTAIN_UNDEFINED",r,e,n);if(n)if("add"==e.op){var p=e.path.split("/").length,u=i.split("/").length;if(p!==u+1&&p!==u)throw new t.JsonPatchError("Cannot perform an `add` operation at the desired path","OPERATION_PATH_CANNOT_ADD",r,e,n)}else if("replace"===e.op||"remove"===e.op||"_get"===e.op){if(e.path!==i)throw new t.JsonPatchError("Cannot perform the operation at a path that does not exist","OPERATION_PATH_UNRESOLVABLE",r,e,n)}else if("move"===e.op||"copy"===e.op){var s=l([{op:"_get",path:e.from,value:void 0}],n);if(s&&"OPERATION_PATH_UNRESOLVABLE"===s.name)throw new t.JsonPatchError("Cannot perform the operation from a path that does not exist","OPERATION_FROM_UNRESOLVABLE",r,e,n)}}function l(e,r,n){try{if(!Array.isArray(e))throw new t.JsonPatchError("Patch sequence must be an array","SEQUENCE_NOT_AN_ARRAY");if(r)s(o._deepClone(r),o._deepClone(e),n||!0);else{n=n||f;for(var a=0;a=48&&t<=57))return!1;r++}return!0},t.escapePathComponent=p,t.unescapePathComponent=function(e){return e.replace(/~1/g,"/").replace(/~0/g,"~")},t._getPathRecursive=u,t.getPath=function(e,t){if(e===t)return"/";var r=u(e,t);if(""===r)throw new Error("Object not found in root");return"/"+r},t.hasUndefined=function e(t){if(void 0===t)return!0;if(t)if(Array.isArray(t)){for(var r=0,n=t.length;r=w){if(p&&"add"===r.op&&O>v.length)throw new t.JsonPatchError("The specified index MUST NOT be greater than the number of elements in the array","OPERATION_VALUE_OUT_OF_BOUNDS",f,r,e);if(!1===(h=a[r.op].call(r,v,O,e)).test)throw new t.JsonPatchError("Test operation failed","TEST_OPERATION_FAILED",f,r,e);return h}}else if(O&&-1!=O.indexOf("~")&&(O=n.unescapePathComponent(O)),y>=w){if(!1===(h=o[r.op].call(r,v,O,e)).test)throw new t.JsonPatchError("Test operation failed","TEST_OPERATION_FAILED",f,r,e);return h}v=v[O]}}function u(e,r,o,a,i){if(void 0===a&&(a=!0),void 0===i&&(i=!0),o&&!Array.isArray(r))throw new t.JsonPatchError("Patch sequence must be an array","SEQUENCE_NOT_AN_ARRAY");a||(e=n._deepClone(e));for(var u=new Array(r.length),s=0,c=r.length;s0)throw new t.JsonPatchError('Operation `path` property must start with "/"',"OPERATION_PATH_INVALID",r,e,a);if(("move"===e.op||"copy"===e.op)&&"string"!=typeof e.from)throw new t.JsonPatchError("Operation `from` property is not present (applicable in `move` and `copy` operations)","OPERATION_FROM_REQUIRED",r,e,a);if(("add"===e.op||"replace"===e.op||"test"===e.op)&&void 0===e.value)throw new t.JsonPatchError("Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)","OPERATION_VALUE_REQUIRED",r,e,a);if(("add"===e.op||"replace"===e.op||"test"===e.op)&&n.hasUndefined(e.value))throw new t.JsonPatchError("Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)","OPERATION_VALUE_CANNOT_CONTAIN_UNDEFINED",r,e,a);if(a)if("add"==e.op){var p=e.path.split("/").length,u=i.split("/").length;if(p!==u+1&&p!==u)throw new t.JsonPatchError("Cannot perform an `add` operation at the desired path","OPERATION_PATH_CANNOT_ADD",r,e,a)}else if("replace"===e.op||"remove"===e.op||"_get"===e.op){if(e.path!==i)throw new t.JsonPatchError("Cannot perform the operation at a path that does not exist","OPERATION_PATH_UNRESOLVABLE",r,e,a)}else if("move"===e.op||"copy"===e.op){var s=f([{op:"_get",path:e.from,value:void 0}],a);if(s&&"OPERATION_PATH_UNRESOLVABLE"===s.name)throw new t.JsonPatchError("Cannot perform the operation from a path that does not exist","OPERATION_FROM_UNRESOLVABLE",r,e,a)}}function f(e,r,o){try{if(!Array.isArray(e))throw new t.JsonPatchError("Patch sequence must be an array","SEQUENCE_NOT_AN_ARRAY");if(r)u(n._deepClone(r),n._deepClone(e),o||!0);else{o=o||c;for(var a=0;a0&&(e.patches=[],e.callback&&e.callback(n)),n}function d(e,t,r,n,a){if(t!==e){"function"==typeof t.toJSON&&(t=t.toJSON());for(var i=o._objectKeys(t),p=o._objectKeys(e),u=!1,s=p.length-1;s>=0;s--){var c=e[l=p[s]];if(!o.hasOwnProperty(t,l)||void 0===t[l]&&void 0!==c&&!1===Array.isArray(t))Array.isArray(e)===Array.isArray(t)?(a&&r.push({op:"test",path:n+"/"+o.escapePathComponent(l),value:o._deepClone(c)}),r.push({op:"remove",path:n+"/"+o.escapePathComponent(l)}),u=!0):(a&&r.push({op:"test",path:n,value:e}),r.push({op:"replace",path:n,value:t}),!0);else{var f=t[l];"object"==typeof c&&null!=c&&"object"==typeof f&&null!=f?d(c,f,r,n+"/"+o.escapePathComponent(l),a):c!==f&&(!0,a&&r.push({op:"test",path:n+"/"+o.escapePathComponent(l),value:o._deepClone(c)}),r.push({op:"replace",path:n+"/"+o.escapePathComponent(l),value:o._deepClone(f)}))}}if(u||i.length!=p.length)for(s=0;s0&&(e.patches=[],e.callback&&e.callback(n)),n}function l(e,t,r,n,a){if(t!==e){"function"==typeof t.toJSON&&(t=t.toJSON());for(var i=o._objectKeys(t),p=o._objectKeys(e),u=!1,s=p.length-1;s>=0;s--){var c=e[h=p[s]];if(!o.hasOwnProperty(t,h)||void 0===t[h]&&void 0!==c&&!1===Array.isArray(t))Array.isArray(e)===Array.isArray(t)?(a&&r.push({op:"test",path:n+"/"+o.escapePathComponent(h),value:o._deepClone(c)}),r.push({op:"remove",path:n+"/"+o.escapePathComponent(h)}),u=!0):(a&&r.push({op:"test",path:n,value:e}),r.push({op:"replace",path:n,value:t}),!0);else{var f=t[h];"object"==typeof c&&null!=c&&"object"==typeof f&&null!=f?l(c,f,r,n+"/"+o.escapePathComponent(h),a):c!==f&&(!0,a&&r.push({op:"test",path:n+"/"+o.escapePathComponent(h),value:o._deepClone(c)}),r.push({op:"replace",path:n+"/"+o.escapePathComponent(h),value:o._deepClone(f)}))}}if(u||i.length!=p.length)for(s=0;s(root: T, observer: duplex.Observer): void;
+ observe(obj: Object | T[], callback?: (patches: core.Operation[]) => void): duplex.Observer;
+ generate(observer: duplex.Observer