|
|
@ -1,133 +1,207 @@
|
|
|
|
{{/*
|
|
|
|
/* Finds and returns all schema definitions for objects, including subschemas,
|
|
|
|
|
|
|
|
* in a JSON schema.
|
|
|
|
Finds and returns all objects, including nested ones, given a dict containing:
|
|
|
|
*
|
|
|
|
* `schema`: a JSON schema object
|
|
|
|
* The input should be a dict containing:
|
|
|
|
* `anchor_base`: a prefix to add to the HTML anchors generated for each object. If nil, no anchors are generated.
|
|
|
|
*
|
|
|
|
* `name`: optionally, a name to use for this object in error/warning messages. If left unset,
|
|
|
|
* * `schema`: a dict containing a JSON schema.
|
|
|
|
the object's `title` property is used (if present).
|
|
|
|
* * `anchor_base`: a prefix to add to the HTML anchors generated for each
|
|
|
|
|
|
|
|
* object. If nil, no anchors are generated.
|
|
|
|
This template finds all nested objects inside `schema`.
|
|
|
|
* * `name`: optionally, a name to use for this schema in error/warning
|
|
|
|
|
|
|
|
* messages. If left unset, the schema's `title` property is used (if
|
|
|
|
Assumes that "resolve-refs" and "resolve-allof" has already been called on the
|
|
|
|
* present).
|
|
|
|
input schema.
|
|
|
|
*
|
|
|
|
|
|
|
|
* Assumes that "resolve-refs" and "resolve-allof" has already been called on
|
|
|
|
Returns an array of all the objects found. The first object keeps all its properties. For all other objects, the following properties are returned:
|
|
|
|
* the input schema.
|
|
|
|
* title
|
|
|
|
*
|
|
|
|
* properties
|
|
|
|
* Returns an array of all the JSON schema definitions with `type: object` found
|
|
|
|
* required
|
|
|
|
* by recursing through `schema` and inspecting any subschemas, and including
|
|
|
|
* enum
|
|
|
|
* `schema` itself.
|
|
|
|
* anchor: a string suitable for using as an html anchor for this object (if `anchor_base` was set, and the object has a title)
|
|
|
|
*
|
|
|
|
|
|
|
|
* The returned entries are based on the JSON schema definitions found by
|
|
|
|
Note that the returned array contains only unique objects.
|
|
|
|
* recursing through the input `schema`, with the following differences:
|
|
|
|
|
|
|
|
*
|
|
|
|
*/}}
|
|
|
|
* * `allOf` references are expanded. (Although this partial requires that
|
|
|
|
|
|
|
|
* `resolve-allof` is called on the top-level `schema` beforehand,
|
|
|
|
|
|
|
|
* `resolve-allof` doesn't recurse down to subschemas).
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* * If `anchor_base` is set, each object with a `title` and `properties`
|
|
|
|
|
|
|
|
* is given an `anchor`, which is a string suitable for using as an html
|
|
|
|
|
|
|
|
* anchor for that object schema.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* * With the *exception* of the top-level `schema` (if it is an object),
|
|
|
|
|
|
|
|
* properties outside the following list are removed:
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* * title
|
|
|
|
|
|
|
|
* * properties
|
|
|
|
|
|
|
|
* * required
|
|
|
|
|
|
|
|
* * enum
|
|
|
|
|
|
|
|
* * anchor
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* In particular, this means that examples are removed (typically examples
|
|
|
|
|
|
|
|
* are not helpful for subschemas), which means that duplicate schemas can
|
|
|
|
|
|
|
|
* be successfully eliminated.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* The returned array contains only unique objects (ie, if the same object is
|
|
|
|
|
|
|
|
* referenced twice within `schema`, it will only be returned once).
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
{{ $this_object := .schema }}
|
|
|
|
{{ $res := partial "resolve-additional-types-inner" (dict
|
|
|
|
{{ $anchor_base := .anchor_base }}
|
|
|
|
"schema" .schema
|
|
|
|
{{ $all_objects := slice }}
|
|
|
|
"anchor_base" .anchor_base
|
|
|
|
{{ $name := .name | default $this_object.title | default "<untitled object>" }}
|
|
|
|
"name" (.name | default .schema.title | default "<untitled object>")
|
|
|
|
|
|
|
|
) }}
|
|
|
|
|
|
|
|
{{ return $res.objects }}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* A helper for the resolve-additional-types partial.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* Takes the same inputs as resolve-additional-types itself, except that `name` is mandatory.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* Returns a dict containing:
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* * `objects`: The array of object schema definitions.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* * `schema`: An updated copy of the `schema` input (eg, nested `allOf`
|
|
|
|
|
|
|
|
* entries are expanded, and an `anchor` may be added). If the input
|
|
|
|
|
|
|
|
* `schema` was itself an object, this will be the same as the first entry
|
|
|
|
|
|
|
|
* in `objects`.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
{{ define "partials/resolve-additional-types-inner" }}
|
|
|
|
|
|
|
|
{{ $this_object := .schema }}
|
|
|
|
|
|
|
|
{{ $anchor_base := .anchor_base }}
|
|
|
|
|
|
|
|
{{ $name := .name }}
|
|
|
|
|
|
|
|
{{ $all_objects := slice }}
|
|
|
|
|
|
|
|
|
|
|
|
{{ if eq $this_object.type "object" }}
|
|
|
|
{{ if eq $this_object.type "object" }}
|
|
|
|
{{/* give this object an anchor, if it has a name */}}
|
|
|
|
/* Give this object an anchor, if it has a name and properties */
|
|
|
|
{{ if (and $anchor_base $this_object.title) }}
|
|
|
|
{{ if (and $anchor_base $this_object.title $this_object.properties) }}
|
|
|
|
{{ $this_object = merge $this_object (dict "anchor" (printf "%s_%s" $anchor_base (anchorize $this_object.title))) }}
|
|
|
|
{{ $this_object = merge $this_object (dict "anchor" (printf "%s_%s" $anchor_base (anchorize $this_object.title))) }}
|
|
|
|
{{ end }}
|
|
|
|
{{ end }}
|
|
|
|
|
|
|
|
|
|
|
|
{{/*
|
|
|
|
/* Add any nested objects referenced in this object's `additionalProperties` */
|
|
|
|
Add the object we were passed into the $all_objects array
|
|
|
|
|
|
|
|
*/}}
|
|
|
|
|
|
|
|
{{ $all_objects = $all_objects | append $this_object }}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{{/*
|
|
|
|
|
|
|
|
Add any nested objects referenced in this object's `additionalProperties`
|
|
|
|
|
|
|
|
*/}}
|
|
|
|
|
|
|
|
{{ if $this_object.additionalProperties }}
|
|
|
|
{{ if $this_object.additionalProperties }}
|
|
|
|
{{ if reflect.IsMap $this_object.additionalProperties }}
|
|
|
|
{{ if reflect.IsMap $this_object.additionalProperties }}
|
|
|
|
{{ $all_objects = partial "get-additional-objects" (dict
|
|
|
|
{{ $res := partial "get-additional-objects" (dict
|
|
|
|
"this_object" $this_object.additionalProperties
|
|
|
|
"this_object" $this_object.additionalProperties
|
|
|
|
"all_objects" $all_objects
|
|
|
|
"all_objects" $all_objects
|
|
|
|
"anchor_base" $anchor_base
|
|
|
|
"anchor_base" $anchor_base
|
|
|
|
"name" (printf "%s.additional" $name)
|
|
|
|
"name" (printf "%s.additional" $name)
|
|
|
|
) }}
|
|
|
|
) }}
|
|
|
|
|
|
|
|
{{ $all_objects = $res.objects }}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Update the top-level schema with the updated subschemas for the additionalProperties */
|
|
|
|
|
|
|
|
{{ $this_object = merge $this_object (dict "additionalProperties" $res.schema) }}
|
|
|
|
{{ end }}
|
|
|
|
{{ end }}
|
|
|
|
{{ end }}
|
|
|
|
{{ end }}
|
|
|
|
|
|
|
|
|
|
|
|
{{/*
|
|
|
|
/* Add any nested objects referenced in this object's `patternProperties` */
|
|
|
|
Add any nested objects referenced in this object's `patternProperties`
|
|
|
|
|
|
|
|
*/}}
|
|
|
|
|
|
|
|
{{ if $this_object.patternProperties }}
|
|
|
|
{{ if $this_object.patternProperties }}
|
|
|
|
|
|
|
|
{{ $updated_pattern_properties := dict }}
|
|
|
|
{{ range $pattern, $object := $this_object.patternProperties}}
|
|
|
|
{{ range $pattern, $object := $this_object.patternProperties}}
|
|
|
|
{{ $all_objects = partial "get-additional-objects" (dict
|
|
|
|
{{ $res := partial "get-additional-objects" (dict
|
|
|
|
"this_object" $object
|
|
|
|
"this_object" $object
|
|
|
|
"all_objects" $all_objects
|
|
|
|
"all_objects" $all_objects
|
|
|
|
"anchor_base" $anchor_base
|
|
|
|
"anchor_base" $anchor_base
|
|
|
|
"name" (printf "%s.pattern.%s" $name $pattern)
|
|
|
|
"name" (printf "%s.pattern.%s" $name $pattern)
|
|
|
|
) }}
|
|
|
|
) }}
|
|
|
|
|
|
|
|
{{ $all_objects = $res.objects }}
|
|
|
|
|
|
|
|
{{ $updated_pattern_properties = merge $updated_pattern_properties (dict $pattern $res.schema) }}
|
|
|
|
{{ end }}
|
|
|
|
{{ end }}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Update the top-level schema with the updated subschemas for the patternProperties */
|
|
|
|
|
|
|
|
{{ $this_object = merge $this_object (dict "patternProperties" $updated_pattern_properties) }}
|
|
|
|
{{ end }}
|
|
|
|
{{ end }}
|
|
|
|
|
|
|
|
|
|
|
|
{{/*
|
|
|
|
/* Add any nested objects referenced in this object's `properties` */
|
|
|
|
Add any nested objects referenced in this object's `properties`
|
|
|
|
{{ if $this_object.properties }}
|
|
|
|
*/}}
|
|
|
|
{{ $updated_properties := dict }}
|
|
|
|
{{ range $key, $property := $this_object.properties}}
|
|
|
|
{{ range $key, $property := $this_object.properties}}
|
|
|
|
{{ $all_objects = partial "get-additional-objects" (dict
|
|
|
|
{{ $res := partial "get-additional-objects" (dict
|
|
|
|
"this_object" $property
|
|
|
|
"this_object" $property
|
|
|
|
"all_objects" $all_objects
|
|
|
|
"all_objects" $all_objects
|
|
|
|
"anchor_base" $anchor_base
|
|
|
|
"anchor_base" $anchor_base
|
|
|
|
"name" (printf "%s.%s" $name $key)
|
|
|
|
"name" (printf "%s.%s" $name $key)
|
|
|
|
) }}
|
|
|
|
) }}
|
|
|
|
|
|
|
|
{{ $all_objects = $res.objects }}
|
|
|
|
|
|
|
|
{{ $updated_properties = merge $updated_properties (dict $key $res.schema) }}
|
|
|
|
{{ end }}
|
|
|
|
{{ end }}
|
|
|
|
|
|
|
|
|
|
|
|
{{ end }}
|
|
|
|
/* Update the top-level schema with the updated subschemas for the regular properties */
|
|
|
|
|
|
|
|
{{ $this_object = merge $this_object (dict "properties" $updated_properties) }}
|
|
|
|
|
|
|
|
{{ end }}
|
|
|
|
|
|
|
|
|
|
|
|
{{ if eq $this_object.type "array" }}
|
|
|
|
/* Finally, prepend the updated schema for the top-level object onto the $all_objects array */
|
|
|
|
{{/*
|
|
|
|
{{ $tmp := slice $this_object }}
|
|
|
|
Add any nested objects referenced in this object's `items`
|
|
|
|
{{ if $all_objects }}
|
|
|
|
*/}}
|
|
|
|
{{ $tmp = $tmp | append $all_objects }}
|
|
|
|
|
|
|
|
{{ end }}
|
|
|
|
|
|
|
|
{{ $all_objects = $tmp }}
|
|
|
|
|
|
|
|
{{ end }}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{{ if eq $this_object.type "array" }}
|
|
|
|
|
|
|
|
/* Add any nested objects referenced in this object's `items` */
|
|
|
|
{{ if $this_object.items.anyOf }}
|
|
|
|
{{ if $this_object.items.anyOf }}
|
|
|
|
{{ range $idx, $item := $this_object.items.anyOf }}
|
|
|
|
{{ range $idx, $item := $this_object.items.anyOf }}
|
|
|
|
{{ $all_objects = partial "get-additional-objects" (dict
|
|
|
|
{{ $res := partial "get-additional-objects" (dict
|
|
|
|
"this_object" $item
|
|
|
|
"this_object" $item
|
|
|
|
"all_objects" $all_objects
|
|
|
|
"all_objects" $all_objects
|
|
|
|
"anchor_base" $anchor_base
|
|
|
|
"anchor_base" $anchor_base
|
|
|
|
"name" (printf "%s.items[%d]" $name $idx)
|
|
|
|
"name" (printf "%s.items[%d]" $name $idx)
|
|
|
|
) }}
|
|
|
|
) }}
|
|
|
|
|
|
|
|
{{ $all_objects = $res.objects }}
|
|
|
|
{{ end }}
|
|
|
|
{{ end }}
|
|
|
|
{{ else if reflect.IsMap $this_object.items}}
|
|
|
|
{{ else if reflect.IsMap $this_object.items}}
|
|
|
|
{{ $all_objects = partial "get-additional-objects" (dict
|
|
|
|
{{ $res := partial "get-additional-objects" (dict
|
|
|
|
"this_object" $this_object.items
|
|
|
|
"this_object" $this_object.items
|
|
|
|
"all_objects" $all_objects
|
|
|
|
"all_objects" $all_objects
|
|
|
|
"anchor_base" $anchor_base
|
|
|
|
"anchor_base" $anchor_base
|
|
|
|
"name" (printf "%s.items" $name)
|
|
|
|
"name" (printf "%s.items" $name)
|
|
|
|
) }}
|
|
|
|
) }}
|
|
|
|
|
|
|
|
{{ $all_objects = $res.objects }}
|
|
|
|
|
|
|
|
/* Update the top-level schema with the updated subschema for the items */
|
|
|
|
|
|
|
|
{{ $this_object = merge $this_object (dict "items" $res.schema) }}
|
|
|
|
{{ else }}
|
|
|
|
{{ else }}
|
|
|
|
{{ errorf "%s is defined as an 'array' but lacks a valid 'items'" $name }}
|
|
|
|
{{ errorf "%s is defined as an 'array' but lacks a valid 'items'" $name }}
|
|
|
|
{{ end }}
|
|
|
|
{{ end }}
|
|
|
|
{{ end }}
|
|
|
|
{{ end }}
|
|
|
|
|
|
|
|
|
|
|
|
{{/*
|
|
|
|
/* Handle object schemas using the `oneOf` keyword
|
|
|
|
Handle object schemas using the `oneOf` keyword
|
|
|
|
* (https://json-schema.org/understanding-json-schema/reference/combining.html#oneof)
|
|
|
|
(https://json-schema.org/understanding-json-schema/reference/combining.html#oneof)
|
|
|
|
*/
|
|
|
|
*/}}
|
|
|
|
{{ if $this_object.oneOf }}
|
|
|
|
{{ if $this_object.oneOf }}
|
|
|
|
|
|
|
|
{{ range $idx, $item := $this_object.oneOf }}
|
|
|
|
{{ range $idx, $item := $this_object.oneOf }}
|
|
|
|
{{ $all_objects = partial "get-additional-objects" (dict
|
|
|
|
{{ $res := partial "get-additional-objects" (dict
|
|
|
|
"this_object" $item
|
|
|
|
"this_object" $item
|
|
|
|
"all_objects" $all_objects
|
|
|
|
"all_objects" $all_objects
|
|
|
|
"anchor_base" $anchor_base
|
|
|
|
"anchor_base" $anchor_base
|
|
|
|
"name" (printf "%s.oneOf[%d]" $name $idx)
|
|
|
|
"name" (printf "%s.oneOf[%d]" $name $idx)
|
|
|
|
) }}
|
|
|
|
) }}
|
|
|
|
|
|
|
|
{{ $all_objects = $res.objects }}
|
|
|
|
|
|
|
|
{{ end }}
|
|
|
|
{{ end }}
|
|
|
|
{{ end }}
|
|
|
|
{{ end }}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{{ return uniq $all_objects }}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{{ return (dict
|
|
|
|
|
|
|
|
"objects" (uniq $all_objects)
|
|
|
|
|
|
|
|
"schema" $this_object
|
|
|
|
|
|
|
|
) }}
|
|
|
|
|
|
|
|
{{ end }}
|
|
|
|
|
|
|
|
|
|
|
|
{{/*
|
|
|
|
/* This actually makes the recursive call and adds the returned object schema definitions to the array.
|
|
|
|
This actually makes the recursive call and adds the returned objects to the array
|
|
|
|
*
|
|
|
|
*/}}
|
|
|
|
* Input is a dict containing:
|
|
|
|
|
|
|
|
* * `this_object`: a JSON schema object.
|
|
|
|
|
|
|
|
* * `name`: a name to use for this object in error/warning messages.
|
|
|
|
|
|
|
|
* * `anchor_base`: a prefix to add to the HTML anchors generated for each
|
|
|
|
|
|
|
|
* object. If nil, no anchors are generated.
|
|
|
|
|
|
|
|
* * `all_objects`: the array of object schema definitions so far.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* Returns a dict containing:
|
|
|
|
|
|
|
|
* * `objects`: The array of object schema definitions.
|
|
|
|
|
|
|
|
* * `schema`: An updated copy of the `schema` input (eg, nested `allOf`
|
|
|
|
|
|
|
|
* entries are expanded, and an `anchor` may be added).
|
|
|
|
|
|
|
|
*/
|
|
|
|
{{ define "partials/get-additional-objects" }}
|
|
|
|
{{ define "partials/get-additional-objects" }}
|
|
|
|
{{/* .name is the name of the object for logging purposes */}}
|
|
|
|
/* .name is the name of the object for logging purposes */
|
|
|
|
{{ $name := .name }}
|
|
|
|
{{ $name := .name }}
|
|
|
|
|
|
|
|
|
|
|
|
{{ $all_objects := .all_objects }}
|
|
|
|
{{ $all_objects := .all_objects }}
|
|
|
@ -136,26 +210,25 @@
|
|
|
|
{{ errorf "Invalid call to partials/get-additional-objects: %s is not a map" $name .this_object }}
|
|
|
|
{{ errorf "Invalid call to partials/get-additional-objects: %s is not a map" $name .this_object }}
|
|
|
|
{{ end }}
|
|
|
|
{{ end }}
|
|
|
|
|
|
|
|
|
|
|
|
/* although we expect resolve-allof to be called on the input, resolve-allof does not recurse into
|
|
|
|
/* Although we expect resolve-allof to be called on the input, resolve-allof does not recurse into
|
|
|
|
* nested objects, so we have to call it again.
|
|
|
|
* nested schemas, so we have to call it again.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
{{ $this_object := partial "json-schema/resolve-allof" .this_object }}
|
|
|
|
{{ $this_object := partial "json-schema/resolve-allof" .this_object }}
|
|
|
|
|
|
|
|
|
|
|
|
{{ $more_objects := partial "json-schema/resolve-additional-types" (dict "schema" $this_object "anchor_base" .anchor_base "name" $name) }}
|
|
|
|
{{ $res := partial "resolve-additional-types-inner" (dict "schema" $this_object "anchor_base" .anchor_base "name" $name) }}
|
|
|
|
{{/*
|
|
|
|
{{ range $res.objects }}
|
|
|
|
As far as I know we don't have something like Array.concat(), so add them one at a time
|
|
|
|
|
|
|
|
*/}}
|
|
|
|
|
|
|
|
{{ range $more_objects}}
|
|
|
|
|
|
|
|
{{ $all_objects = $all_objects | append (partial "clean-object" .) }}
|
|
|
|
{{ $all_objects = $all_objects | append (partial "clean-object" .) }}
|
|
|
|
{{ end }}
|
|
|
|
{{ end }}
|
|
|
|
{{ return $all_objects }}
|
|
|
|
{{ return (dict
|
|
|
|
|
|
|
|
"objects" $all_objects
|
|
|
|
|
|
|
|
"schema" $res.schema
|
|
|
|
|
|
|
|
) }}
|
|
|
|
{{ end }}
|
|
|
|
{{ end }}
|
|
|
|
|
|
|
|
|
|
|
|
{{/*
|
|
|
|
/* Only copy the bits of the object that we actually care about.
|
|
|
|
Only copy the bits of the object that we actually care about.
|
|
|
|
* This is needed for uniqify to work - otherwise objects that are the same
|
|
|
|
This is needed for uniqify to work - otherwise objects that are the same
|
|
|
|
* but with (for example) different examples will be considered different.
|
|
|
|
but with (for example) different examples will be considered different.
|
|
|
|
*/
|
|
|
|
*/}}
|
|
|
|
|
|
|
|
{{ define "partials/clean-object" }}
|
|
|
|
{{ define "partials/clean-object" }}
|
|
|
|
{{ return (dict "title" .title "properties" .properties "required" .required "enum" .enum "anchor" .anchor) }}
|
|
|
|
{{ return (dict "title" .title "properties" .properties "required" .required "enum" .enum "anchor" .anchor) }}
|
|
|
|
{{ end }}
|
|
|
|
{{ end }}
|
|
|
|