Include information about additionalProperties in object tables (#1798)

Currently, if we have an object which has additionalProperties in addition to properties, that information gets lost. This PR seeks to address that.
pull/1814/head
Richard van der Hoff 1 month ago committed by GitHub
parent eea3dfa969
commit 48f4c4954f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1 @@
Show information about "Additional Properties" in object tables.

@ -52,7 +52,6 @@ paths:
might be and could be "alpha", semantically versioned, or arbitrary. might be and could be "alpha", semantically versioned, or arbitrary.
required: required:
- version - version
# TODO: TravisR - Make this render
additionalProperties: additionalProperties:
type: object type: object
title: Internationalised Policy title: Internationalised Policy

@ -29,6 +29,8 @@
* *
* * title * * title
* * properties * * properties
* * additionalProperties
* * patternProperties
* * required * * required
* * enum * * enum
* * anchor * * anchor
@ -45,27 +47,31 @@
"schema" .schema "schema" .schema
"anchor_base" .anchor_base "anchor_base" .anchor_base
"name" (.name | default .schema.title | default "<untitled object>") "name" (.name | default .schema.title | default "<untitled object>")
"top_level" true
) }} ) }}
{{ return $res.objects }} {{ return $res.objects }}
/* /*
* A helper for the resolve-additional-types partial. * A helper for the resolve-additional-types partial.
* *
* Takes the same inputs as resolve-additional-types itself, except that `name` is mandatory. * Takes the same inputs as resolve-additional-types itself, except:
* * `name` is mandatory.
* * `top_level`, if set, indicates that this is the top-level object.
* *
* Returns a dict containing: * Returns a dict containing:
* *
* * `objects`: The array of object schema definitions. * * `objects`: The array of object schema definitions.
* *
* * `schema`: An updated copy of the `schema` input (eg, nested `allOf` * * `schema`: An updated copy of the `schema` input (eg, an `anchor` may be added).
* entries are expanded, and an `anchor` may be added). If the input * If the input `schema` was itself an object that we should create a table for,
* `schema` was itself an object, this will be the same as the first entry * this will be the same as the first entry in `objects`.
* in `objects`.
*/ */
{{ define "partials/resolve-additional-types-inner" }} {{ define "partials/resolve-additional-types-inner" }}
{{ $this_object := .schema }} {{ $this_object := .schema }}
{{ $anchor_base := .anchor_base }} {{ $anchor_base := .anchor_base }}
{{ $name := .name }} {{ $name := .name }}
{{ $top_level := .top_level }}
{{ $all_objects := slice }} {{ $all_objects := slice }}
{{ if eq $this_object.type "object" }} {{ if eq $this_object.type "object" }}
@ -126,12 +132,24 @@
{{ $this_object = merge $this_object (dict "properties" $updated_properties) }} {{ $this_object = merge $this_object (dict "properties" $updated_properties) }}
{{ end }} {{ end }}
/* Finally, prepend the updated schema for the top-level object onto the $all_objects array */ /* We'll want to create a table for `$this_object` itself if either:
{{ $tmp := slice $this_object }} *
{{ if $all_objects }} * - The object has some regular properties (not just patternProperties or additionalProperties), or:
{{ $tmp = $tmp | append $all_objects }} * - It is the top-level object. (We use a special format of table for top-level objects that
* only have patternProperties or additionalProperties)
*
* In those cases, prepend the updated schema for the top-level object onto the $all_objects array.
*
* We think about this last so that we can take advantage of any updates to the schema that happened
* above (in particular, addition of `anchor` attributes).
*/
{{ if or $this_object.properties $top_level }}
{{ $tmp := slice $this_object }}
{{ if $all_objects }}
{{ $tmp = $tmp | append $all_objects }}
{{ end }}
{{ $all_objects = $tmp }}
{{ end }} {{ end }}
{{ $all_objects = $tmp }}
{{ end }} {{ end }}
{{ if eq $this_object.type "array" }} {{ if eq $this_object.type "array" }}
@ -198,8 +216,7 @@
* *
* Returns a dict containing: * Returns a dict containing:
* * `objects`: The array of object schema definitions. * * `objects`: The array of object schema definitions.
* * `schema`: An updated copy of the `schema` input (eg, nested `allOf` * * `schema`: An updated copy of the `schema` input (eg, an `anchor` may be added).
* 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 */
@ -211,7 +228,7 @@
{{ 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 }}
{{ $res := partial "resolve-additional-types-inner" (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 "top_level" false) }}
{{ range $res.objects }} {{ range $res.objects }}
{{ $all_objects = $all_objects | append (partial "clean-object" .) }} {{ $all_objects = $all_objects | append (partial "clean-object" .) }}
{{ end }} {{ end }}
@ -226,5 +243,5 @@
* 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 "additionalProperties" .additionalProperties "patternProperties" .patternProperties "required" .required "enum" .enum "anchor" .anchor) }}
{{ end }} {{ end }}

@ -9,11 +9,11 @@
* `properties`: optional dictionary of the properties to list, each given as: * `properties`: optional dictionary of the properties to list, each given as:
`property_name` : `property_data` `property_name` : `property_data`
* `additionalProperties`: optional dictionary for properties with undefined * `additionalProperties`: a JSON Schema for additional properties on the
names, in the same format as `property_data` object.
* `patternProperties`: optional dictionary for properties with names adhering * `patternProperties`: optional dictionary for properties with names adhering
to a regex pattern, in the same format as `property_data` to a regex pattern. A map from regex pattern to JSON Schema.
* `required`: optional array containing the names of required properties. * `required`: optional array containing the names of required properties.
In some cases (such as response body specifications) this isn't used, and In some cases (such as response body specifications) this isn't used, and
@ -26,7 +26,6 @@
{{ $required := .required}} {{ $required := .required}}
{{ if $properties }} {{ if $properties }}
<table{{ if .anchor }} id="{{ .anchor }}"{{ end }} class="object-table"> <table{{ if .anchor }} id="{{ .anchor }}"{{ end }} class="object-table">
{{ with $title }} {{ with $title }}
<caption>{{ . }}</caption> <caption>{{ . }}</caption>
@ -52,9 +51,40 @@
{{ end }} {{ end }}
{{/*
If the object has additional properties *as well as* regular properties, we add a special row to the table.
Note that, per https://json-schema.org/draft/2020-12/json-schema-core#name-boolean-json-schemas, JSON schemas
can be a simple "true" or "false" as well as the more normal object.
`additionalProperties: true` is pretty much the default for Matrix (it means: "you're allowed to include random
unspecced properties in your object"), so nothing to do here.
`additionalProperties: false` means "you're not allowed to include any unspecced properties in your object". We
may want to consider how to display that; for now we just ignore it.
TODO: support `patternProperties` here.
*/}}
{{ if reflect.IsMap .additionalProperties }}
<tr>
<td>&lt;Other properties&gt;</code></td>
<td><code>{{ partial "partials/property-type" .additionalProperties | safeHTML }}</code></td>
<td>{{ partial "partials/property-description" (dict "property" .additionalProperties) }}</td>
</tr>
{{ end }}
</table> </table>
{{ else if (or .additionalProperties .patternProperties) }} {{ else if (or .additionalProperties .patternProperties) }}
{{/*
A special format of table for objects which only have additionalProperties or patternProperties.
This is only ever used for top-level objects. Nested objects in this situation are just shown
as rows within their parent object, and don't get their own table. (They are filtered out in
resolve-additional-types.)
*/}}
<table{{ if .anchor }} id="{{ .anchor }}"{{ end }} class="object-table"> <table{{ if .anchor }} id="{{ .anchor }}"{{ end }} class="object-table">
{{ with $title }} {{ with $title }}
<caption>{{ . }}</caption> <caption>{{ . }}</caption>
@ -116,7 +146,7 @@
{{ else if or (reflect.IsSlice .type) .oneOf }} {{ else if or (reflect.IsSlice .type) .oneOf }}
{{/* {{/*
It's legal to specify an array of types. It's legal to specify an array of types.
There are two ways to do that: There are two ways to do that:
- Use an array of strings. - Use an array of strings.
- Use oneOf, with items having a schema. - Use oneOf, with items having a schema.

Loading…
Cancel
Save