caching/vendor/github.com/evanphx/json-patch
Knative Automation 506882f82a
upgrade to latest dependencies (#828)
bumping google.golang.org/api b52e40b...ee5c9cc:
  > ee5c9cc chore(main): release 0.159.0 (# 2378)
  > 55b0516 fix(transport): relax universe checks (# 2376)
  > a8d9414 feat(all): auto-regenerate discovery clients (# 2377)
  > 68b1bc1 chore(main): release 0.158.0 (# 2360)
  > df17254 fix(transport/grpc): add universe domain verification (# 2375)
  > b21a1fa fix(internal): support internaloption.WithDefaultUniverseDomain (# 2373)
  > ddb3a12 chore(google-api-go-generator): replace literal with const (# 2363)
  > d266978 feat(all): auto-regenerate discovery clients (# 2374)
  > 73fc7fd fix(transport): not enable s2a when there is endpoint override (# 2368)
  > 2d69d97 feat(all): auto-regenerate discovery clients (# 2372)
  > 45c097f feat(all): auto-regenerate discovery clients (# 2369)
  > addc18c chore(all): update module github.com/google/go-github/v52 to v58 (# 2351)
  > a4e39d8 chore(all): update all to v0.47.0 (# 2367)
  > e0db6a5 feat(all): auto-regenerate discovery clients (# 2366)
  > f40db7f feat(all): auto-regenerate discovery clients (# 2365)
  > 69626e3 feat(transport): add universe domain support (# 2355)
  > 6c3b622 feat(all): auto-regenerate discovery clients (# 2361)
  > 6ef1144 feat(impersonate): add universe domain support (# 2296)
  > 6e77ef2 chore(main): release 0.157.0 (# 2346)
  > 72a8ffd feat(all): auto-regenerate discovery clients (# 2358)
  > 74a1558 docs(option): update WithDefaultEndpointTemplate docs (# 2356)
  > 135da01 chore(all): update all to a9fa171 (# 2350)
  > 0d002f9 feat(all): auto-regenerate discovery clients (# 2354)
  > da330c2 feat(all): auto-regenerate discovery clients (# 2353)
  > 5bf46ee feat(all): auto-regenerate discovery clients (# 2352)
  > 3bf8f4f feat(all): auto-regenerate discovery clients (# 2349)
  > 763c331 feat(all): auto-regenerate discovery clients (# 2348)
  > c3e43a1 feat(all): auto-regenerate discovery clients (# 2345)
  > d016573 chore(main): release 0.156.0 (# 2333)
  > 05de776 feat(all): auto-regenerate discovery clients (# 2344)
  > 811e925 feat(all): auto-regenerate discovery clients (# 2343)
  > 9e45101 feat(google-api-go-generator): add universe domain support (# 2335)
  > 3f90b98 feat(all): auto-regenerate discovery clients (# 2341)
  > 9745014 test: fix overflow (# 2342)
  > 3f8b548 chore(all): update all (# 2338)
  > c8905be chore(deps): bump github.com/cloudflare/circl from 1.3.3 to 1.3.7 in /internal/kokoro/discogen (# 2340)
  > d008b6e feat(all): auto-regenerate discovery clients (# 2339)
  > ceefb9b feat(all): auto-regenerate discovery clients (# 2337)
  > bd4dad1 feat(all): auto-regenerate discovery clients (# 2336)
  > 014a8e0 feat(all): auto-regenerate discovery clients (# 2332)
bumping knative.dev/hack f3f03ac...ab9b690:
  > ab9b690 Don't hardcode serving as the repo when setting highest semver (# 361)
  > 45dcf10 Update community files (# 360)
  > 40f0ac2 Update community files (# 359)
bumping github.com/google/uuid 4d47f8e...0f11ee6:
  > 0f11ee6 chore(master): release 1.6.0 (# 151)
  > 16939da chore(tests):  add strict monotonicity test case for uuid v7. (# 154)
  > 016b199 fix: fix typo in version 7 uuid documentation (# 153)
  > 1d8b6ea ci: set token permissions to github workflows (# 143)
  > a2b2b32 fix: Monotonicity in UUIDv7 (# 150)
  > c58770e feat: add Max UUID constant (# 149)
bumping knative.dev/pkg b488e7b...d34ca03:
  > d34ca03 Update knative.dev/hack to latest main (# 2949)
  > 91c6ec8 Bump google.golang.org/api from 0.157.0 to 0.159.0 (# 2946)
  > 6d59538 Bump github.com/evanphx/json-patch/v5 from 5.8.1 to 5.9.0 (# 2945)
  > 6eb53f5 Bump github.com/google/uuid from 1.5.0 to 1.6.0 (# 2944)
  > 2b8687a upgrade to latest dependencies (# 2943)
  > b42fab9 Update community files (# 2942)
  > 3f7ce63 Bump google.golang.org/api from 0.155.0 to 0.157.0 (# 2941)
  > 2a92e9d Bump github.com/evanphx/json-patch/v5 from 5.8.0 to 5.8.1 (# 2940)
  > 455683d Update community files (# 2939)
bumping google.golang.org/genproto/googleapis/api 989df2b...50ed04b:
  > 50ed04b chore(all): update all to v4 (# 1076)
  > 0d6446b chore(all): update all (# 1075)
  > 995d672 chore(all): update all (# 1073)
bumping google.golang.org/genproto 989df2b...50ed04b:
  > 50ed04b chore(all): update all to v4 (# 1076)
  > 0d6446b chore(all): update all (# 1075)
  > 995d672 chore(all): update all (# 1073)
bumping github.com/go-logr/logr 8adefbe...dcdc3f2:
  > dcdc3f2 slogr: fix unintended API break in v0.8.0 (# 253)
  > 5d88f52 funcr: Add LogInfoLevel Option to skip logging level in the info log (# 240)
  > 177005d build(deps): bump actions/upload-artifact from 3.1.3 to 4.0.0
  > e7f489a build(deps): bump github/codeql-action from 2.22.9 to 3.22.11
  > cf56c3b build(deps): bump actions/setup-go from 4 to 5
  > 2ad296e build(deps): bump github/codeql-action from 2.22.8 to 2.22.9
  > d55b4e2 Merge pull request # 241 from thockin/master
  > c589653 Merge pull request # 245 from thockin/sloghandler_empty_groups
  > 98ee9d9 Clean up slog testing and restore coverage
  > 006d752 Merge pull request # 246 from thockin/slog_context_tests
  > b01bad7 sloghandler: unnamed groups should be inlined
  > b228ba8 Break examples to new file
  > 5153ab2 unit tests with full SlogSink mock implementation
  > 2665157 Add tests for context with slog
  > 6432877 Add benchmarks for slogSink
  > 58f101e Fix bug in slog support carrying the wrong sink
  > f558531 Put slog tests in a helper, move funcr test
  > 6151b2f support a slog.Logger pointer in a context
  > 83dbe72 Fix some lint
  > 1fffd07 move slogr into main package
  > b5e7d9f funcr: Be consistent about quoted
  > 41d36ee build(deps): bump github/codeql-action from 2.22.7 to 2.22.8
  > 44c6ac8 funcr: Be consistent about colons
  > f36813a build(deps): bump github/codeql-action from 2.22.5 to 2.22.7
  > 955d2aa funcr: Be consistent about commas
  > 24eb27c build(deps): bump actions/github-script from 6.4.1 to 7.0.1
  > 8221825 Add SlogSink support to funcr
  > 5b79d78 Merge pull request # 233 from go-logr/dependabot/github_actions/github/codeql-action-2.22.5
  > d95f9b6 Get rid of testSlogSink
  > 424fad7 Merge pull request # 232 from go-logr/dependabot/github_actions/ossf/scorecard-action-2.3.1
  > e602c1d build(deps): bump github/codeql-action from 2.22.4 to 2.22.5
  > cdb930d Minor cleanups in slogr_test (readability)
  > 64618df build(deps): bump ossf/scorecard-action from 2.3.0 to 2.3.1

Signed-off-by: Knative Automation <automation@knative.team>
2024-01-29 15:36:25 +00:00
..
v5 upgrade to latest dependencies (#828) 2024-01-29 15:36:25 +00:00
.gitignore upgrade to latest dependencies (#613) 2022-03-23 10:23:19 -07:00
LICENSE bump k8s v0.18.12, go1.15 (#387) 2020-11-17 14:28:52 -08:00
README.md upgrade to latest dependencies (#587) 2022-01-05 13:08:33 -08:00
errors.go Update our dependency on K8s libs to 1.15.3 (#101) 2019-09-18 13:49:54 -07:00
merge.go upgrade to latest dependencies (#587) 2022-01-05 13:08:33 -08:00
patch.go upgrade to latest dependencies (#613) 2022-03-23 10:23:19 -07:00

README.md

JSON-Patch

jsonpatch is a library which provides functionality for both applying RFC6902 JSON patches against documents, as well as for calculating & applying RFC7396 JSON merge patches.

GoDoc Build Status Report Card

Get It!

Latest and greatest:

go get -u github.com/evanphx/json-patch/v5

Stable Versions:

  • Version 5: go get -u gopkg.in/evanphx/json-patch.v5
  • Version 4: go get -u gopkg.in/evanphx/json-patch.v4

(previous versions below v3 are unavailable)

Use It!

Configuration

  • There is a global configuration variable jsonpatch.SupportNegativeIndices. This defaults to true and enables the non-standard practice of allowing negative indices to mean indices starting at the end of an array. This functionality can be disabled by setting jsonpatch.SupportNegativeIndices = false.

  • There is a global configuration variable jsonpatch.AccumulatedCopySizeLimit, which limits the total size increase in bytes caused by "copy" operations in a patch. It defaults to 0, which means there is no limit.

These global variables control the behavior of jsonpatch.Apply.

An alternative to jsonpatch.Apply is jsonpatch.ApplyWithOptions whose behavior is controlled by an options parameter of type *jsonpatch.ApplyOptions.

Structure jsonpatch.ApplyOptions includes the configuration options above and adds two new options: AllowMissingPathOnRemove and EnsurePathExistsOnAdd.

When AllowMissingPathOnRemove is set to true, jsonpatch.ApplyWithOptions will ignore remove operations whose path points to a non-existent location in the JSON document. AllowMissingPathOnRemove defaults to false which will lead to jsonpatch.ApplyWithOptions returning an error when hitting a missing path on remove.

When EnsurePathExistsOnAdd is set to true, jsonpatch.ApplyWithOptions will make sure that add operations produce all the path elements that are missing from the target object.

Use jsonpatch.NewApplyOptions to create an instance of jsonpatch.ApplyOptions whose values are populated from the global configuration variables.

Create and apply a merge patch

Given both an original JSON document and a modified JSON document, you can create a Merge Patch document.

It can describe the changes needed to convert from the original to the modified JSON document.

Once you have a merge patch, you can apply it to other JSON documents using the jsonpatch.MergePatch(document, patch) function.

package main

import (
	"fmt"

	jsonpatch "github.com/evanphx/json-patch"
)

func main() {
	// Let's create a merge patch from these two documents...
	original := []byte(`{"name": "John", "age": 24, "height": 3.21}`)
	target := []byte(`{"name": "Jane", "age": 24}`)

	patch, err := jsonpatch.CreateMergePatch(original, target)
	if err != nil {
		panic(err)
	}

	// Now lets apply the patch against a different JSON document...

	alternative := []byte(`{"name": "Tina", "age": 28, "height": 3.75}`)
	modifiedAlternative, err := jsonpatch.MergePatch(alternative, patch)

	fmt.Printf("patch document:   %s\n", patch)
	fmt.Printf("updated alternative doc: %s\n", modifiedAlternative)
}

When ran, you get the following output:

$ go run main.go
patch document:   {"height":null,"name":"Jane"}
updated alternative doc: {"age":28,"name":"Jane"}

Create and apply a JSON Patch

You can create patch objects using DecodePatch([]byte), which can then be applied against JSON documents.

The following is an example of creating a patch from two operations, and applying it against a JSON document.

package main

import (
	"fmt"

	jsonpatch "github.com/evanphx/json-patch"
)

func main() {
	original := []byte(`{"name": "John", "age": 24, "height": 3.21}`)
	patchJSON := []byte(`[
		{"op": "replace", "path": "/name", "value": "Jane"},
		{"op": "remove", "path": "/height"}
	]`)

	patch, err := jsonpatch.DecodePatch(patchJSON)
	if err != nil {
		panic(err)
	}

	modified, err := patch.Apply(original)
	if err != nil {
		panic(err)
	}

	fmt.Printf("Original document: %s\n", original)
	fmt.Printf("Modified document: %s\n", modified)
}

When ran, you get the following output:

$ go run main.go
Original document: {"name": "John", "age": 24, "height": 3.21}
Modified document: {"age":24,"name":"Jane"}

Comparing JSON documents

Due to potential whitespace and ordering differences, one cannot simply compare JSON strings or byte-arrays directly.

As such, you can instead use jsonpatch.Equal(document1, document2) to determine if two JSON documents are structurally equal. This ignores whitespace differences, and key-value ordering.

package main

import (
	"fmt"

	jsonpatch "github.com/evanphx/json-patch"
)

func main() {
	original := []byte(`{"name": "John", "age": 24, "height": 3.21}`)
	similar := []byte(`
		{
			"age": 24,
			"height": 3.21,
			"name": "John"
		}
	`)
	different := []byte(`{"name": "Jane", "age": 20, "height": 3.37}`)

	if jsonpatch.Equal(original, similar) {
		fmt.Println(`"original" is structurally equal to "similar"`)
	}

	if !jsonpatch.Equal(original, different) {
		fmt.Println(`"original" is _not_ structurally equal to "different"`)
	}
}

When ran, you get the following output:

$ go run main.go
"original" is structurally equal to "similar"
"original" is _not_ structurally equal to "different"

Combine merge patches

Given two JSON merge patch documents, it is possible to combine them into a single merge patch which can describe both set of changes.

The resulting merge patch can be used such that applying it results in a document structurally similar as merging each merge patch to the document in succession.

package main

import (
	"fmt"

	jsonpatch "github.com/evanphx/json-patch"
)

func main() {
	original := []byte(`{"name": "John", "age": 24, "height": 3.21}`)

	nameAndHeight := []byte(`{"height":null,"name":"Jane"}`)
	ageAndEyes := []byte(`{"age":4.23,"eyes":"blue"}`)

	// Let's combine these merge patch documents...
	combinedPatch, err := jsonpatch.MergeMergePatches(nameAndHeight, ageAndEyes)
	if err != nil {
		panic(err)
	}

	// Apply each patch individual against the original document
	withoutCombinedPatch, err := jsonpatch.MergePatch(original, nameAndHeight)
	if err != nil {
		panic(err)
	}

	withoutCombinedPatch, err = jsonpatch.MergePatch(withoutCombinedPatch, ageAndEyes)
	if err != nil {
		panic(err)
	}

	// Apply the combined patch against the original document

	withCombinedPatch, err := jsonpatch.MergePatch(original, combinedPatch)
	if err != nil {
		panic(err)
	}

	// Do both result in the same thing? They should!
	if jsonpatch.Equal(withCombinedPatch, withoutCombinedPatch) {
		fmt.Println("Both JSON documents are structurally the same!")
	}

	fmt.Printf("combined merge patch: %s", combinedPatch)
}

When ran, you get the following output:

$ go run main.go
Both JSON documents are structurally the same!
combined merge patch: {"age":4.23,"eyes":"blue","height":null,"name":"Jane"}

CLI for comparing JSON documents

You can install the commandline program json-patch.

This program can take multiple JSON patch documents as arguments, and fed a JSON document from stdin. It will apply the patch(es) against the document and output the modified doc.

patch.1.json

[
    {"op": "replace", "path": "/name", "value": "Jane"},
    {"op": "remove", "path": "/height"}
]

patch.2.json

[
    {"op": "add", "path": "/address", "value": "123 Main St"},
    {"op": "replace", "path": "/age", "value": "21"}
]

document.json

{
    "name": "John",
    "age": 24,
    "height": 3.21
}

You can then run:

$ go install github.com/evanphx/json-patch/cmd/json-patch
$ cat document.json | json-patch -p patch.1.json -p patch.2.json
{"address":"123 Main St","age":"21","name":"Jane"}

Help It!

Contributions are welcomed! Leave an issue or create a PR.

Before creating a pull request, we'd ask that you make sure tests are passing and that you have added new tests when applicable.

Contributors can run tests using:

go test -cover ./...

Builds for pull requests are tested automatically using TravisCI.