source: node_modules/fast-json-patch/README.md

main
Last change on this file was d24f17c, checked in by Aleksandar Panovski <apano77@…>, 15 months ago

Initial commit

  • Property mode set to 100644
File size: 17.8 KB
RevLine 
[d24f17c]1JSON-Patch
2===============
3
4> A leaner and meaner implementation of JSON-Patch. Small footprint. High performance.
5
6[![Build Status](https://travis-ci.org/Starcounter-Jack/JSON-Patch.svg?branch=master)](https://travis-ci.org/Starcounter-Jack/JSON-Patch)
7
8With JSON-Patch, you can:
9- **apply** patches (arrays) and single operations on JS object
10- **validate** a sequence of patches
11- **observe** for changes and **generate** patches when a change is detected
12- **compare** two objects to obtain the difference
13
14Tested in Firefox, Chrome, Edge, Safari, IE11, Deno and Node.js
15
16
17## Why you should use JSON-Patch
18
19JSON-Patch [(RFC6902)](http://tools.ietf.org/html/rfc6902) is a standard format that
20allows you to update a JSON document by sending the changes rather than the whole document.
21JSON Patch plays well with the HTTP PATCH verb (method) and REST style programming.
22
23Mark Nottingham has a [nice blog]( http://www.mnot.net/blog/2012/09/05/patch) about it.
24
25
26## Install
27
28[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):
29
30```sh
31# NPM
32npm install fast-json-patch --save
33```
34
35
36## Adding to your project
37
38### In a web browser
39
40Load the bundled distribution script:
41
42```html
43<script src="dist/fast-json-patch.min.js"></script>
44```
45
46In [browsers that support ECMAScript modules](https://caniuse.com/#feat=es6-module), the below code uses this library as a module:
47
48```html
49<script type="module">
50 import * as jsonpatch from 'fast-json-patch/index.mjs';
51 import { applyOperation } from 'fast-json-patch/index.mjs';
52</script>
53```
54
55### In Node.js
56
57In Node 12+ with `--experimental-modules` flag, the below code uses this library as an ECMAScript module:
58
59```js
60import * as jsonpatch from 'fast-json-patch/index.mjs';
61import { applyOperation } from 'fast-json-patch/index.mjs';
62```
63
64In Webpack (and most surely other bundlers based on Babel), the below code uses this library as an ECMAScript module:
65
66```js
67import * as jsonpatch from 'fast-json-patch';
68import { applyOperation } from 'fast-json-patch';
69```
70
71In standard Node, the below code uses this library as a CommonJS module:
72
73```js
74const { applyOperation } = require('fast-json-patch');
75const applyOperation = require('fast-json-patch').applyOperation;
76```
77
78## Directories
79
80Directories used in this package:
81
82- `dist/` - contains ES5 files for a Web browser
83- `commonjs/` - contains CommonJS module and typings
84- `module/` - contains ECMAScript module and typings
85- `src/` - contains TypeScript source files
86
87## API
88
89#### `function applyPatch<T>(document: T, patch: Operation[], validateOperation?: boolean | Validator<T>, mutateDocument: boolean = true, banPrototypeModifications: boolean = true): PatchResult<T>`
90
91Applies `patch` array on `obj`.
92
93- `document` The document to patch
94- `patch` a JSON-Patch array of operations to apply
95- `validateOperation` Boolean for whether to validate each operation with our default validator, or to pass a validator callback
96- `mutateDocument` Whether to mutate the original document or clone it before applying
97- `banPrototypeModifications` Whether to ban modifications to `__proto__`, defaults to `true`.
98
99An invalid patch results in throwing an error (see `jsonpatch.validate` for more information about the error object).
100
101It modifies the `document` object and `patch` - it gets the values by reference.
102If you would like to avoid touching your `patch` array values, clone them: `jsonpatch.applyPatch(document, jsonpatch.deepClone(patch))`.
103
104Returns an array of [`OperationResult`](#operationresult-type) objects - one item for each item in `patches`, each item is an object `{newDocument: any, test?: boolean, removed?: any}`.
105
106* `test` - boolean result of the test
107* `remove`, `replace` and `move` - original object that has been removed
108* `add` (only when adding to an array) - index at which item has been inserted (useful when using `-` alias)
109
110- ** Note: It throws `TEST_OPERATION_FAILED` error if `test` operation fails. **
111- ** Note II: the returned array has `newDocument` property that you can use as the final state of the patched document **.
112- ** Note III: By default, when `banPrototypeModifications` is `true`, this method throws a `TypeError` when you attempt to modify an object's prototype.
113
114- See [Validation notes](#validation-notes).
115
116Example:
117
118```js
119var document = { firstName: "Albert", contactDetails: { phoneNumbers: [] } };
120var patch = [
121 { op: "replace", path: "/firstName", value: "Joachim" },
122 { op: "add", path: "/lastName", value: "Wester" },
123 { op: "add", path: "/contactDetails/phoneNumbers/0", value: { number: "555-123" } }
124];
125document = jsonpatch.applyPatch(document, patch).newDocument;
126// document == { firstName: "Joachim", lastName: "Wester", contactDetails: { phoneNumbers: [{number:"555-123"}] } };
127```
128
129#### `function applyOperation<T>(document: T, operation: Operation, validateOperation: boolean | Validator<T> = false, mutateDocument: boolean = true, banPrototypeModifications: boolean = true, index: number = 0): OperationResult<T>`
130
131Applies single operation object `operation` on `document`.
132
133- `document` The document to patch
134- `operation` The operation to apply
135- `validateOperation` Whether to validate the operation, or to pass a validator callback
136- `mutateDocument` Whether to mutate the original document or clone it before applying
137- `banPrototypeModifications` Whether to ban modifications to `__proto__`, defaults to `true`.
138- `index` The index of the operation in your patch array. Useful for better error reporting when that operation fails to apply.
139
140It modifies the `document` object and `operation` - it gets the values by reference.
141If you would like to avoid touching your values, clone them: `jsonpatch.applyOperation(document, jsonpatch.deepClone(operation))`.
142
143Returns an [`OperationResult`](#operationresult-type) object `{newDocument: any, test?: boolean, removed?: any}`.
144
145- ** Note: It throws `TEST_OPERATION_FAILED` error if `test` operation fails. **
146- ** Note II: By default, when `banPrototypeModifications` is `true`, this method throws a `TypeError` when you attempt to modify an object's prototype.
147
148- See [Validation notes](#validation-notes).
149
150Example:
151
152```js
153var document = { firstName: "Albert", contactDetails: { phoneNumbers: [] } };
154var operation = { op: "replace", path: "/firstName", value: "Joachim" };
155document = jsonpatch.applyOperation(document, operation).newDocument;
156// document == { firstName: "Joachim", contactDetails: { phoneNumbers: [] }}
157```
158
159#### `jsonpatch.applyReducer<T>(document: T, operation: Operation, index: number): T`
160
161**Ideal for `patch.reduce(jsonpatch.applyReducer, document)`**.
162
163Applies single operation object `operation` on `document`.
164
165Returns the a modified document.
166
167Note: It throws `TEST_OPERATION_FAILED` error if `test` operation fails.
168
169Example:
170
171```js
172var document = { firstName: "Albert", contactDetails: { phoneNumbers: [ ] } };
173var patch = [
174 { op:"replace", path: "/firstName", value: "Joachim" },
175 { op:"add", path: "/lastName", value: "Wester" },
176 { op:"add", path: "/contactDetails/phoneNumbers/0", value: { number: "555-123" } }
177];
178var updatedDocument = patch.reduce(applyReducer, document);
179// updatedDocument == { firstName:"Joachim", lastName:"Wester", contactDetails:{ phoneNumbers[ {number:"555-123"} ] } };
180```
181
182#### `jsonpatch.deepClone(value: any): any`
183
184Returns deeply cloned value.
185
186#### `jsonpatch.escapePathComponent(path: string): string`
187
188Returns the escaped path.
189
190#### `jsonpatch.unescapePathComponent(path: string): string`
191
192Returns the unescaped path.
193
194#### `jsonpatch.getValueByPointer(document: object, pointer: string)`
195
196Retrieves a value from a JSON document by a JSON pointer.
197
198Returns the value.
199
200#### `jsonpatch.observe(document: any, callback?: Function): Observer`
201
202Sets up an deep observer on `document` that listens for changes in object tree. When changes are detected, the optional
203callback is called with the generated patches array as the parameter.
204
205Returns `observer`.
206
207#### `jsonpatch.generate(document: any, observer: Observer, invertible = false): Operation[]`
208
209If there are pending changes in `obj`, returns them synchronously. If a `callback` was defined in `observe`
210method, it will be triggered synchronously as well. If `invertible` is true, then each change will be preceded by a test operation of the value before the change.
211
212If there are no pending changes in `obj`, returns an empty array (length 0).
213
214Example:
215
216```js
217var document = { firstName: "Joachim", lastName: "Wester", contactDetails: { phoneNumbers: [ { number:"555-123" }] } };
218var observer = jsonpatch.observe(document);
219document.firstName = "Albert";
220document.contactDetails.phoneNumbers[0].number = "123";
221document.contactDetails.phoneNumbers.push({ number:"456" });
222var patch = jsonpatch.generate(observer);
223// patch == [
224// { op: "replace", path: "/firstName", value: "Albert"},
225// { op: "replace", path: "/contactDetails/phoneNumbers/0/number", value: "123" },
226// { op: "add", path: "/contactDetails/phoneNumbers/1", value: {number:"456"}}
227// ];
228```
229
230Example of generating patches with test operations for values in the first object:
231
232```js
233var document = { firstName: "Joachim", lastName: "Wester", contactDetails: { phoneNumbers: [ { number:"555-123" }] } };
234var observer = jsonpatch.observe(document);
235document.firstName = "Albert";
236document.contactDetails.phoneNumbers[0].number = "123";
237document.contactDetails.phoneNumbers.push({ number:"456" });
238var patch = jsonpatch.generate(observer, true);
239// patch == [
240// { op: "test", path: "/firstName", value: "Joachim"},
241// { op: "replace", path: "/firstName", value: "Albert"},
242// { op: "test", path: "/contactDetails/phoneNumbers/0/number", value: "555-123" },
243// { op: "replace", path: "/contactDetails/phoneNumbers/0/number", value: "123" },
244// { op: "add", path: "/contactDetails/phoneNumbers/1", value: {number:"456"}}
245// ];
246```
247
248#### `jsonpatch.unobserve(document, observer)`
249```typescript
250jsonpatch.unobserve(document: any, observer: Observer): void
251
252type JsonableObj = { [key:string]: Jsonable };
253type JsonableArr = Jsonable[];
254type Jsonable = JsonableArr | JsonableObj | string | number | boolean | null;
255```
256
257Destroys the observer set up on `document`.
258
259Any remaining changes are delivered synchronously (as in `jsonpatch.generate`). Note: this is different that ES6/7 `Object.unobserve`, which delivers remaining changes asynchronously.
260
261#### `jsonpatch.compare(document1, document2, invertible)`
262
263```typescript
264jsonpatch.compare(document1: Jsonable, document2: Jsonable, invertible = false): Operation[]
265
266type JsonableObj = { [key:string]: Jsonable };
267type JsonableArr = Jsonable[];
268type Jsonable = JsonableArr | JsonableObj | string | number | boolean | null;
269```
270
271Compares object trees `document1` and `document2` and returns the difference relative to `document1` as a patches array. If `invertible` is true, then each change will be preceded by a test operation of the value in `document1`.
272
273If there are no differences, returns an empty array (length 0).
274
275Example:
276
277```js
278var documentA = {user: {firstName: "Albert", lastName: "Einstein"}};
279var documentB = {user: {firstName: "Albert", lastName: "Collins"}};
280var diff = jsonpatch.compare(documentA, documentB);
281//diff == [{op: "replace", path: "/user/lastName", value: "Collins"}]
282```
283
284Example of comparing two object trees with test operations for values in the first object:
285
286```js
287var documentA = {user: {firstName: "Albert", lastName: "Einstein"}};
288var documentB = {user: {firstName: "Albert", lastName: "Collins"}};
289var diff = jsonpatch.compare(documentA, documentB, true);
290//diff == [
291// {op: "test", path: "/user/lastName", value: "Einstein"},
292// {op: "replace", path: "/user/lastName", value: "Collins"}
293// ];
294```
295
296#### `jsonpatch.validate(patch: Operation[], document?: any, validator?: Function): JsonPatchError`
297
298See [Validation notes](#validation-notes)
299
300Validates a sequence of operations. If `document` parameter is provided, the sequence is additionally validated against the object tree.
301
302If there are no errors, returns undefined. If there is an errors, returns a JsonPatchError object with the following properties:
303
304- `name` String - short error code
305- `message` String - long human readable error message
306- `index` Number - index of the operation in the sequence
307- `operation` Object - reference to the operation
308- `tree` Object - reference to the tree
309
310Possible errors:
311
312Error name | Error message
313------------------------------|------------
314SEQUENCE_NOT_AN_ARRAY | Patch sequence must be an array
315OPERATION_NOT_AN_OBJECT | Operation is not an object
316OPERATION_OP_INVALID | Operation `op` property is not one of operations defined in RFC-6902
317OPERATION_PATH_INVALID | Operation `path` property is not a valid string
318OPERATION_FROM_REQUIRED | Operation `from` property is not present (applicable in `move` and `copy` operations)
319OPERATION_VALUE_REQUIRED | Operation `value` property is not present, or `undefined` (applicable in `add`, `replace` and `test` operations)
320OPERATION_VALUE_CANNOT_CONTAIN_UNDEFINED | Operation `value` property object has at least one `undefined` value (applicable in `add`, `replace` and `test` operations)
321OPERATION_PATH_CANNOT_ADD | Cannot perform an `add` operation at the desired path
322OPERATION_PATH_UNRESOLVABLE | Cannot perform the operation at a path that does not exist
323OPERATION_FROM_UNRESOLVABLE | Cannot perform the operation from a path that does not exist
324OPERATION_PATH_ILLEGAL_ARRAY_INDEX | Expected an unsigned base-10 integer value, making the new referenced value the array element with the zero-based index
325OPERATION_VALUE_OUT_OF_BOUNDS | The specified index MUST NOT be greater than the number of elements in the array
326TEST_OPERATION_FAILED | When operation is `test` and the test fails, applies to `applyReducer`.
327
328Example:
329
330```js
331var obj = {user: {firstName: "Albert"}};
332var patches = [{op: "replace", path: "/user/firstName", value: "Albert"}, {op: "replace", path: "/user/lastName", value: "Einstein"}];
333var errors = jsonpatch.validate(patches, obj);
334if (errors.length == 0) {
335 //there are no errors!
336}
337else {
338 for (var i=0; i < errors.length; i++) {
339 if (!errors[i]) {
340 console.log("Valid patch at index", i, patches[i]);
341 }
342 else {
343 console.error("Invalid patch at index", i, errors[i], patches[i]);
344 }
345 }
346}
347```
348
349## `OperationResult` Type
350
351Functions `applyPatch` and `applyOperation` both return `OperationResult` object. This object is:
352
353```ts
354{newDocument: any, test?: boolean, removed?: any}
355```
356
357Where:
358
359- `newDocument`: the new state of the document after the patch/operation is applied.
360- `test`: if the operation was a `test` operation. This will be its result.
361- `removed`: contains the removed, moved, or replaced values from the document after a `remove`, `move` or `replace` operation.
362
363
364## Validation Notes
365
366Functions `applyPatch`, `applyOperation`, and `validate` accept a `validate`/ `validator` parameter:
367
368- If the `validateOperation` parameter is set to `false`, validation will not occur.
369- If set to `true`, the patch is extensively validated before applying using jsonpatch's default validation.
370- If set to a `function` callback, the patch is validated using that function.
371
372If you pass a validator, it will be called with four parameters for each operation, `function(operation, index, tree, existingPath)` and it is expected to throw `JsonPatchError` when your conditions are not met.
373
374- `operation` The operation it self.
375- `index` `operation`'s index in the patch array (if application).
376- `tree` The object that is supposed to be patched.
377- `existingPath` the path `operation` points to.
378
379## Overwriting and `move` Operation
380
381When the target of the move operation already exists, it is cached, deep cloned and returned as `removed` in `OperationResult`.
382
383## `undefined`s (JS to JSON projection)
384
385As `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`.
386
387Whenever 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)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) treats them:
388
389> 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).
390
391See the [ECMAScript spec](http://www.ecma-international.org/ecma-262/6.0/index.html#sec-json.stringify) for details.
392
393## Specs/tests
394
395 - [Run in browser](http://starcounter-jack.github.io/JSON-Patch/test/)
396
397## [Contributing](CONTRIBUTING.md)
398
399## Changelog
400
401To see the list of recent changes, see [Releases](https://github.com/Starcounter-Jack/JSON-Patch/releases).
402
403## Footprint
4044 KB minified and gzipped (12 KB minified)
405
406## Performance
407
408##### [`add` benchmark](https://run.perf.zone/view/JSON-Patch-Add-Operation-1535541298893)
409
410![image](https://user-images.githubusercontent.com/17054134/44784357-aa422480-ab8d-11e8-8a7e-037e692dd842.png)
411
412##### [`replace` benchmark](https://run.perf.zone/view/JSON-Patch-Replace-Operation-1535540952263)
413
414![image](https://user-images.githubusercontent.com/17054134/44784275-5fc0a800-ab8d-11e8-8a90-e87b8d5409d0.png)
415
416Tested on 29.08.2018. Compared libraries:
417
418- [Starcounter-Jack/JSON-Patch](https://www.npmjs.com/package/fast-json-patch) 2.0.6
419- [bruth/jsonpatch-js](https://www.npmjs.com/package/json-patch) 0.7.0
420- [dharmafly/jsonpatch.js](https://www.npmjs.com/package/jsonpatch) 3.0.1
421- [jiff](https://www.npmjs.com/package/jiff) 0.7.3
422- [RFC6902](https://www.npmjs.com/package/rfc6902) 2.4.0
423
424We 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.
425
426## License
427
428MIT
Note: See TracBrowser for help on using the repository browser.