[d24f17c] | 1 | JSON-Patch
|
---|
| 2 | ===============
|
---|
| 3 |
|
---|
| 4 | > A leaner and meaner implementation of JSON-Patch. Small footprint. High performance.
|
---|
| 5 |
|
---|
| 6 | [](https://travis-ci.org/Starcounter-Jack/JSON-Patch)
|
---|
| 7 |
|
---|
| 8 | With 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 |
|
---|
| 14 | Tested in Firefox, Chrome, Edge, Safari, IE11, Deno and Node.js
|
---|
| 15 |
|
---|
| 16 |
|
---|
| 17 | ## Why you should use JSON-Patch
|
---|
| 18 |
|
---|
| 19 | JSON-Patch [(RFC6902)](http://tools.ietf.org/html/rfc6902) is a standard format that
|
---|
| 20 | allows you to update a JSON document by sending the changes rather than the whole document.
|
---|
| 21 | JSON Patch plays well with the HTTP PATCH verb (method) and REST style programming.
|
---|
| 22 |
|
---|
| 23 | Mark 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
|
---|
| 32 | npm install fast-json-patch --save
|
---|
| 33 | ```
|
---|
| 34 |
|
---|
| 35 |
|
---|
| 36 | ## Adding to your project
|
---|
| 37 |
|
---|
| 38 | ### In a web browser
|
---|
| 39 |
|
---|
| 40 | Load the bundled distribution script:
|
---|
| 41 |
|
---|
| 42 | ```html
|
---|
| 43 | <script src="dist/fast-json-patch.min.js"></script>
|
---|
| 44 | ```
|
---|
| 45 |
|
---|
| 46 | In [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 |
|
---|
| 57 | In Node 12+ with `--experimental-modules` flag, the below code uses this library as an ECMAScript module:
|
---|
| 58 |
|
---|
| 59 | ```js
|
---|
| 60 | import * as jsonpatch from 'fast-json-patch/index.mjs';
|
---|
| 61 | import { applyOperation } from 'fast-json-patch/index.mjs';
|
---|
| 62 | ```
|
---|
| 63 |
|
---|
| 64 | In Webpack (and most surely other bundlers based on Babel), the below code uses this library as an ECMAScript module:
|
---|
| 65 |
|
---|
| 66 | ```js
|
---|
| 67 | import * as jsonpatch from 'fast-json-patch';
|
---|
| 68 | import { applyOperation } from 'fast-json-patch';
|
---|
| 69 | ```
|
---|
| 70 |
|
---|
| 71 | In standard Node, the below code uses this library as a CommonJS module:
|
---|
| 72 |
|
---|
| 73 | ```js
|
---|
| 74 | const { applyOperation } = require('fast-json-patch');
|
---|
| 75 | const applyOperation = require('fast-json-patch').applyOperation;
|
---|
| 76 | ```
|
---|
| 77 |
|
---|
| 78 | ## Directories
|
---|
| 79 |
|
---|
| 80 | Directories 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 |
|
---|
| 91 | Applies `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 |
|
---|
| 99 | An invalid patch results in throwing an error (see `jsonpatch.validate` for more information about the error object).
|
---|
| 100 |
|
---|
| 101 | It modifies the `document` object and `patch` - it gets the values by reference.
|
---|
| 102 | If you would like to avoid touching your `patch` array values, clone them: `jsonpatch.applyPatch(document, jsonpatch.deepClone(patch))`.
|
---|
| 103 |
|
---|
| 104 | Returns 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 |
|
---|
| 116 | Example:
|
---|
| 117 |
|
---|
| 118 | ```js
|
---|
| 119 | var document = { firstName: "Albert", contactDetails: { phoneNumbers: [] } };
|
---|
| 120 | var 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 | ];
|
---|
| 125 | document = 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 |
|
---|
| 131 | Applies 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 |
|
---|
| 140 | It modifies the `document` object and `operation` - it gets the values by reference.
|
---|
| 141 | If you would like to avoid touching your values, clone them: `jsonpatch.applyOperation(document, jsonpatch.deepClone(operation))`.
|
---|
| 142 |
|
---|
| 143 | Returns 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 |
|
---|
| 150 | Example:
|
---|
| 151 |
|
---|
| 152 | ```js
|
---|
| 153 | var document = { firstName: "Albert", contactDetails: { phoneNumbers: [] } };
|
---|
| 154 | var operation = { op: "replace", path: "/firstName", value: "Joachim" };
|
---|
| 155 | document = 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 |
|
---|
| 163 | Applies single operation object `operation` on `document`.
|
---|
| 164 |
|
---|
| 165 | Returns the a modified document.
|
---|
| 166 |
|
---|
| 167 | Note: It throws `TEST_OPERATION_FAILED` error if `test` operation fails.
|
---|
| 168 |
|
---|
| 169 | Example:
|
---|
| 170 |
|
---|
| 171 | ```js
|
---|
| 172 | var document = { firstName: "Albert", contactDetails: { phoneNumbers: [ ] } };
|
---|
| 173 | var 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 | ];
|
---|
| 178 | var 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 |
|
---|
| 184 | Returns deeply cloned value.
|
---|
| 185 |
|
---|
| 186 | #### `jsonpatch.escapePathComponent(path: string): string`
|
---|
| 187 |
|
---|
| 188 | Returns the escaped path.
|
---|
| 189 |
|
---|
| 190 | #### `jsonpatch.unescapePathComponent(path: string): string`
|
---|
| 191 |
|
---|
| 192 | Returns the unescaped path.
|
---|
| 193 |
|
---|
| 194 | #### `jsonpatch.getValueByPointer(document: object, pointer: string)`
|
---|
| 195 |
|
---|
| 196 | Retrieves a value from a JSON document by a JSON pointer.
|
---|
| 197 |
|
---|
| 198 | Returns the value.
|
---|
| 199 |
|
---|
| 200 | #### `jsonpatch.observe(document: any, callback?: Function): Observer`
|
---|
| 201 |
|
---|
| 202 | Sets up an deep observer on `document` that listens for changes in object tree. When changes are detected, the optional
|
---|
| 203 | callback is called with the generated patches array as the parameter.
|
---|
| 204 |
|
---|
| 205 | Returns `observer`.
|
---|
| 206 |
|
---|
| 207 | #### `jsonpatch.generate(document: any, observer: Observer, invertible = false): Operation[]`
|
---|
| 208 |
|
---|
| 209 | If there are pending changes in `obj`, returns them synchronously. If a `callback` was defined in `observe`
|
---|
| 210 | method, 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 |
|
---|
| 212 | If there are no pending changes in `obj`, returns an empty array (length 0).
|
---|
| 213 |
|
---|
| 214 | Example:
|
---|
| 215 |
|
---|
| 216 | ```js
|
---|
| 217 | var document = { firstName: "Joachim", lastName: "Wester", contactDetails: { phoneNumbers: [ { number:"555-123" }] } };
|
---|
| 218 | var observer = jsonpatch.observe(document);
|
---|
| 219 | document.firstName = "Albert";
|
---|
| 220 | document.contactDetails.phoneNumbers[0].number = "123";
|
---|
| 221 | document.contactDetails.phoneNumbers.push({ number:"456" });
|
---|
| 222 | var 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 |
|
---|
| 230 | Example of generating patches with test operations for values in the first object:
|
---|
| 231 |
|
---|
| 232 | ```js
|
---|
| 233 | var document = { firstName: "Joachim", lastName: "Wester", contactDetails: { phoneNumbers: [ { number:"555-123" }] } };
|
---|
| 234 | var observer = jsonpatch.observe(document);
|
---|
| 235 | document.firstName = "Albert";
|
---|
| 236 | document.contactDetails.phoneNumbers[0].number = "123";
|
---|
| 237 | document.contactDetails.phoneNumbers.push({ number:"456" });
|
---|
| 238 | var 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
|
---|
| 250 | jsonpatch.unobserve(document: any, observer: Observer): void
|
---|
| 251 |
|
---|
| 252 | type JsonableObj = { [key:string]: Jsonable };
|
---|
| 253 | type JsonableArr = Jsonable[];
|
---|
| 254 | type Jsonable = JsonableArr | JsonableObj | string | number | boolean | null;
|
---|
| 255 | ```
|
---|
| 256 |
|
---|
| 257 | Destroys the observer set up on `document`.
|
---|
| 258 |
|
---|
| 259 | Any 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
|
---|
| 264 | jsonpatch.compare(document1: Jsonable, document2: Jsonable, invertible = false): Operation[]
|
---|
| 265 |
|
---|
| 266 | type JsonableObj = { [key:string]: Jsonable };
|
---|
| 267 | type JsonableArr = Jsonable[];
|
---|
| 268 | type Jsonable = JsonableArr | JsonableObj | string | number | boolean | null;
|
---|
| 269 | ```
|
---|
| 270 |
|
---|
| 271 | Compares 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 |
|
---|
| 273 | If there are no differences, returns an empty array (length 0).
|
---|
| 274 |
|
---|
| 275 | Example:
|
---|
| 276 |
|
---|
| 277 | ```js
|
---|
| 278 | var documentA = {user: {firstName: "Albert", lastName: "Einstein"}};
|
---|
| 279 | var documentB = {user: {firstName: "Albert", lastName: "Collins"}};
|
---|
| 280 | var diff = jsonpatch.compare(documentA, documentB);
|
---|
| 281 | //diff == [{op: "replace", path: "/user/lastName", value: "Collins"}]
|
---|
| 282 | ```
|
---|
| 283 |
|
---|
| 284 | Example of comparing two object trees with test operations for values in the first object:
|
---|
| 285 |
|
---|
| 286 | ```js
|
---|
| 287 | var documentA = {user: {firstName: "Albert", lastName: "Einstein"}};
|
---|
| 288 | var documentB = {user: {firstName: "Albert", lastName: "Collins"}};
|
---|
| 289 | var 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 |
|
---|
| 298 | See [Validation notes](#validation-notes)
|
---|
| 299 |
|
---|
| 300 | Validates a sequence of operations. If `document` parameter is provided, the sequence is additionally validated against the object tree.
|
---|
| 301 |
|
---|
| 302 | If 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 |
|
---|
| 310 | Possible errors:
|
---|
| 311 |
|
---|
| 312 | Error name | Error message
|
---|
| 313 | ------------------------------|------------
|
---|
| 314 | SEQUENCE_NOT_AN_ARRAY | Patch sequence must be an array
|
---|
| 315 | OPERATION_NOT_AN_OBJECT | Operation is not an object
|
---|
| 316 | OPERATION_OP_INVALID | Operation `op` property is not one of operations defined in RFC-6902
|
---|
| 317 | OPERATION_PATH_INVALID | Operation `path` property is not a valid string
|
---|
| 318 | OPERATION_FROM_REQUIRED | Operation `from` property is not present (applicable in `move` and `copy` operations)
|
---|
| 319 | OPERATION_VALUE_REQUIRED | Operation `value` property is not present, or `undefined` (applicable in `add`, `replace` and `test` operations)
|
---|
| 320 | OPERATION_VALUE_CANNOT_CONTAIN_UNDEFINED | Operation `value` property object has at least one `undefined` value (applicable in `add`, `replace` and `test` operations)
|
---|
| 321 | OPERATION_PATH_CANNOT_ADD | Cannot perform an `add` operation at the desired path
|
---|
| 322 | OPERATION_PATH_UNRESOLVABLE | Cannot perform the operation at a path that does not exist
|
---|
| 323 | OPERATION_FROM_UNRESOLVABLE | Cannot perform the operation from a path that does not exist
|
---|
| 324 | 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
|
---|
| 325 | OPERATION_VALUE_OUT_OF_BOUNDS | The specified index MUST NOT be greater than the number of elements in the array
|
---|
| 326 | TEST_OPERATION_FAILED | When operation is `test` and the test fails, applies to `applyReducer`.
|
---|
| 327 |
|
---|
| 328 | Example:
|
---|
| 329 |
|
---|
| 330 | ```js
|
---|
| 331 | var obj = {user: {firstName: "Albert"}};
|
---|
| 332 | var patches = [{op: "replace", path: "/user/firstName", value: "Albert"}, {op: "replace", path: "/user/lastName", value: "Einstein"}];
|
---|
| 333 | var errors = jsonpatch.validate(patches, obj);
|
---|
| 334 | if (errors.length == 0) {
|
---|
| 335 | //there are no errors!
|
---|
| 336 | }
|
---|
| 337 | else {
|
---|
| 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 |
|
---|
| 351 | Functions `applyPatch` and `applyOperation` both return `OperationResult` object. This object is:
|
---|
| 352 |
|
---|
| 353 | ```ts
|
---|
| 354 | {newDocument: any, test?: boolean, removed?: any}
|
---|
| 355 | ```
|
---|
| 356 |
|
---|
| 357 | Where:
|
---|
| 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 |
|
---|
| 366 | Functions `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 |
|
---|
| 372 | If 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 |
|
---|
| 381 | When 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 |
|
---|
| 385 | 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`.
|
---|
| 386 |
|
---|
| 387 | 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)](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 |
|
---|
| 391 | See 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 |
|
---|
| 401 | To see the list of recent changes, see [Releases](https://github.com/Starcounter-Jack/JSON-Patch/releases).
|
---|
| 402 |
|
---|
| 403 | ## Footprint
|
---|
| 404 | 4 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 | 
|
---|
| 411 |
|
---|
| 412 | ##### [`replace` benchmark](https://run.perf.zone/view/JSON-Patch-Replace-Operation-1535540952263)
|
---|
| 413 |
|
---|
| 414 | 
|
---|
| 415 |
|
---|
| 416 | Tested 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 |
|
---|
| 424 | 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.
|
---|
| 425 |
|
---|
| 426 | ## License
|
---|
| 427 |
|
---|
| 428 | MIT
|
---|