{"id":13652514,"url":"https://github.com/Starcounter-Jack/JSON-Patch","last_synced_at":"2025-04-23T03:30:52.578Z","repository":{"id":7471023,"uuid":"8818872","full_name":"Starcounter-Jack/JSON-Patch","owner":"Starcounter-Jack","description":"Lean and mean Javascript implementation of the JSON-Patch standard (RFC 6902). Update JSON documents using delta patches.","archived":false,"fork":false,"pushed_at":"2024-07-17T00:41:04.000Z","size":4058,"stargazers_count":1866,"open_issues_count":79,"forks_count":220,"subscribers_count":28,"default_branch":"master","last_synced_at":"2025-04-19T05:55:51.926Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Starcounter-Jack.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-03-16T13:08:46.000Z","updated_at":"2025-04-18T08:03:00.000Z","dependencies_parsed_at":"2024-11-10T03:41:12.015Z","dependency_job_id":null,"html_url":"https://github.com/Starcounter-Jack/JSON-Patch","commit_stats":{"total_commits":510,"total_committers":51,"mean_commits":10.0,"dds":0.7176470588235294,"last_synced_commit":"9d313ac01916e525e9204074f06e5295edec491b"},"previous_names":[],"tags_count":50,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Starcounter-Jack%2FJSON-Patch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Starcounter-Jack%2FJSON-Patch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Starcounter-Jack%2FJSON-Patch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Starcounter-Jack%2FJSON-Patch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Starcounter-Jack","download_url":"https://codeload.github.com/Starcounter-Jack/JSON-Patch/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249694636,"owners_count":21311561,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T02:01:00.040Z","updated_at":"2025-04-23T03:30:51.246Z","avatar_url":"https://github.com/Starcounter-Jack.png","language":"JavaScript","funding_links":[],"categories":["Differencing","JavaScript"],"sub_categories":[],"readme":"JSON-Patch\n===============\n\n\u003e A leaner and meaner implementation of JSON-Patch. Small footprint. High performance.\n\n[![Build Status](https://travis-ci.org/Starcounter-Jack/JSON-Patch.svg?branch=master)](https://travis-ci.org/Starcounter-Jack/JSON-Patch)\n\nWith JSON-Patch, you can:\n- **apply** patches (arrays) and single operations on JS object\n- **validate** a sequence of patches\n- **observe** for changes and **generate** patches when a change is detected\n- **compare** two objects to obtain the difference\n\nTested in Firefox, Chrome, Edge, Safari, IE11, Deno and Node.js\n\n\n## Why you should use JSON-Patch\n\nJSON-Patch [(RFC6902)](http://tools.ietf.org/html/rfc6902) is a standard format that\nallows you to update a JSON document by sending the changes rather than the whole document.\nJSON Patch plays well with the HTTP PATCH verb (method) and REST style programming.\n\nMark Nottingham has a [nice blog]( http://www.mnot.net/blog/2012/09/05/patch) about it.\n\n\n## Install\n\n[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):\n\n```sh\n# NPM\nnpm install fast-json-patch --save\n```\n\n\n## Adding to your project\n\n### In a web browser\n\nLoad the bundled distribution script:\n\n```html\n\u003cscript src=\"dist/fast-json-patch.min.js\"\u003e\u003c/script\u003e\n```\n\nIn [browsers that support ECMAScript modules](https://caniuse.com/#feat=es6-module), the below code uses this library as a module:\n\n```html\n\u003cscript type=\"module\"\u003e\n  import * as jsonpatch from 'fast-json-patch/index.mjs';\n  import { applyOperation } from 'fast-json-patch/index.mjs';\n\u003c/script\u003e\n```\n\n### In Node.js\n\nIn Node 12+ with `--experimental-modules` flag, the below code uses this library as an ECMAScript module:\n\n```js\nimport * as jsonpatch from 'fast-json-patch/index.mjs';\nimport { applyOperation } from 'fast-json-patch/index.mjs';\n```\n\nIn Webpack (and most surely other bundlers based on Babel), the below code uses this library as an ECMAScript module:\n\n```js\nimport * as jsonpatch from 'fast-json-patch';\nimport { applyOperation } from 'fast-json-patch';\n```\n\nIn standard Node, the below code uses this library as a CommonJS module:\n\n```js\nconst { applyOperation } = require('fast-json-patch');\nconst applyOperation = require('fast-json-patch').applyOperation;\n```\n\n## Directories\n\nDirectories used in this package:\n\n- `dist/` - contains ES5 files for a Web browser\n- `commonjs/` - contains CommonJS module and typings\n- `module/` - contains ECMAScript module and typings\n- `src/` - contains TypeScript source files\n\n## API\n\n#### `function applyPatch\u003cT\u003e(document: T, patch: Operation[], validateOperation?: boolean | Validator\u003cT\u003e, mutateDocument: boolean = true, banPrototypeModifications: boolean = true): PatchResult\u003cT\u003e`\n\nApplies `patch` array on `obj`.\n\n- `document` The document to patch\n- `patch` a JSON-Patch array of operations to apply\n- `validateOperation` Boolean for whether to validate each operation with our default validator, or to pass a validator callback\n- `mutateDocument` Whether to mutate the original document or clone it before applying\n- `banPrototypeModifications`  Whether to ban modifications to `__proto__`, defaults to `true`.\n\nAn invalid patch results in throwing an error (see `jsonpatch.validate` for more information about the error object).\n\nIt modifies the `document` object and `patch` - it gets the values by reference.\nIf you would like to avoid touching your `patch` array values, clone them: `jsonpatch.applyPatch(document, jsonpatch.deepClone(patch))`.\n\nReturns 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}`.\n\n* `test` - boolean result of the test\n* `remove`, `replace` and `move` - original object that has been removed\n* `add` (only when adding to an array) - index at which item has been inserted (useful when using `-` alias)\n\n- ** Note: It throws `TEST_OPERATION_FAILED` error if `test` operation fails. **\n- ** Note II: the returned array has `newDocument` property that you can use as the final state of the patched document **.\n- ** Note III: By default, when `banPrototypeModifications` is `true`, this method throws a `TypeError` when you attempt to modify an object's prototype.\n\n- See [Validation notes](#validation-notes).\n\nExample:\n\n```js\nvar document = { firstName: \"Albert\", contactDetails: { phoneNumbers: [] } };\nvar patch = [\n  { op: \"replace\", path: \"/firstName\", value: \"Joachim\" },\n  { op: \"add\", path: \"/lastName\", value: \"Wester\" },\n  { op: \"add\", path: \"/contactDetails/phoneNumbers/0\", value: { number: \"555-123\" }  }\n];\ndocument = jsonpatch.applyPatch(document, patch).newDocument;\n// document == { firstName: \"Joachim\", lastName: \"Wester\", contactDetails: { phoneNumbers: [{number:\"555-123\"}] } };\n```\n\n#### `function applyOperation\u003cT\u003e(document: T, operation: Operation, validateOperation: boolean | Validator\u003cT\u003e = false, mutateDocument: boolean = true, banPrototypeModifications: boolean = true, index: number = 0): OperationResult\u003cT\u003e`\n\nApplies single operation object `operation` on `document`.\n\n- `document` The document to patch\n- `operation` The operation to apply\n- `validateOperation` Whether to validate the operation, or to pass a validator callback\n- `mutateDocument` Whether to mutate the original document or clone it before applying\n- `banPrototypeModifications` Whether to ban modifications to `__proto__`, defaults to `true`.\n- `index` The index of the operation in your patch array. Useful for better error reporting when that operation fails to apply.\n\nIt modifies the `document` object and `operation` - it gets the values by reference.\nIf you would like to avoid touching your values, clone them: `jsonpatch.applyOperation(document, jsonpatch.deepClone(operation))`.\n\nReturns an [`OperationResult`](#operationresult-type) object `{newDocument: any, test?: boolean, removed?: any}`.\n\n- ** Note: It throws `TEST_OPERATION_FAILED` error if `test` operation fails. **\n- ** Note II: By default, when `banPrototypeModifications` is `true`, this method throws a `TypeError` when you attempt to modify an object's prototype.\n\n- See [Validation notes](#validation-notes).\n\nExample:\n\n```js\nvar document = { firstName: \"Albert\", contactDetails: { phoneNumbers: [] } };\nvar operation = { op: \"replace\", path: \"/firstName\", value: \"Joachim\" };\ndocument = jsonpatch.applyOperation(document, operation).newDocument;\n// document == { firstName: \"Joachim\", contactDetails: { phoneNumbers: [] }}\n```\n\n#### `jsonpatch.applyReducer\u003cT\u003e(document: T, operation: Operation, index: number): T`\n\n**Ideal for `patch.reduce(jsonpatch.applyReducer, document)`**.\n\nApplies single operation object `operation` on `document`.\n\nReturns the a modified document.\n\nNote: It throws `TEST_OPERATION_FAILED` error if `test` operation fails.\n\nExample:\n\n```js\nvar document = { firstName: \"Albert\", contactDetails: { phoneNumbers: [ ] } };\nvar patch = [\n  { op:\"replace\", path: \"/firstName\", value: \"Joachim\" },\n  { op:\"add\", path: \"/lastName\", value: \"Wester\" },\n  { op:\"add\", path: \"/contactDetails/phoneNumbers/0\", value: { number: \"555-123\" } }\n];\nvar updatedDocument = patch.reduce(applyReducer, document);\n// updatedDocument == { firstName:\"Joachim\", lastName:\"Wester\", contactDetails:{ phoneNumbers[ {number:\"555-123\"} ] } };\n```\n\n#### `jsonpatch.deepClone(value: any): any`\n\nReturns deeply cloned value.\n\n#### `jsonpatch.escapePathComponent(path: string): string`\n\nReturns the escaped path.\n\n#### `jsonpatch.unescapePathComponent(path: string): string`\n\nReturns the unescaped path.\n\n#### `jsonpatch.getValueByPointer(document: object, pointer: string)`\n\nRetrieves a value from a JSON document by a JSON pointer.\n\nReturns the value.\n\n#### `jsonpatch.observe(document: any, callback?: Function): Observer`\n\nSets up an deep observer on `document` that listens for changes in object tree. When changes are detected, the optional\ncallback is called with the generated patches array as the parameter.\n\nReturns `observer`.\n\n#### `jsonpatch.generate(document: any, observer: Observer, invertible = false): Operation[]`\n\nIf there are pending changes in `obj`, returns them synchronously. If a `callback` was defined in `observe`\nmethod, 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.\n\nIf there are no pending changes in `obj`, returns an empty array (length 0).\n\nExample:\n\n```js\nvar document = { firstName: \"Joachim\", lastName: \"Wester\", contactDetails: { phoneNumbers: [ { number:\"555-123\" }] } };\nvar observer = jsonpatch.observe(document);\ndocument.firstName = \"Albert\";\ndocument.contactDetails.phoneNumbers[0].number = \"123\";\ndocument.contactDetails.phoneNumbers.push({ number:\"456\" });\nvar patch = jsonpatch.generate(observer);\n// patch  == [\n//   { op: \"replace\", path: \"/firstName\", value: \"Albert\"},\n//   { op: \"replace\", path: \"/contactDetails/phoneNumbers/0/number\", value: \"123\" },\n//   { op: \"add\", path: \"/contactDetails/phoneNumbers/1\", value: {number:\"456\"}}\n// ];\n```\n\nExample of generating patches with test operations for values in the first object:\n\n```js\nvar document = { firstName: \"Joachim\", lastName: \"Wester\", contactDetails: { phoneNumbers: [ { number:\"555-123\" }] } };\nvar observer = jsonpatch.observe(document);\ndocument.firstName = \"Albert\";\ndocument.contactDetails.phoneNumbers[0].number = \"123\";\ndocument.contactDetails.phoneNumbers.push({ number:\"456\" });\nvar patch = jsonpatch.generate(observer, true);\n// patch  == [\n//   { op: \"test\", path: \"/firstName\", value: \"Joachim\"},\n//   { op: \"replace\", path: \"/firstName\", value: \"Albert\"},\n//   { op: \"test\", path: \"/contactDetails/phoneNumbers/0/number\", value: \"555-123\" },\n//   { op: \"replace\", path: \"/contactDetails/phoneNumbers/0/number\", value: \"123\" },\n//   { op: \"add\", path: \"/contactDetails/phoneNumbers/1\", value: {number:\"456\"}}\n// ];\n```\n\n#### `jsonpatch.unobserve(document, observer)`\n```typescript\njsonpatch.unobserve(document: any, observer: Observer): void\n\ntype JsonableObj = { [key:string]: Jsonable };\ntype JsonableArr = Jsonable[];\ntype Jsonable = JsonableArr | JsonableObj | string | number | boolean | null;\n```\n\nDestroys the observer set up on `document`.\n\nAny remaining changes are delivered synchronously (as in `jsonpatch.generate`). Note: this is different that ES6/7 `Object.unobserve`, which delivers remaining changes asynchronously.\n\n#### `jsonpatch.compare(document1, document2, invertible)`\n\n```typescript\njsonpatch.compare(document1: Jsonable, document2: Jsonable, invertible = false): Operation[]\n\ntype JsonableObj = { [key:string]: Jsonable };\ntype JsonableArr = Jsonable[];\ntype Jsonable = JsonableArr | JsonableObj | string | number | boolean | null;\n```\n\nCompares 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`.\n\nIf there are no differences, returns an empty array (length 0).\n\nExample:\n\n```js\nvar documentA = {user: {firstName: \"Albert\", lastName: \"Einstein\"}};\nvar documentB = {user: {firstName: \"Albert\", lastName: \"Collins\"}};\nvar diff = jsonpatch.compare(documentA, documentB);\n//diff == [{op: \"replace\", path: \"/user/lastName\", value: \"Collins\"}]\n```\n\nExample of comparing two object trees with test operations for values in the first object:\n\n```js\nvar documentA = {user: {firstName: \"Albert\", lastName: \"Einstein\"}};\nvar documentB = {user: {firstName: \"Albert\", lastName: \"Collins\"}};\nvar diff = jsonpatch.compare(documentA, documentB, true);\n//diff == [\n//   {op: \"test\", path: \"/user/lastName\", value: \"Einstein\"},\n//   {op: \"replace\", path: \"/user/lastName\", value: \"Collins\"}\n// ];\n```\n\n#### `jsonpatch.validate(patch: Operation[], document?: any, validator?: Function): JsonPatchError`\n\nSee [Validation notes](#validation-notes)\n\nValidates a sequence of operations. If `document` parameter is provided, the sequence is additionally validated against the object tree.\n\nIf there are no errors, returns undefined. If there is an errors, returns a JsonPatchError object with the following properties:\n\n- `name` String - short error code\n- `message` String - long human readable error message\n- `index` Number - index of the operation in the sequence\n- `operation` Object - reference to the operation\n- `tree` Object - reference to the tree\n\nPossible errors:\n\nError name                    | Error message\n------------------------------|------------\nSEQUENCE_NOT_AN_ARRAY         | Patch sequence must be an array\nOPERATION_NOT_AN_OBJECT       | Operation is not an object\nOPERATION_OP_INVALID          | Operation `op` property is not one of operations defined in RFC-6902\nOPERATION_PATH_INVALID        | Operation `path` property is not a valid string\nOPERATION_FROM_REQUIRED       | Operation `from` property is not present (applicable in `move` and `copy` operations)\nOPERATION_VALUE_REQUIRED      | Operation `value` property is not present, or `undefined` (applicable in `add`, `replace` and `test` operations)\nOPERATION_VALUE_CANNOT_CONTAIN_UNDEFINED  | Operation `value` property object has at least one `undefined` value (applicable in `add`, `replace` and `test` operations)\nOPERATION_PATH_CANNOT_ADD     | Cannot perform an `add` operation at the desired path\nOPERATION_PATH_UNRESOLVABLE   | Cannot perform the operation at a path that does not exist\nOPERATION_FROM_UNRESOLVABLE   | Cannot perform the operation from a path that does not exist\nOPERATION_PATH_ILLEGAL_ARRAY_INDEX | Expected an unsigned base-10 integer value, making the new referenced value the array element with the zero-based index\nOPERATION_VALUE_OUT_OF_BOUNDS | The specified index MUST NOT be greater than the number of elements in the array\nTEST_OPERATION_FAILED | When operation is `test` and the test fails, applies to `applyReducer`.\n\nExample:\n\n```js\nvar obj = {user: {firstName: \"Albert\"}};\nvar patches = [{op: \"replace\", path: \"/user/firstName\", value: \"Albert\"}, {op: \"replace\", path: \"/user/lastName\", value: \"Einstein\"}];\nvar errors = jsonpatch.validate(patches, obj);\nif (errors.length == 0) {\n //there are no errors!\n}\nelse {\n  for (var i=0; i \u003c errors.length; i++) {\n    if (!errors[i]) {\n      console.log(\"Valid patch at index\", i, patches[i]);\n    }\n    else {\n      console.error(\"Invalid patch at index\", i, errors[i], patches[i]);\n    }\n  }\n}\n```\n\n## `OperationResult` Type\n\nFunctions `applyPatch` and `applyOperation` both return `OperationResult` object. This object is:\n\n```ts\n{newDocument: any, test?: boolean, removed?: any}\n```\n\nWhere:\n\n- `newDocument`: the new state of the document after the patch/operation is applied.\n- `test`: if the operation was a `test` operation. This will be its result.\n- `removed`: contains the removed, moved, or replaced values from the document after a `remove`, `move` or `replace` operation.\n\n\n## Validation Notes\n\nFunctions `applyPatch`, `applyOperation`, and `validate` accept a `validate`/ `validator` parameter:\n\n- If the `validateOperation` parameter is set to `false`, validation will not occur.\n- If set to `true`, the patch is extensively validated before applying using jsonpatch's default validation.\n- If set to a `function` callback, the patch is validated using that function.\n\nIf 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.\n\n- `operation` The operation it self.\n- `index` `operation`'s index in the patch array (if application).\n- `tree` The object that is supposed to be patched.\n- `existingPath` the path `operation` points to.\n\n## Overwriting and `move` Operation\n\nWhen the target of the move operation already exists, it is cached, deep cloned and returned as `removed` in `OperationResult`.\n\n## `undefined`s (JS to JSON projection)\n\nAs `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`.\n\nWhenever 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:\n\n\u003e 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).\n\nSee the [ECMAScript spec](http://www.ecma-international.org/ecma-262/6.0/index.html#sec-json.stringify) for details.\n\n## Specs/tests\n\n - [Run in browser](http://starcounter-jack.github.io/JSON-Patch/test/)\n\n## [Contributing](CONTRIBUTING.md)\n\n## Changelog\n\nTo see the list of recent changes, see [Releases](https://github.com/Starcounter-Jack/JSON-Patch/releases).\n\n## Footprint\n4 KB minified and gzipped (12 KB minified)\n\n## Performance\n\n##### [`add` benchmark](https://run.perf.zone/view/JSON-Patch-Add-Operation-1535541298893)\n\n![image](https://user-images.githubusercontent.com/17054134/44784357-aa422480-ab8d-11e8-8a7e-037e692dd842.png)\n\n##### [`replace` benchmark](https://run.perf.zone/view/JSON-Patch-Replace-Operation-1535540952263)\n\n![image](https://user-images.githubusercontent.com/17054134/44784275-5fc0a800-ab8d-11e8-8a90-e87b8d5409d0.png)\n\nTested on 29.08.2018. Compared libraries:\n\n- [Starcounter-Jack/JSON-Patch](https://www.npmjs.com/package/fast-json-patch) 2.0.6\n- [bruth/jsonpatch-js](https://www.npmjs.com/package/json-patch) 0.7.0\n- [dharmafly/jsonpatch.js](https://www.npmjs.com/package/jsonpatch) 3.0.1\n- [jiff](https://www.npmjs.com/package/jiff) 0.7.3\n- [RFC6902](https://www.npmjs.com/package/rfc6902) 2.4.0\n\nWe 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.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FStarcounter-Jack%2FJSON-Patch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FStarcounter-Jack%2FJSON-Patch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FStarcounter-Jack%2FJSON-Patch/lists"}