diff --git a/data/custom-formats.yaml b/data/custom-formats.yaml new file mode 100644 index 00000000..84e7c61b --- /dev/null +++ b/data/custom-formats.yaml @@ -0,0 +1,33 @@ +# Copyright 2024 Commaille Kévin +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# The list of custom formats supported for the `format` key and the +# `x-pattern-format` extension (see `openapi_extensions.md` for more details). +# +# Each entry must use the `mx-` prefix and have the form: +# +# mx-custom-key: +# title: The title rendered in the specification +# url: /url/to#definition +# pattern: "REGEX" (not used for rendering, but allows to define the common +# pattern to use for the format) + +mx-user-id: + title: User ID + url: /appendices#user-identifiers + pattern: "^@" +mx-event-id: + title: Event ID + url: /appendices#event-ids + pattern: "^\\$" diff --git a/data/event-schemas/schema/m.ignored_user_list.yaml b/data/event-schemas/schema/m.ignored_user_list.yaml index 32cc6a46..af838490 100644 --- a/data/event-schemas/schema/m.ignored_user_list.yaml +++ b/data/event-schemas/schema/m.ignored_user_list.yaml @@ -17,7 +17,7 @@ properties: "^@": type: "object" description: "An empty object for future enhancement" - x-pattern: "$USER_ID" + x-pattern-format: "mx-user-id" required: - ignored_users type: diff --git a/data/event-schemas/schema/m.receipt.yaml b/data/event-schemas/schema/m.receipt.yaml index 702191d1..23a5d835 100644 --- a/data/event-schemas/schema/m.receipt.yaml +++ b/data/event-schemas/schema/m.receipt.yaml @@ -16,7 +16,7 @@ properties: patternProperties: "^\\$": type: object - x-pattern: "$EVENT_ID" + x-pattern-format: "mx-event-id" title: Event Receipts description: |- The collection of receipts for this event ID. @@ -34,7 +34,7 @@ properties: description: |- The mapping of user ID to receipt. The user ID is the entity who sent this receipt. - x-pattern: "$USER_ID" + x-pattern-format: "mx-user-id" properties: ts: type: integer diff --git a/layouts/partials/openapi/render-object-table.html b/layouts/partials/openapi/render-object-table.html index 030978b1..2647d02f 100644 --- a/layouts/partials/openapi/render-object-table.html +++ b/layouts/partials/openapi/render-object-table.html @@ -179,17 +179,47 @@ {{/* If the property uses `patternProperties` to describe its internal structure, handle this with a bit of recursion. - Note that we ignore the pattern as the current definitions + Types are grouped by pattern format. Note that we ignore + patterns without a format as the current definitions always have a single pattern, but we might need to handle them later to differentiate schemas according to patterns. */}} + + {{/* Use a Scratch to manipulate the map easily. */}} + {{ $scratch := newScratch }} + + {{ range $pattern, $schema := .patternProperties }} + {{ $formatId := "string" }} + {{ with index $schema "x-pattern-format" }} + {{ $formatId = . }} + {{ end }} + + {{/* Initialize the map for the format if it doesn't exist. */}} + {{ if not (reflect.IsSlice ($scratch.Get $formatId)) }} + {{ $scratch.Set $formatId slice }} + {{ end }} + + {{ $scratch.Add $formatId (partial "property-type" $schema) }} + {{ end }} + + {{/* First generate the type string for each format. */}} {{ $types := slice }} + {{ range $formatId, $formatTypes := $scratch.Values }} + {{ $formatKey := "string" }} + {{ if ne $formatId "string" }} + {{ with index site.Data "custom-formats" $formatId }} + {{ $formatKey = printf "%s" (htmlEscape .url) (htmlEscape .title) }} + {{ else }} + {{ errorf "Unsupported value for `x-pattern-format`: %s" $formatId }} + {{ end }} + {{ end }} - {{ range $pattern, $schema := .patternProperties}} - {{ $types = $types | append (partial "property-type" $schema) }} + {{ $formatString := printf "{%s: %s}" $formatKey (delimit $formatTypes "|") }} + {{ $types = $types | append $formatString }} {{ end }} - {{ $type = delimit (slice "{string: " (delimit $types "|") "}" ) "" }} + {{/* Then join all the formats. */}} + {{ $type = delimit $types "|" }} {{ end }} {{ return $type }} diff --git a/openapi_extensions.md b/openapi_extensions.md index 8a7146a9..ee72d47e 100644 --- a/openapi_extensions.md +++ b/openapi_extensions.md @@ -31,3 +31,12 @@ particular Matrix specification versions. Although the OpenAPI/JSON Schema specs only allow to use `$ref` to reference a whole example, we use it to compose examples from other examples. + +## Custom `x-pattern-format` key and custom formats + +In JSON Schema, `format` is a property to convey semantic information about a +schema. We define `x-pattern-format` as a key on the schemas under +`patternProperties` with the same use as `format`, but that applies to the +pattern of the property. We also define custom values for formats with the `mx-` +prefix in `data/custom-formats.yaml`. Those values are recognized in the +rendered specification and link to the definition of the format.