Skip to content

Instantly share code, notes, and snippets.

@Checksum
Last active February 11, 2025 13:59

Revisions

  1. Checksum revised this gist Mar 10, 2020. 1 changed file with 27 additions and 14 deletions.
    41 changes: 27 additions & 14 deletions diff-patch.jq
    Original file line number Diff line number Diff line change
    @@ -1,13 +1,29 @@
    # Tested only with top level objects
    # JSON diff and patch for jq (https://stedolan.github.io/jq/)
    # Author: Srinath Sankar
    #
    # Usage:
    # diff: jq -sS 'include "diff-patch"; diff' a.json b.json > patch.json
    # patch: jq -sS 'include "diff-patch"; patch' a.json patch.json
    #
    # Caveats: tested only with top level objects using jq 1.6

    def flatten_obj:
    . as $obj
    | reduce ($obj | paths(scalars)) as $path
    ( {};
    walk(if type == "array" then sort else . end)
    | . as $obj
    | reduce ($obj | paths(scalars)) as $path
    ( {};
    .[$path | join("~>")] = ($obj | getpath($path))
    );

    # jq -sS 'include "diff-patch"; diff' a.json b.json > patch.json

    def zip_obj:
    . as $obj
    | reduce (. | keys[]) as $key
    ( {};
    . | setpath($key | split("~>") | map(. as $k | try tonumber catch $k); $obj[$key])
    );


    def diff:
    (.[0] | flatten_obj) as $a
    | (.[1] | flatten_obj) as $b
    @@ -25,7 +41,6 @@ def diff:
    $diff
    end
    )
    | . as $diff
    # Deleted
    | reduce $removed[] as $k
    ( .;
    @@ -35,15 +50,13 @@ def diff:
    | reduce $added[] as $k
    ( .;
    .[$k] |= $b[$k]
    );
    )
    | zip_obj;


    # jq -sS 'include "diff-patch"; patch' a.json patch.json
    def patch:
    (.[0] | flatten_obj) as $input
    | (.[1] | flatten_obj) as $patch
    | ($input * $patch) as $patched
    | ($patched | with_entries(select(.value != "~>-"))) as $patched
    | reduce ($patched | keys[]) as $key
    ( {};
    . | setpath($key | split("~>") | map(. as $k | try tonumber catch $k); $patched[$key])
    );
    | ($input * $patch)
    | with_entries(select(.value != "~>-"))
    | zip_obj;
  2. Checksum created this gist Mar 10, 2020.
    49 changes: 49 additions & 0 deletions diff-patch.jq
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,49 @@
    # Tested only with top level objects

    def flatten_obj:
    . as $obj
    | reduce ($obj | paths(scalars)) as $path
    ( {};
    .[$path | join("~>")] = ($obj | getpath($path))
    );

    # jq -sS 'include "diff-patch"; diff' a.json b.json > patch.json
    def diff:
    (.[0] | flatten_obj) as $a
    | (.[1] | flatten_obj) as $b
    | ($a | keys) as $aKeys
    | ($b | keys) as $bKeys
    | ($aKeys - $bKeys) as $removed
    | ($bKeys - $aKeys) as $added
    # Modified
    | reduce ($a | keys[]) as $key
    ( {};
    . as $diff
    | if $a[$key] != $b[$key] then
    $diff[$key] |= $b[$key]
    else
    $diff
    end
    )
    | . as $diff
    # Deleted
    | reduce $removed[] as $k
    ( .;
    .[$k] |= "~>-"
    )
    # Added
    | reduce $added[] as $k
    ( .;
    .[$k] |= $b[$k]
    );

    # jq -sS 'include "diff-patch"; patch' a.json patch.json
    def patch:
    (.[0] | flatten_obj) as $input
    | (.[1] | flatten_obj) as $patch
    | ($input * $patch) as $patched
    | ($patched | with_entries(select(.value != "~>-"))) as $patched
    | reduce ($patched | keys[]) as $key
    ( {};
    . | setpath($key | split("~>") | map(. as $k | try tonumber catch $k); $patched[$key])
    );