{{- /* tplYaml input: map with 2 keys: - doc: interface{} - ctx: context to pass to tpl function output: JSON encoded map with 1 key: - doc: interface{} with any keys called tpl or tplSpread values templated and replaced maps matching the following syntax will be templated and parsed as YAML { $tplYaml: string } maps matching the follow syntax will be templated, parsed as YAML, and spread into the parent map/slice { $tplYamlSpread: string } */}} {{- define "tplYaml" -}} {{- $patch := get (include "tplYamlItr" (dict "ctx" .ctx "parentKind" "" "parentPath" "" "path" "/" "value" .doc) | fromJson) "patch" -}} {{- include "jsonpatch" (dict "doc" .doc "patch" $patch) -}} {{- end -}} {{- /* tplYamlItr input: map with 4 keys: - path: string JSONPath to current element - parentKind: string kind of parent element - parentPath: string JSONPath to parent element - value: interface{} - ctx: context to pass to tpl function output: JSON encoded map with 1 key: - patch: list of patches to apply in order to template */}} {{- define "tplYamlItr" -}} {{- $params := . -}} {{- $kind := kindOf $params.value -}} {{- $patch := list -}} {{- $joinPath := $params.path -}} {{- if eq $params.path "/" -}} {{- $joinPath = "" -}} {{- end -}} {{- $joinParentPath := $params.parentPath -}} {{- if eq $params.parentPath "/" -}} {{- $joinParentPath = "" -}} {{- end -}} {{- if eq $kind "slice" -}} {{- $iAdj := 0 -}} {{- range $i, $v := $params.value -}} {{- $iPath := printf "%s/%d" $joinPath (add $i $iAdj) -}} {{- $itrPatch := get (include "tplYamlItr" (dict "ctx" $params.ctx "parentKind" $kind "parentPath" $params.path "path" $iPath "value" $v) | fromJson) "patch" -}} {{- $itrLen := len $itrPatch -}} {{- if gt $itrLen 0 -}} {{- $patch = concat $patch $itrPatch -}} {{- if eq (get (index $itrPatch 0) "op") "remove" -}} {{- $iAdj = add $iAdj (sub $itrLen 2) -}} {{- end -}} {{- end -}} {{- end -}} {{- else if eq $kind "map" -}} {{- if and (eq (len $params.value) 1) (or (hasKey $params.value "$tplYaml") (hasKey $params.value "$tplYamlSpread")) -}} {{- $tpl := get $params.value "$tplYaml" -}} {{- $spread := false -}} {{- if hasKey $params.value "$tplYamlSpread" -}} {{- if eq $params.path "/" -}} {{- fail "cannot $tplYamlSpread on root object" -}} {{- end -}} {{- $tpl = get $params.value "$tplYamlSpread" -}} {{- $spread = true -}} {{- end -}} {{- $res := tpl $tpl $params.ctx -}} {{- $res = get (fromYaml (tpl "tpl: {{ nindent 2 .res }}" (merge (dict "res" $res) $params.ctx))) "tpl" -}} {{- if eq $spread false -}} {{- $patch = append $patch (dict "op" "replace" "path" $params.path "value" $res) -}} {{- else -}} {{- $resKind := kindOf $res -}} {{- if and (ne $resKind "invalid") (ne $resKind $params.parentKind) -}} {{- fail (cat "can only $tplYamlSpread slice onto a slice or map onto a map; attempted to spread" $resKind "on" $params.parentKind "at path" $params.path) -}} {{- end -}} {{- $patch = append $patch (dict "op" "remove" "path" $params.path) -}} {{- if eq $resKind "invalid" -}} {{- /* no-op */ -}} {{- else if eq $resKind "slice" -}} {{- range $v := reverse $res -}} {{- $patch = append $patch (dict "op" "add" "path" $params.path "value" $v) -}} {{- end -}} {{- else -}} {{- range $k, $v := $res -}} {{- $kPath := replace "~" "~0" $k -}} {{- $kPath = replace "/" "~1" $kPath -}} {{- $kPath = printf "%s/%s" $joinParentPath $kPath -}} {{- $patch = append $patch (dict "op" "add" "path" $kPath "value" $v) -}} {{- end -}} {{- end -}} {{- end -}} {{- else -}} {{- range $k, $v := $params.value -}} {{- $kPath := replace "~" "~0" $k -}} {{- $kPath = replace "/" "~1" $kPath -}} {{- $kPath = printf "%s/%s" $joinPath $kPath -}} {{- $itrPatch := get (include "tplYamlItr" (dict "ctx" $params.ctx "parentKind" $kind "parentPath" $params.path "path" $kPath "value" $v) | fromJson) "patch" -}} {{- if gt (len $itrPatch) 0 -}} {{- $patch = concat $patch $itrPatch -}} {{- end -}} {{- end -}} {{- end -}} {{- end -}} {{- toJson (dict "patch" $patch) -}} {{- end -}}