{"id":13457860,"url":"https://github.com/benjamine/jsondiffpatch","last_synced_at":"2025-05-13T18:04:57.700Z","repository":{"id":37336050,"uuid":"2624312","full_name":"benjamine/jsondiffpatch","owner":"benjamine","description":"Diff \u0026 patch JavaScript objects","archived":false,"fork":false,"pushed_at":"2025-03-31T23:25:12.000Z","size":3832,"stargazers_count":4993,"open_issues_count":40,"forks_count":477,"subscribers_count":85,"default_branch":"master","last_synced_at":"2025-05-05T23:12:47.641Z","etag":null,"topics":["delta","diff","diffing","json","jsondiffpatch","patch","text-diff"],"latest_commit_sha":null,"homepage":"https://jsondiffpatch.com","language":"TypeScript","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/benjamine.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"MIT-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,"zenodo":null}},"created_at":"2011-10-22T01:59:30.000Z","updated_at":"2025-05-05T23:12:01.000Z","dependencies_parsed_at":"2024-04-24T00:30:03.296Z","dependency_job_id":"dbda03b0-d02f-411c-bc99-a8f7aad4d7dc","html_url":"https://github.com/benjamine/jsondiffpatch","commit_stats":null,"previous_names":[],"tags_count":65,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benjamine%2Fjsondiffpatch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benjamine%2Fjsondiffpatch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benjamine%2Fjsondiffpatch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benjamine%2Fjsondiffpatch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/benjamine","download_url":"https://codeload.github.com/benjamine/jsondiffpatch/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252590628,"owners_count":21772940,"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":["delta","diff","diffing","json","jsondiffpatch","patch","text-diff"],"created_at":"2024-07-31T09:00:38.464Z","updated_at":"2025-05-05T23:12:49.363Z","avatar_url":"https://github.com/benjamine.png","language":"TypeScript","readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"demos/html-demo/logo.svg\" width=\"48px\" align=\"center\" alt=\"jsondiffpatch logo\" /\u003e\n  \u003ch1 align=\"center\"\u003ejsondiffpatch\u003c/h1\u003e\n  \u003cp align=\"center\"\u003e\n    \u003ca href=\"https://jsondiffpatch.com\"\u003ejsondiffpatch.com\u003c/a\u003e\n    \u003cbr/\u003e\n    Diff \u0026 patch JavaScript objects\n  \u003c/p\u003e\n\u003c/p\u003e\n\n\u003c!--- badges --\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/benjamine/jsondiffpatch/actions?query=branch%3Amaster\"\u003e\u003cimg src=\"https://github.com/benjamine/jsondiffpatch/actions/workflows/CI.yml/badge.svg?event=push\u0026branch=master\" alt=\"JsonDiffPatch CI status\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://twitter.com/beneidel\" rel=\"nofollow\"\u003e\u003cimg src=\"https://img.shields.io/badge/created%20by-@beneidel-BACABA.svg\" alt=\"Created by Benjamin Eidelman\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://opensource.org/licenses/MIT\" rel=\"nofollow\"\u003e\u003cimg src=\"https://img.shields.io/github/license/benjamine/jsondiffpatch\" alt=\"License\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/jsondiffpatch\" rel=\"nofollow\"\u003e\u003cimg src=\"https://img.shields.io/npm/dw/jsondiffpatch.svg\" alt=\"npm\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/benjamine/jsondiffpatch\" rel=\"nofollow\"\u003e\u003cimg src=\"https://img.shields.io/github/stars/benjamine/jsondiffpatch\" alt=\"stars\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## **[Live Demo](https://jsondiffpatch.com)**\n\n- min+gzipped ~ 16KB\n- browser and server (ESM-only)\n- deep diff, use delta to patch\n- smart array diffing using [LCS](http://en.wikipedia.org/wiki/Longest_common_subsequence_problem), **_IMPORTANT NOTE:_** to match objects inside an array you must provide an `objectHash` function (this is how objects are matched, otherwise a dumb match by position is used). For more details, check [Array diff documentation](docs/arrays.md)\n- (optionally) text diffing of long strings powered by [google-diff-match-patch](http://code.google.com/p/google-diff-match-patch/) (diff at character level)\n- reverse a delta, unpatch (eg. revert object to its original state using a delta)\n- multiple output formats:\n  - pure JSON, low footprint [delta format](docs/deltas.md)\n  - \u003cspan style=\"background-color: #bbffbb; color: black;\"\u003evisual\u003c/span\u003e \u003cspan style=\"background-color: #ffbbbb; color:black; text-decoration: line-through\"\u003ediff\u003c/span\u003e (html), see [demo](https://jsondiffpatch.com)\n  - annotated JSON (html), to help explain the delta format with annotations\n  - JSON Patch ([RFC 6902](https://datatracker.ietf.org/doc/html/rfc6902)), can generate patches, and also apply them\n  - console (colored), try running `./node_modules/.bin/jsondiffpatch left.json right.json`\n  - write your own! check [Formatters documentation](docs/formatters.md)\n- BONUS: `jsondiffpatch.clone(obj)` (deep clone)\n\n## Supported platforms\n\n- Any browser that [supports ES6](https://caniuse.com/es6)\n- Node.js 18, 20+\n\n## Usage\n\non your terminal:\n\n```sh\nnpx jsondiffpatch --help\n```\n\n![console_demo!](docs/demo/consoledemo.png)\n\nor as a library:\n\n```ts\n// sample data\nconst country = {\n  name: 'Argentina',\n  capital: 'Buenos Aires',\n  independence: new Date(1816, 6, 9),\n};\n\n// clone country, using dateReviver for Date objects\nconst country2 = JSON.parse(JSON.stringify(country), jsondiffpatch.dateReviver);\n\n// make some changes\ncountry2.name = 'Republica Argentina';\ncountry2.population = 41324992;\ndelete country2.capital;\n\nconst delta = jsondiffpatch.diff(country, country2);\n\nassertSame(delta, {\n  name: ['Argentina', 'Republica Argentina'], // old value, new value\n  population: ['41324992'], // new value\n  capital: ['Buenos Aires', 0, 0], // deleted\n});\n\n// patch original\njsondiffpatch.patch(country, delta);\n\n// reverse diff\nconst reverseDelta = jsondiffpatch.reverse(delta);\n// also country2 can be return to original value with: jsondiffpatch.unpatch(country2, delta);\n\nconst delta2 = jsondiffpatch.diff(country, country2);\nassert(delta2 === undefined);\n// undefined =\u003e no difference\n```\n\nArray diffing:\n\n```ts\n// sample data\nconst country = {\n  name: 'Argentina',\n  cities: [\n    {\n      name: 'Buenos Aires',\n      population: 13028000,\n    },\n    {\n      name: 'Cordoba',\n      population: 1430023,\n    },\n    {\n      name: 'Rosario',\n      population: 1136286,\n    },\n    {\n      name: 'Mendoza',\n      population: 901126,\n    },\n    {\n      name: 'San Miguel de Tucuman',\n      population: 800000,\n    },\n  ],\n};\n\n// clone country\nconst country2 = JSON.parse(JSON.stringify(country));\n\n// delete Cordoba\ncountry.cities.splice(1, 1);\n\n// add La Plata\ncountry.cities.splice(4, 0, {\n  name: 'La Plata',\n});\n\n// modify Rosario, and move it\nconst rosario = country.cities.splice(1, 1)[0];\nrosario.population += 1234;\ncountry.cities.push(rosario);\n\n// create a configured instance, match objects by name\nconst diffpatcher = jsondiffpatch.create({\n  objectHash: function (obj) {\n    return obj.name;\n  },\n});\n\nconst delta = diffpatcher.diff(country, country2);\n\nassertSame(delta, {\n  cities: {\n    _t: 'a', // indicates this node is an array (not an object)\n    1: [\n      // inserted at index 1\n      {\n        name: 'Cordoba',\n        population: 1430023,\n      },\n    ],\n    2: {\n      // population modified at index 2 (Rosario)\n      population: [1137520, 1136286],\n    },\n    _3: [\n      // removed from index 3\n      {\n        name: 'La Plata',\n      },\n      0,\n      0,\n    ],\n    _4: [\n      // move from index 4 to index 2\n      '',\n      2,\n      3,\n    ],\n  },\n});\n```\n\nFor more example cases (nested objects or arrays, long text diffs) check `packages/jsondiffpatch/test/examples/`\n\nIf you want to understand deltas, see [delta format documentation](docs/deltas.md)\n\n## Installing\n\n### NPM\n\nThis works for node, or in browsers if you already do bundling on your app\n\n```sh\nnpm install jsondiffpatch\n```\n\n```js\nimport {* as jsondiffpatch} from 'jsondiffpatch';\nconst jsondiffpatchInstance = jsondiffpatch.create(options);\n```\n\n### browser\n\nIn a browser, you can load a bundle using a tool like [esm.sh](https://esm.sh) or [Skypack](https://www.skypack.dev).\n\n## Options\n\n```ts\nimport * as jsondiffpatch from 'jsondiffpatch';\n\n// Only import if you want text diffs using diff-match-patch\nimport { diff_match_patch } from '@dmsnell/diff-match-patch';\n\nconst jsondiffpatchInstance = jsondiffpatch.create({\n  // used to match objects when diffing arrays, by default only === operator is used\n  objectHash: function (obj) {\n    // this function is used only to when objects are not equal by ref\n    return obj._id || obj.id;\n  },\n  arrays: {\n    // default true, detect items moved inside the array (otherwise they will be registered as remove+add)\n    detectMove: true,\n    // default false, the value of items moved is not included in deltas\n    includeValueOnMove: false,\n  },\n  textDiff: {\n    // If using text diffs, it's required to pass in the diff-match-patch library in through this proprty.\n    // Alternatively, you can import jsondiffpatch using `jsondiffpatch/with-text-diffs` to avoid having to pass in diff-match-patch through the options.\n    diffMatchPatch: diff_match_patch,\n    // default 60, minimum string length (left and right sides) to use text diff algorithm: google-diff-match-patch\n    minLength: 60,\n  },\n  propertyFilter: function (name, context) {\n    /*\n       this optional function can be specified to ignore object properties (eg. volatile data)\n        name: property name, present in either context.left or context.right objects\n        context: the diff context (has context.left and context.right objects)\n      */\n    return name.slice(0, 1) !== '$';\n  },\n  cloneDiffValues: false /* default false. if true, values in the obtained delta will be cloned\n      (using jsondiffpatch.clone by default), to ensure delta keeps no references to left or right objects. this becomes useful if you're diffing and patching the same objects multiple times without serializing deltas.\n      instead of true, a function can be specified here to provide a custom clone(value).\n      */\n  omitRemovedValues: false /* if you don't need to unpatch (reverse deltas),\n      \"old\"/\"left\" values (removed or replaced) are not included in the delta.\n      you can set this to true to get more compact deltas.\n      */,\n});\n```\n\n## Visual Diff\n\n```html\n\u003c!doctype html\u003e\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003clink rel=\"stylesheet\" href=\"./style.css\" type=\"text/css\" /\u003e\n    \u003clink\n      rel=\"stylesheet\"\n      href=\"https://esm.sh/jsondiffpatch@0.6.0/lib/formatters/styles/html.css\"\n      type=\"text/css\"\n    /\u003e\n    \u003clink\n      rel=\"stylesheet\"\n      href=\"https://esm.sh/jsondiffpatch@0.6.0/lib/formatters/styles/annotated.css\"\n      type=\"text/css\"\n    /\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n    \u003cdiv id=\"visual\"\u003e\u003c/div\u003e\n    \u003chr /\u003e\n    \u003cdiv id=\"annotated\"\u003e\u003c/div\u003e\n    \u003cscript type=\"module\"\u003e\n      import * as jsondiffpatch from 'https://esm.sh/jsondiffpatch@0.6.0';\n      import * as annotatedFormatter from 'https://esm.sh/jsondiffpatch@0.6.0/formatters/annotated';\n      import * as htmlFormatter from 'https://esm.sh/jsondiffpatch@0.6.0/formatters/html';\n\n      const left = { a: 3, b: 4 };\n      const right = { a: 5, c: 9 };\n      const delta = jsondiffpatch.diff(left, right);\n\n      // beautiful html diff\n      document.getElementById('visual').innerHTML = htmlFormatter.format(\n        delta,\n        left,\n      );\n\n      // self-explained json\n      document.getElementById('annotated').innerHTML =\n        annotatedFormatter.format(delta, left);\n    \u003c/script\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\nTo see formatters in action check the [Live Demo](https://jsondiffpatch.com).\n\nFor more details check [Formatters documentation](docs/formatters.md)\n\n## Plugins\n\n`diff()`, `patch()` and `reverse()` functions are implemented using Pipes \u0026 Filters pattern, making it extremely customizable by adding or replacing filters on a pipe.\n\nCheck [Plugins documentation](docs/plugins.md) for details.\n\n## Related Projects\n\n- [jsondiffpatch.net (C#)\n  ](https://github.com/wbish/jsondiffpatch.net)\n- [SystemTextJson.JsonDiffPatch\n  (C#)](https://github.com/weichch/system-text-json-jsondiffpatch)\n- [Go JSON Diff (and Patch)\n  ](https://github.com/yudai/gojsondiff)\n- [json-diff-patch (python)](https://github.com/apack1001/json-diff-patch)\n- [jsondiffpatch-react](https://github.com/bluepeter/jsondiffpatch-react), also check docs for [usage in react](/docs/react.md)\n\n## All contributors ✨\n\n\u003ca href=\"https://github.com/benjamine/jsondiffpatch/graphs/contributors\"\u003e\n  \u003cp align=\"center\"\u003e\n    \u003cimg width=\"720\" src=\"https://contrib.rocks/image?repo=benjamine/jsondiffpatch\" alt=\"A table of avatars from the project's contributors\" /\u003e\n  \u003c/p\u003e\n\u003c/a\u003e\n","funding_links":[],"categories":["TypeScript","JavaScript","Repository","Differencing","Document Processing"],"sub_categories":["Object / JSON / JSON Schema"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbenjamine%2Fjsondiffpatch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbenjamine%2Fjsondiffpatch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbenjamine%2Fjsondiffpatch/lists"}