{"id":13442319,"url":"https://github.com/lambdaisland/deep-diff2","last_synced_at":"2025-12-12T01:33:40.962Z","repository":{"id":41161471,"uuid":"155414751","full_name":"lambdaisland/deep-diff2","owner":"lambdaisland","description":"Deep diff Clojure data structures and pretty print the result","archived":false,"fork":false,"pushed_at":"2025-02-11T14:43:08.000Z","size":544,"stargazers_count":312,"open_issues_count":8,"forks_count":19,"subscribers_count":11,"default_branch":"main","last_synced_at":"2025-06-25T09:38:06.675Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lambdaisland.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"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,"zenodo":null}},"created_at":"2018-10-30T16:00:06.000Z","updated_at":"2025-06-23T18:13:31.000Z","dependencies_parsed_at":"2024-02-16T20:30:34.252Z","dependency_job_id":"13f66ee3-ad1b-495c-ad37-f62f2adfd5d1","html_url":"https://github.com/lambdaisland/deep-diff2","commit_stats":{"total_commits":193,"total_committers":17,"mean_commits":"11.352941176470589","dds":0.4559585492227979,"last_synced_commit":"0c04153e30639e0c7776500f42083d9f6a38cf89"},"previous_names":["lambdaisland/deep-diff"],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/lambdaisland/deep-diff2","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lambdaisland%2Fdeep-diff2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lambdaisland%2Fdeep-diff2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lambdaisland%2Fdeep-diff2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lambdaisland%2Fdeep-diff2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lambdaisland","download_url":"https://codeload.github.com/lambdaisland/deep-diff2/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lambdaisland%2Fdeep-diff2/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261902221,"owners_count":23227775,"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-07-31T03:01:44.286Z","updated_at":"2025-12-12T01:33:35.885Z","avatar_url":"https://github.com/lambdaisland.png","language":"Clojure","funding_links":["https://opencollective.com/lambda-island","http://opencollective.com/lambda-island"],"categories":["Clojure"],"sub_categories":[],"readme":"# lambdaisland/deep-diff2\n\n\u003c!-- badges --\u003e\n[![CircleCI](https://circleci.com/gh/lambdaisland/deep-diff2.svg?style=svg)](https://circleci.com/gh/lambdaisland/deep-diff2) [![cljdoc badge](https://cljdoc.org/badge/lambdaisland/deep-diff2)](https://cljdoc.org/d/lambdaisland/deep-diff2) [![Clojars Project](https://img.shields.io/clojars/v/lambdaisland/deep-diff2.svg)](https://clojars.org/lambdaisland/deep-diff2)\n\u003c!-- /badges --\u003e\n\nRecursively compare Clojure or ClojureScript data structures, and produce a colorized diff of the result.\n\n![screenshot showing REPL example](screenshot.png)\n\nDeep-diff2 is foremost intended for creating visual diffs for human consumption,\nif you want to programatically diff/patch Clojure data structures then\n[Editscript](https://github.com/juji-io/editscript) may be a better fit, see\n[this write-up by Huahai Yang](https://juji.io/blog/comparing-clojure-diff-libraries/).\n\n\u003c!-- opencollective --\u003e\n## Lambda Island Open Source\n\nThank you! deep-diff2 is made possible thanks to our generous backers. [Become a\nbacker on OpenCollective](https://opencollective.com/lambda-island) so that we\ncan continue to make deep-diff2 better.\n\n\u003ca href=\"https://opencollective.com/lambda-island\"\u003e\n\u003cimg src=\"https://opencollective.com/lambda-island/organizations.svg?avatarHeight=46\u0026width=800\u0026button=false\"\u003e\n\u003cimg src=\"https://opencollective.com/lambda-island/individuals.svg?avatarHeight=46\u0026width=800\u0026button=false\"\u003e\n\u003c/a\u003e\n\u003cimg align=\"left\" src=\"https://github.com/lambdaisland/open-source/raw/master/artwork/lighthouse_readme.png\"\u003e\n\n\u0026nbsp;\n\ndeep-diff2 is part of a growing collection of quality Clojure libraries created and maintained\nby the fine folks at [Gaiwan](https://gaiwan.co).\n\nPay it forward by [becoming a backer on our OpenCollective](http://opencollective.com/lambda-island),\nso that we continue to enjoy a thriving Clojure ecosystem.\n\nYou can find an overview of all our different projects at [lambdaisland/open-source](https://github.com/lambdaisland/open-source).\n\n\u0026nbsp;\n\n\u0026nbsp;\n\u003c!-- /opencollective --\u003e\n\n## Installation\n\ndeps.edn\n\n```\nlambdaisland/deep-diff2 {:mvn/version \"2.12.219\"}\n```\n\nproject.clj\n\n```\n[lambdaisland/deep-diff2 \"2.12.219\"]\n```\n\n## Use\n\n- [API docs](https://cljdoc.org/d/lambdaisland/deep-diff2/CURRENT)\n\n``` clojure\n(require '[lambdaisland.deep-diff2 :as ddiff])\n\n(ddiff/pretty-print (ddiff/diff {:a 1 :b 2} {:a 1 :c 3}))\n```\n\n### Diffing\n\n`lambdaisland.deep-diff2/diff` takes two arguments and returns a \"diff\", a data\nstructure that contains markers for insertions, deletions, or mismatches. These\nare records with `-` and `+` fields.\n\n``` clojure\n(ddiff/diff {:a 1 :b 2} {:a 1 :b 3})\n{:a 1, :b #lambdaisland.deep_diff.diff.Mismatch{:- 2, :+ 3}}\n```\n\n### Printing\n\nYou can pass this diff to `lambdaisland.deep-diff2/pretty-print`. This function\nuses [Puget](https://github.com/greglook/puget) and\n[Fipp](https://github.com/brandonbloom/fipp) to format the diff and print the\nresult to standard out.\n\nFor fine grained control you can create a custom Puget printer, and supply it to\n`pretty-print`.\n\n``` clojure\n(def narrow-printer (ddiff/printer {:width 10}))\n\n(ddiff/pretty-print (ddiff/diff {:a 1 :b 2} {:a 1 :b 3}) narrow-printer)\n```\n\nFor more advanced uses like incorporating diffs into your own Fipp documents, see `lambdaisland.deep-diff2.printer/format-doc`, `lambdaisland.deep-diff2.printer/print-doc`.\n\n### Minimizing\n\nIf you are only interested in the changes, and not in any values that haven't\nchanged, then you can use `ddiff/minimize` to return a more compact diff.\n\nThis is especially useful for potentially large nested data structures, for\nexample a JSON response coming from a web service.\n\n```clj\n(-\u003e (ddiff/diff {:a \"apple\" :b \"pear\"} {:a \"apple\" :b \"banana\"})\n    ddiff/minimize\n    ddiff/pretty-print)\n;; {:b -\"pear\" +\"banana\"}\n```\n\n### Print handlers for custom or built-in types\n\nIn recent versions deep-diff2 initializes its internal copy of Puget with\n`{:print-fallback :print}`, meaning it will fall back to using the system\nprinter, which you can extend by extending the `print-method` multimethod.\n\nThis also means that we automatically pick up additional handlers installed by\nlibraries, such as [time-literals](https://github.com/henryw374/time-literals).\n\nYou can also register print handlers for deep-diff2 specifically by using\n`lambdaisland.deep-diff2.printer-impl/register-print-handler!`, or by passing an\n`:extra-handlers` map to `printer`.\n\nIf you are dealing with printing of custom types you might find that there are\nmultiple print implementations you need to keep up-to-date, see\n[lambdaisland.data-printers](https://github.com/lambdaisland/data-printers) for\na high-level API that can work with all the commonly used print implementations.\n\n#### Example of a custom type\n\nSee [repl_sessions/custom_type.clj](repl_sessions/custom_type.clj) for the full\ncode and results.\n\n```clj\n(deftype Degrees [amount unit]\n  Object\n  (equals [this that]\n    (and (instance? Degrees that)\n         (= amount (.-amount that))\n         (= unit (.-unit that)))))\n\n;; Using system handler fallback\n(defmethod print-method Degrees [degrees out]\n  (.write out (str (.-amount degrees) \"°\" (.-unit degrees))))\n  \n;; OR Using a Puget-specific handler\n(lambdaisland.deep-diff2.printer-impl/register-print-handler!\n `Degrees\n (fn [printer value]\n   [:span\n    (lambdaisland.deep-diff2.puget.color/document printer :number (str (.-amount value)))\n    (lambdaisland.deep-diff2.puget.color/document printer :tag \"°\")\n    (lambdaisland.deep-diff2.puget.color/document printer :keyword (str (.-unit value)))]))\n```\n\n### Set up a custom print handler with different colors by utilizing Puget library\n\nSometimes, we need to tune the colors to:\n\n- Ensure adequate contrast on a different background.\n- Ensure readability by people who are colorblind.\n- Match your editor or main diff tool's color scheme.\n\n#### Config of Puget\n\nFortunately, the Puget library included in deep-diff2 already allows customization through a custom printer. \n\nIn the Puget libray, 8-bit scheme is expressed via `[:fg-256 5 n]` where n is between 0 and 255. We can combine foreground and background, for example, like so: `[:fg-256 5 226 :bg-256 5 56]`.\n\n24-bit scheme is expressed via `[:fg-256 2 r g b]` where r g b are each between 0 and 255. Foreground and background can be combined, for example: `[:fg-256 2 205 236 255 :bg-256 2 110 22 188]`.\n\n#### An example of customizing color\n\nFor example, if we change the `:lambdaisland.deep-diff2.printer-impl/deletion` from `[:red]` to  `[:bg-256 5 13]`, the color code it outputs will change from `\\u001b[31m` to `\\u001b[48;5;13m`\n\n```\nuser=\u003e (use 'lambdaisland.deep-diff2)\nnil\nuser=\u003e (def color-printer (printer {:color-scheme {:lambdaisland.deep-diff2.printer-impl/deletion [:bg-256 5 13]}}))\n#'user/color-printer\nuser=\u003e (pretty-print (diff {:a 1} {:b 2}) color-printer)\n{+:b 2, -:a 1}\n```\n\nThat results in the following highlighting:\n![screenshot showing color customization](color-scheme.png)\n\n### Time, data literal\n\nA common use case is diffing and printing Java date and time objects\n(`java.util.Date`, `java.time.*`, `java.sql.Date|Time|DateTime`).\n\nChances are you already have print handlers (and data readers) set up for these\nvia the [time-literals](https://github.com/henryw374/time-literals) library\n(perhaps indirectly by pulling in [tick](https://github.com/juxt/tick). In that\ncase these should _just work_.\n\n```clj\n(ddiff/diff #inst \"2019-04-09T14:57:46.128-00:00\"\n            #inst \"2019-04-10T14:57:46.128-00:00\")\n```\nor\n```clj\n(import '[java.sql Timestamp])\n(ddiff/diff (Timestamp. 0)\n            (doto (Timestamp. 1000) (.setNanos 101)))\n```\n\nIf you need to diff a rich set of time literal, using\n\n```\n(require '[time-literals.read-write])\n(require '[lambdaisland.deep-diff2 :as ddiff])\n(time-literals.read-write/print-time-literals-clj!)\n(ddiff/pretty-print (ddiff/diff #time/date \"2039-01-01\" #time/date-time \"2018-07-05T08:08:44.026\"))\n```\n\n## Deep-diff 1 vs 2\n\nThe original deep-diff only worked on Clojure, not ClojureScript. In porting the\ncode to CLJC we were forced to make some breaking changes. To not break existing\nconsumers we decided to move both the namespaces and the released artifact to\nnew names, so the old and new deep-diff can exist side by side.\n\nWe also had to fork Puget to make it cljc compatible. This required breaking\nchanges as well, making it unlikely these changes will make it upstream, so\ninstead we vendor our own copy of Puget under `lambdaisland.deep-diff2.puget.*`.\nThis does mean we don't automatically pick up custom Puget print handlers,\nunless they are *also* registered with our own copy of Puget. See above for more\ninfo on that.\n\nWhen starting new projects you should use `lambdaisland/deep-diff2`. However if\nyou have existing code that uses `lambdaisland/deep-diff` and you don't need the\nClojureScript support then it is not necessary to upgrade. The old version still\nworks fine (on Clojure).\n\nYou can upgrade of course, simply by replacing all namespace names from\n`lambdaisland.deep-diff` to `lambdaisland.deep-diff2`. If you are only using the\ntop-level API (`diff`, `printer`, `pretty-print`) and you aren't using custom\nprint handlers, then things should work exactly the same. If you find that\ndeep-diff 2 behaves differently then please file an issue, you may have found a\nregression.\n\nThe old code still lives on the `deep-diff-1` branch, and we do accept bugfix\npatches there, so we may put out bugfix releases of the original deep-diff in\nthe future. When in doubt check the CHANGELOG.\n\n\u003c!-- contributing --\u003e\n## Contributing\n\nWe warmly welcome patches to deep-diff2. Please keep in mind the following:\n\n- adhere to the [LambdaIsland Clojure Style Guide](https://nextjournal.com/lambdaisland/clojure-style-guide)\n- write patches that solve a problem \n- start by stating the problem, then supply a minimal solution `*`\n- by contributing you agree to license your contributions as EPL 1.0\n- don't break the contract with downstream consumers `**`\n- don't break the tests\n\nWe would very much appreciate it if you also\n\n- update the CHANGELOG and README\n- add tests for new functionality\n\nWe recommend opening an issue first, before opening a pull request. That way we\ncan make sure we agree what the problem is, and discuss how best to solve it.\nThis is especially true if you add new dependencies, or significantly increase\nthe API surface. In cases like these we need to decide if these changes are in\nline with the project's goals.\n\n`*` This goes for features too, a feature needs to solve a problem. State the problem it solves first, only then move on to solving it.\n\n`**` Projects that have a version that starts with `0.` may still see breaking changes, although we also consider the level of community adoption. The more widespread a project is, the less likely we're willing to introduce breakage. See [LambdaIsland-flavored Versioning](https://github.com/lambdaisland/open-source#lambdaisland-flavored-versioning) for more info.\n\u003c!-- /contributing --\u003e\n\n## Credits\n\nThis library builds upon\n[clj-diff](https://github.com/brentonashworth/clj-diff), which implements a\ndiffing algorithm for sequences, and\n[clj-arrangements](https://github.com/greglook/clj-arrangement), which makes\ndisparate types sortable.\n\nPretty printing and colorization are handled by\n[Puget](https://github.com/greglook/puget) and\n[Fipp](https://github.com/brandonbloom/fipp).\n\nThis library was originally developed as part of the\n[Kaocha](https://github.com/lambdaisland/kaocha) test runner.\n\nAnother library that implements a form of data structure diffing is [editscript](https://github.com/juji-io/editscript).\n\n\u003c!-- license --\u003e\n## License\n\nCopyright \u0026copy; 2018-2024 Arne Brasseur and contributors\n\nAvailable under the terms of the Eclipse Public License 1.0, see LICENSE.txt\n\u003c!-- /license --\u003e","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flambdaisland%2Fdeep-diff2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flambdaisland%2Fdeep-diff2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flambdaisland%2Fdeep-diff2/lists"}