From 013b33a3a9f1c1bc14cc4ff747f7b03872a8ab3b Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 13 Mar 2024 13:40:56 +0000 Subject: [PATCH] Add a new `partial` for resolving object refs, properly --- .../partials/json-schema/resolve-refs.html | 8 ++ .../partials/openapi/resolve-ref-object.html | 75 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 layouts/partials/openapi/resolve-ref-object.html diff --git a/layouts/partials/json-schema/resolve-refs.html b/layouts/partials/json-schema/resolve-refs.html index 1d99201db..425e5577d 100644 --- a/layouts/partials/json-schema/resolve-refs.html +++ b/layouts/partials/json-schema/resolve-refs.html @@ -7,6 +7,14 @@ rather than a normal `dict` because with `dict` you can't replace key values: https://discourse.gohugo.io/t/how-can-i-add-set-and-delete-keys-in-a-dictionary/29661 + XXX: This partial should be phased out, and replaced with + `openapi/resolve-ref-object`. OpenAPI 3 doesn't really allow arbitrary JSON + references. As [swagger.io] says: "A common misconception is that `$ref` is + allowed anywhere in an OpenAPI specification file. Actually `$ref` is only + allowed in places where the OpenAPI 3.0 Specification explicitly states that + the value may be a reference." + + [swagger.io]: https://swagger.io/docs/specification/using-ref/#allowed-places */}} {{ $schema := .schema }} diff --git a/layouts/partials/openapi/resolve-ref-object.html b/layouts/partials/openapi/resolve-ref-object.html new file mode 100644 index 000000000..9b38415e5 --- /dev/null +++ b/layouts/partials/openapi/resolve-ref-object.html @@ -0,0 +1,75 @@ +{{/* + +Handles OpenAPI "Reference Objects". + +Reference objects are JSON objects with a single property, `$ref` (and +optionally a `summary` and `description`). This partial resolves the reference +and returns the expanded object. + +The input parameter is a dict with the following keys: + +* `schema`: A schema object to check for $ref properties. + +* `path`: The path of the schema file containing the (potential) ref; used for resolving + relative references. + +* `root_schema`: The top-level schema which contains the potential ref; use for resolving `#/` + references. + +Ref: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#reference-object. + +*/}} + +{{ $schema := .schema }} +{{ $path := .path }} +{{ $root_schema := .root_schema }} + +{{ $ret := $schema }} + +{{ $ref_value := index $schema "$ref"}} +{{ if $ref_value }} + {{ $ref_url := urls.Parse $ref_value }} + + {{ if ne $ref_url.Path "" }} + {{/* Reference to a different file: load it */}} + {{ $full_path := path.Join $path $ref_url.Path }} + {{ $without_ext := replaceRE "\\.[^\\.]*$" "" $full_path }} + {{ $pieces := split $without_ext "/" }} + {{ $ret = index site.Data $pieces }} + {{ else }} + {{ $ret = $root_schema }} + {{ end }} + + {{ if ne $ref_url.Fragment "" }} + {{/* + Per https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#relative-reference s-in-uris: + + > If a URI contains a fragment identifier, then the fragment should + > be resolved per the fragment resolution mechanism of the + > referenced document. If the representation of the referenced + > document is JSON or YAML, then the fragment identifier SHOULD be + > interpreted as a JSON-Pointer as per RFC6901. + + RFC6901, in a nutshell, says the pointer is a series of keys + separated by `/`. We strip off the leading `/` and use the + subsequent keys as indexes. + */}} + + {{ $keys := split (strings.TrimPrefix "/" $ref_url.Fragment ) "/" }} + {{ $ret = index $ret $keys }} + {{ warnf "Ref val %s keys %s ret %s" $ref_value $keys $ret }} + {{ end }} + + {{/* + OpenAPI spec says that "summary" and "description" from the reference object override + the values from the referenced component. + */}} + {{ if isset $schema "summary" }} + {{ $ret = merge $ret (dict "summary" $schema.summary) }} + {{ end }} + {{ if isset $schema "description" }} + {{ $ret = merge $ret (dict "description" $schema.summary) }} + {{ end }} +{{ end }} + +{{ return $ret }}