Skip to content

josephburnett/jd-website

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Go Report Card

jd aims to be the Unix diff and patch for structured data.

Examples

Diff

Output:

<textarea id="diff-output" rows="3"></textarea>

JSON diff and patch

jd is a commandline utility and Go library for diffing and patching JSON and YAML values. It supports a native jd format (similar to unified format) as well as JSON Merge Patch (RFC 7386) and a subset of JSON Patch (RFC 6902). Try it out at play.jd-tool.io

jd logo

Installation

To get the jd commandline utility:

  • run brew install jd, or
  • run go install github.com/josephburnett/jd@latest, or
  • visit https://github.com/josephburnett/jd/releases/latest and download the pre-built binary for your architecture/os, or
  • run in a Docker image jd(){ docker run --rm -i -v $PWD:$PWD -w $PWD josephburnett/jd "$@"; }.

To use the jd web UI:

Command line usage

Usage: jd [OPTION]... FILE1 [FILE2]
Diff and patch JSON files.

Prints the diff of FILE1 and FILE2 to STDOUT.
When FILE2 is omitted the second input is read from STDIN.
When patching (-p) FILE1 is a diff.

Options:
  -color     Print color diff.
  -p         Apply patch FILE1 to FILE2 or STDIN.
  -o=FILE3   Write to FILE3 instead of STDOUT.
  -set       Treat arrays as sets.
  -mset      Treat arrays as multisets (bags).
  -setkeys   Keys to identify set objects
  -yaml      Read and write YAML instead of JSON.
  -port=N    Serve web UI on port N
  -f=FORMAT  Produce diff in FORMAT "jd" (default), "patch" (RFC 6902) or
             "merge" (RFC 7386)
  -t=FORMATS Translate FILE1 between FORMATS. Supported formats are "jd",
             "patch" (RFC 6902), "merge" (RFC 7386), "json" and "yaml".
             FORMATS are provided as a pair separated by "2". E.g.
             "yaml2json" or "jd2patch".

Examples:
  jd a.json b.json
  cat b.json | jd a.json
  jd -o patch a.json b.json; jd patch a.json
  jd -set a.json b.json
  jd -f patch a.json b.json
  jd -f merge a.json b.json

Library usage

Note: import only release commits (v1.Y.Z) because master can be unstable.

import (
	"fmt"
	jd "github.com/josephburnett/jd/lib"
)

func ExampleJsonNode_Diff() {
	a, _ := jd.ReadJsonString(`{"foo":"bar"}`)
	b, _ := jd.ReadJsonString(`{"foo":"baz"}`)
	fmt.Print(a.Diff(b).Render())
	// Output:
	// @ ["foo"]
	// - "bar"
	// + "baz"
}

func ExampleJsonNode_Patch() {
	a, _ := jd.ReadJsonString(`["foo"]`)
	diff, _ := jd.ReadDiffString(`` +
		`@ [1]` + "\n" +
		`+ "bar"` + "\n")
	b, _ := a.Patch(diff)
	fmt.Print(b.Json())
	// Output:
	// ["foo","bar"]
}

Diff language

Railroad diagram of EBNF

  • A diff is zero or more sections
  • Sections start with a @ header and the path to a node
  • A path is a JSON list of zero or more elements accessing collections
  • A JSON number element (e.g. 0) accesses an array
  • A JSON string element (e.g. "foo") accesses an object
  • An empty JSON object element ({}) accesses an array as a set or multiset
  • After the path is one or more removals or additions, removals first
  • Removals start with - and then the JSON value to be removed
  • Additions start with + and then the JSON value to added

EBNF

Diff ::= ( '@' '[' ( 'JSON String' | 'JSON Number' | 'Empty JSON Object' )* ']' '\n' ( ( '-' 'JSON Value' '\n' )+ | '+' 'JSON Value' '\n' ) ( '+' 'JSON Value' '\n' )* )*

Examples

@ ["a"]
- 1
+ 2
@ [2]
+ {"foo":"bar"}
@ ["Movies",67,"Title"]
- "Dr. Strangelove"
+ "Dr. Evil Love"
@ ["Movies",67,"Actors","Dr. Strangelove"]
- "Peter Sellers"
+ "Mike Myers"
@ ["Movies",102]
+ {"Title":"Austin Powers","Actors":{"Austin Powers":"Mike Myers"}}
@ ["Movies",67,"Tags",{}]
- "Romance"
+ "Action"
+ "Comedy"

Cookbook

Use git diff to produce a structural diff:

git difftool -yx jd @ -- foo.json
@ ["foo"]
- "bar"
+ "baz"

See what changes in a Kubernetes Deployment:

kubectl get deployment example -oyaml > a.yaml
kubectl edit deployment example
# change cpu resource from 100m to 200m
kubectl get deployment example -oyaml | jd -yaml a.yaml

output:

@ ["metadata","annotations","deployment.kubernetes.io/revision"]
- "2"
+ "3"
@ ["metadata","generation"]
- 2
+ 3
@ ["metadata","resourceVersion"]
- "4661"
+ "5179"
@ ["spec","template","spec","containers",0,"resources","requests","cpu"]
- "100m"
+ "200m"
@ ["status","conditions",1,"lastUpdateTime"]
- "2021-12-23T09:40:39Z"
+ "2021-12-23T09:41:49Z"
@ ["status","conditions",1,"message"]
- "ReplicaSet \"nginx-deployment-787d795676\" has successfully progressed."
+ "ReplicaSet \"nginx-deployment-795c7f5bb\" has successfully progressed."
@ ["status","observedGeneration"]
- 2
+ 3

apply these change to another deployment:

# edit file "patch" to contain only the hunk updating cpu request
kubectl patch deployment example2 --type json --patch "$(jd -t jd2patch ~/patch)"

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors