Last active
April 4, 2021 17:10
-
-
Save pivotaljohn/15b584fed986b9cc189b203adbb39af9 to your computer and use it in GitHub Desktop.
RFC 6902 "JSON Patch" implemented in `ytt`
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
kind: Package | |
spec: | |
template: | |
spec: | |
fetch: | |
- imgpkgBundle: | |
image: base-image |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
load("@ytt:struct", "struct") | |
load("@ytt:yaml", "yaml") | |
# `raw_yaml()` makes an editable copy of `node` | |
# warning: all nodes are scrubbed of attached annotations and code. | |
def raw_yaml(node): | |
return yaml.decode(yaml.encode(node)) | |
end | |
def key_or_index(target, part): | |
if type(target) == type([]): | |
part = len(target) if part == "-" else int(part) | |
end | |
return part | |
end | |
# `at()` returns: | |
# 1. the penultimate descendant located along `path` from `node` | |
# 2. the key/index to the ultimate descenant | |
def at(node, path): | |
parts = path.split("/")[1:] | |
target = node | |
for part in parts[:-1]: | |
target = target[key_or_index(target, part)] | |
end | |
return (target, key_or_index(target, parts[-1])) | |
end | |
def edit(left, path, right, op): | |
copy = raw_yaml(left) | |
(target, key) = at(copy, path) | |
op(target, key, right) | |
return copy | |
end | |
def add(target, key, right): | |
if type(target) == type([]): | |
target.insert(key, right) | |
end | |
target[key] = right | |
end | |
def remove(target, key, _): | |
target.pop(key) | |
end | |
def replace(target, key, right): | |
target[key] = right | |
end | |
def move(left, src, dest): | |
(target, key) = at(raw_yaml(left), src) | |
copy = edit(left, src, None, remove) | |
copy = edit(copy, dest, target[key], add) | |
return copy | |
end | |
def jsonpath_add(path): | |
return lambda left, right: edit(left, path, right, add) | |
end | |
def jsonpath_remove(path): | |
return lambda left, right: edit(left, path, right, remove) | |
end | |
def jsonpath_replace(path): | |
return lambda left, right: edit(left, path, right, replace) | |
end | |
def jsonpath_move(src, dest): | |
return lambda left, right: move(left, src, dest) | |
end | |
jsonpatch = struct.make(add=jsonpath_add, move=jsonpath_move, remove=jsonpath_remove, replace=jsonpath_replace) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#@ load("@ytt:overlay", "overlay") | |
#@ load("jsonpatch.star", "jsonpatch") | |
#@overlay/match by=overlay.subset({"kind": "Package"}) | |
#@overlay/replace via=jsonpatch.replace("/spec/template/spec/fetch/0/imgpkgBundle/image") | |
--- | |
dev_image |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#@ load("@ytt:overlay", "overlay") | |
#@ load("jsonpatch.star", "jsonpatch") | |
--- | |
id: A.1 | |
name: Adding an Object Member | |
foo: bar | |
#@overlay/match by=overlay.subset({"id": "A.1"}) | |
#@overlay/replace via=jsonpatch.add("/baz") | |
--- | |
qux | |
#@overlay/match by=overlay.subset({"id": "A.1"}) | |
#@overlay/assert | |
--- | |
baz: qux | |
foo: bar | |
... | |
--- | |
id: A.2 | |
name: Adding an Array Element | |
foo: | |
- bar | |
- baz | |
#@overlay/match by=overlay.subset({"id": "A.2"}) | |
#@overlay/replace via=jsonpatch.add("/foo/1") | |
--- | |
qux | |
#@overlay/match by=overlay.subset({"id": "A.2"}) | |
#@overlay/assert | |
--- | |
foo: | |
#@overlay/assert | |
- bar | |
#@overlay/assert | |
- qux | |
#@overlay/assert | |
- baz | |
... | |
--- | |
id: A.3 | |
name: Removing an Object Member | |
baz: qux | |
foo: bar | |
#@overlay/match by=overlay.subset({"id": "A.3"}) | |
#@overlay/replace via=jsonpatch.remove("/baz") | |
--- | |
#@overlay/match by=overlay.subset({"id": "A.3"}) | |
#@overlay/assert | |
--- | |
foo: bar | |
... | |
--- | |
id: A.4 | |
name: Removing an Array Element | |
foo: ["bar", "quz", "baz"] | |
#@overlay/match by=overlay.subset({"id": "A.4"}) | |
#@overlay/replace via=jsonpatch.remove("/foo/1") | |
--- | |
#@overlay/match by=overlay.subset({"id": "A.4"}) | |
#@overlay/assert | |
--- | |
foo: | |
#@overlay/assert | |
- bar | |
#@overlay/assert | |
- baz | |
... | |
--- | |
id: A.5 | |
name: Replacing a Value | |
baz: qux | |
foo: bar | |
#@overlay/match by=overlay.subset({"id": "A.5"}) | |
#@overlay/replace via=jsonpatch.replace("/baz") | |
--- | |
boo | |
#@overlay/match by=overlay.subset({"id": "A.5"}) | |
#@overlay/assert | |
--- | |
baz: boo | |
foo: bar | |
... | |
--- | |
id: A.6 | |
name: Moving a Value | |
foo: | |
bar: baz | |
waldo: fred | |
qux: | |
corge: grault | |
#@overlay/match by=overlay.subset({"id": "A.6"}) | |
#@overlay/replace via=jsonpatch.move("/foo/waldo","/qux/thud") | |
--- | |
#@overlay/match by=overlay.subset({"id": "A.6"}) | |
--- | |
foo: | |
#@overlay/assert | |
bar: baz | |
qux: | |
#@overlay/assert | |
corge: grault | |
#@overlay/assert | |
thud: fred | |
... | |
--- | |
id: A.7 | |
name: Moving an Array Element | |
foo: | |
- all | |
- grass | |
- cows | |
- eat | |
#@overlay/match by=overlay.subset({"id": "A.7"}) | |
#@overlay/replace via=jsonpatch.move("/foo/1", "/foo/3") | |
--- | |
#@overlay/match by=overlay.subset({"id": "A.7"}) | |
--- | |
#@overlay/assert | |
foo: | |
#@overlay/assert | |
- all | |
#@overlay/assert | |
- cows | |
#@overlay/assert | |
- eat | |
#@overlay/assert | |
- grass | |
... | |
--- | |
id: A.10 | |
name: Adding a Nested Member Object | |
foo: bar | |
#@overlay/match by=overlay.subset({"id": "A.10"}) | |
#@overlay/replace via=jsonpatch.add("/child") | |
--- | |
grandchild: {} | |
#@overlay/match by=overlay.subset({"id": "A.10"}) | |
--- | |
#@overlay/assert | |
foo: bar | |
#@overlay/assert | |
child: | |
#@overlay/assert | |
grandchild: {} | |
... | |
--- | |
id: A.16 | |
name: Adding an Array Value | |
foo: | |
- bar | |
#@overlay/match by=overlay.subset({"id": "A.16"}) | |
#@overlay/replace via=jsonpatch.add("/foo/-") | |
--- | |
- abc | |
- def | |
#@overlay/match by=overlay.subset({"id": "A.16"}) | |
--- | |
foo: | |
#@overlay/assert | |
- bar | |
#@overlay/assert | |
- | |
#@overlay/assert | |
- abc | |
#@overlay/assert | |
- def | |
... | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment