{"id":16368615,"url":"https://github.com/simoneb/ja.di","last_synced_at":"2026-02-26T21:30:15.423Z","repository":{"id":15231931,"uuid":"17960673","full_name":"simoneb/ja.di","owner":"simoneb","description":"JavaScript diff library","archived":false,"fork":false,"pushed_at":"2014-03-21T21:55:25.000Z","size":208,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-31T09:04:52.597Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/simoneb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-03-20T22:27:12.000Z","updated_at":"2015-09-01T20:20:06.000Z","dependencies_parsed_at":"2022-09-09T16:30:09.030Z","dependency_job_id":null,"html_url":"https://github.com/simoneb/ja.di","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simoneb%2Fja.di","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simoneb%2Fja.di/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simoneb%2Fja.di/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simoneb%2Fja.di/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/simoneb","download_url":"https://codeload.github.com/simoneb/ja.di/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239869221,"owners_count":19710485,"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-10-11T02:53:18.702Z","updated_at":"2026-02-26T21:30:14.771Z","avatar_url":"https://github.com/simoneb.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"ja.di [![Build Status](https://travis-ci.org/simoneb/ja.di.svg?branch=master)](https://travis-ci.org/simoneb/ja.di)\n====\n\n**ja.di** is a javascript diff library, it can compute the differences between two javascript values.\n\n## Install\n\n```bash\nnpm install ja.di\n``` \n\nor download [ja.di.js](ja.di.js) and include it in a Web page.\n\n```html\n\u003c!-- \n\u003cscript src=\"lodash.js\"\u003e\u003c/script\u003e\n--\u003e\n\u003cscript src=\"ja.di.js\"\u003e\u003c/script\u003e\n```\n\n\u003e **ja.di** depends on [lodash](http://lodash.com/), it should be available either as node module or in the global scope of a Web page.\n\n## Reference\n\nIn a standard Web page the `window` object gets a `jadi` property which can be used globally.\n\nIn a standard node app:\n \n```javascript\nvar jadi = require('ja.di');\n```\n \nIn a [RequireJS](http://requirejs.org/) module:\n \n```javascript\ndefine(['ja.di'], function(jadi) { \n   [...] \n});\n```\n\n## Use\n\nThe `jadi` object contains two functions:\n\n- `diff(left, right, [key])` returns the difference between `left` and `right`, optionally with a `key` object, mandatory when diffing arrays of complex objects\n- `interpret(diff, map)` interprets the results returned by `jadi.diff` and invokes uses `map` to handle the differences\n\n### diff\n\n`diff`-ing two objects returns `undefined` if they have the same value:\n\n```javascript\njadi.diff(1, 1);\n \u003e undefined\n```\n\nOtherwise an *object* is returned, which matches the structure of the input values. \n\nFor **simple values** the result contains the values themselves in its `_left` and `_right` properties:\n\n```javascript\njadi.diff(1, 2);\n \u003e { _left: 1, _right: 2 }\n```\n\nIt works with any simple types:\n\n```javascript\njadi.diff(\"hello\", \"world\")\n \u003e { _left: \"hello\", _right: \"world\" }\n```\n\n\u003e As of now there is no special support for smart string diffing, i.e. similarity checks.\n\n**Arrays** are compared element by element, without taking element position into account:\n\n```javascript\njadi.diff([1,2], [2,1]);\n \u003e undefined\n```\n\nIf the elements differ the result is an array of objects representing the unmatched elements:\n\n```javascript\njadi.diff(['a','b'], ['b','c']);\n \u003e [{ _left: 'a' }, { _right: 'c' }]\n```\n\nIf the elements of the array are complex values a `key` function is required to match object with the same key together, and the result will have an additional `_key` property to identify them:\n\n```javascript\nvar left  = [{a: 1, b: 'hello'}],\n    right = [{a: 1, b: 'world'}];\njadi.diff(left, right, function(el) { return el.a; });\n \u003e [{ _key: 1, b: { _left: 'hello', _right: 'world' }}]\n```\n\nA key can also be an object instead of a function, in this case it identifies the name of the property to be treated as key:\n\n```javascript\nvar left  = [{a: 1, b: 'hello'}],\n    right = [{a: 1, b: 'world'}];\njadi.diff(left, right, { _key: 'a' });\n \u003e [{ _key: 1, b: { _left: 'hello', _right: 'world' }}] // same as before\n```\n\n**Objects** are compared based on their properties' values, the result is an object:\n\n```javascript\njadi.diff({ a: 1 }, { a: 2 });\n \u003e { a: { _left: 1, _right: 2 } }\n```\n\nComparing objects with different properties (rather than different property values) will result in an object with multiple properties:\n\n```javascript\njadi.diff({ a: 1 }, { b: 2 });\n \u003e { a: { _left: 1 }, b: { _right: 2 } }\n```\n\n\u003e For more details refer to the [diff spec](spec/diff.spec.js)\n\n### interpret\n\nInterpreting a diff can be non-trivial, therefore an `interpret` function is supplied which provides a higher level API. It takes a *diff* and a *map*, which is invoked whenever a corresponding mismatch is found. The following examples assume that there is a `dump` function which writes to the console.\n\n```javascript\nvar diff = jadi.diff(1, 2); // { _left: 1, _right: 2 }\njadi.interpret(diff, { _left: dump });\n \u003e 1\n```\n\nA map is an *object* that mimics the structure of a diff and contains callbacks which are invoked with the values contained therein.\n\n```javascript\njadi.interpret(jadi.diff(1, 2), { _left: dump, _right: dump });\n \u003e 1\n \u003e 2\n```\n\nAlthough diffs come with `_left` and `_right` properties there's a shorthand syntax to handle both at the same time, in case you don't care which side the diff comes from:\n\n```javascript\njadi.interpret(jadi.diff(1, 2), dump);\n \u003e 1\n \u003e 2\n```\n\n**Array** diffs are handled similarly, note that in case a callback function is not supplied for a specific part of a diff (i.e. you're not interested in that part) nothing bad happens:\n\n```javascript\nvar diff = jadi.diff([1,2,3], [3,4]); // [{ _left: 1 }, { _left: 2 }, { _right: 4 }]\njadi.interpret(diff, { _left: dump });\n \u003e 1\n \u003e 2\n```\n\n```javascript\nvar diff = jadi.diff([1,2,3], [3,4]);\njadi.interpret(diff, { _right: dump });\n \u003e 4\n```\n\nWith arrays of complex values it gets a little bit trickier, what is the difference between `[{ a: 'the key', b: 2 }]` and `[{ a: 'the key', b: 3 }]`? We need a key to decide which elements should be compared to each other, in this case we choose property `a` as the key:\n\n```javascript\nvar the_diff = jadi.diff([{ a: 'the_key', b: 2 }], [{ a: 'the_key', b: 3 }], { _key: 'a' });\n \u003e the_diff = [{ b: { _left: 2, _right: 3 }, _key: 'the_key' }]\n```\n\nTo interpret such a diff with a `_key` we need a map with a key too. The callbacks in the map will receive one additional first argument, they key of the compared objects:\n\n```javascript\nvar map = { _key: { b: { _left: dump, _right: dump } } };\njadi.interpret(the_diff, map);\n \u003e the_key 2 // left callback\n \u003e the_key 3 // right callback\n```\n\nThe shorthand syntax still works:\n\n```javascript\nvar map = { _key: { b: dump } };\njadi.interpret(the_diff, map);\n \u003e the key 2 3\n```\n\n**Object** diffs offer an additional dotted notation to invoke composite callbacks when multiple properties change. All the values of the changed properties are passed to the callback:\n\n```javascript\nvar map = { 'a.b': dump };\njadi.interpret(jadi.diff({ a: 1, b: 2 }, { a: 2, b: 3} ), map);\n \u003e        1 2 2 3\n// a left ^ ^ ^ ^ b right\n//  b left -^ ^- a right\n```\n\nComposite handlers can create a hierarchy whereby if multiple properties change the most specific composite handler is called first, and in turn less specific handlers, in any, down to the single property handler.\nThis is achieved by returning a value from composite callbacks. If the return value has a truthy value the property change is considered handled and less specific (or single property) callbacks are not invoked.\nThe default return value of functions, `undefined`, is a falsy value therefore all callbacks, from more specific to less specific, are always called.\n\n\u003e For more details refer to the [interpret spec](spec/interpret.spec.js)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimoneb%2Fja.di","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsimoneb%2Fja.di","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimoneb%2Fja.di/lists"}