@ -1,7 +1,7 @@
{{/*
{{/*
Resolves the `allOf` keyword (https://spec.openapis.org/oas/v3.1.0#composition-and-inheritance-polymorphism),
Resolves the `allOf` keyword (https://spec.openapis.org/oas/v3.1.0#composition-and-inheritance-polymorphism)
given a JSON schema object.
recursively, given a JSON schema object.
`allOf` is used to support a kind of inheritance for JSON schema objects.
`allOf` is used to support a kind of inheritance for JSON schema objects.
@ -11,36 +11,44 @@
Of course the parent can itself inherit from *its* parent, so we recurse to
Of course the parent can itself inherit from *its* parent, so we recurse to
handle that.
handle that.
Note that `allOf` is only resolved at the top level of the schema object. For
example, if you call this on an API definition which defines a `parameter`
which has an allOf schema, it will not be resolved. To handle this, the
openapi templates call resolve-allof for every schema object that they
process.
*/}}
*/}}
{{ $ret := . }}
{{ $ret := . }}
{{ $original := . }}
{{ $original := . }}
{{ if reflect.IsSlice $original }}
{{/*
If it's a slice, just recurse.
*/}}
{{ $ret = slice }}
{{ range $original }}
{{ $resolved := partial "json-schema/resolve-allof" . }}
{{ $ret = $ret | append $resolved }}
{{ end }}
{{ else if reflect.IsMap $original }}
{{ $ret = dict }}
{{/*
{{/*
We special-case 'required', and accumulate the values from all the 'allOf'
We special-case 'required', and accumulate the values from all the 'allOf'
entries (rather than simply overriding them). Start the accumulation here.
entries (rather than simply overriding them). Start the accumulation here.
*/}}
*/}}
{{ $required := .required }}
{{ if not $required }}
{{ $required := slice }}
{{ $required := slice }}
{{ with $original.required }}
{{ $required = . }}
{{ end }}
{{ end }}
{{ with $ret.allOf }}
{{ with $original.allOf }}
{{/*
{{/*
construct a new dict, with each of the allOf entries merged into it in
Merge each of the allOf entries.
turn.
*/}}
*/}}
{{ $all_of_values := dict }}
{{ range . }}
{{ range . }}
{{ with .required }}
{{/*
First, resolve allOf in child.
*/}}
{{ $resolved := partial "json-schema/resolve-allof" . }}
{{ with $resolved.required }}
{{ $required = union $required . }}
{{ $required = union $required . }}
{{ end }}
{{ end }}
@ -51,52 +59,23 @@
Note also that `merge` does a *deep* merge - nested maps are also
Note also that `merge` does a *deep* merge - nested maps are also
merged. (Slices are replaced though.)
merged. (Slices are replaced though.)
*/}}
*/}}
{{ $all_of_values = merge $all_of_values . }}
{{ $ret = merge $ret $resolved }}
{{ end }}
{{ end }}
{{ end }}
{{/*
{{/*
Finally, merge in the original, allowing the original to override allOf.
Finally, merge in the original, allowing the original to override allOf.
*/}}
*/}}
{{ $ret = merge $all_of_values $ret }}
{{ range $key, $value := $original }}
{{ if and (ne $key "allOf") (ne $key "required") }}
{{/*
{{ $resolved := partial "json-schema/resolve-allof" $value }}
Except that if allOf *itself* contains allOf (ie, the parent also
{{ $ret = merge $ret (dict $key $resolved) }}
inherits from a grandparent), then we replace allOf in the original
with that in the parent. Below, we see that this has happened, and
recurse.
TODO: surely it would be better to simply do the recursion as we iterate
though the allOf list above - not least because we might have multiple
parents with different grandparents, and by doing this we only get one
set of grandparents.
*/}}
{{ with $all_of_values.allOf }}
{{ $ret = merge $ret (dict "allOf" . ) }}
{{ end }}
{{ end }}
{{/*
special-case 'required': replace it with the union of all the
'required' arrays from the original and allOf values.
XXX: but first we merge in the original 'required', again? why
do we do that? it should already have been done at the start.
*/}}
{{ with $ret.required }}
{{ $required = union $required $ret.required }}
{{ end }}
{{ end }}
{{ $ret = merge $ret (dict "required" $required) }}
{{ with $required }}
{{ $ret = merge $ret (dict "required" .) }}
{{ end }}
{{ end }}
{{/*
If we replaced the 'allOf' dict with one from a grandparent, we now
need to recurse.
*/}}
{{ if ne $ret.allOf $original.allOf }}
{{ $resolved := partial "json-schema/resolve-allof" $ret }}
{{ $ret = merge $ret $resolved }}
{{ end }}
{{ end }}
{{ return $ret }}
{{ return $ret }}