263 lines
11 KiB
Cheetah
263 lines
11 KiB
Cheetah
{{- /* Determine if Path for requested GVR is at /api or /apis based on emptiness of group */ -}}
|
|
{{- $prefix := (ternary "/api" (join "" "/apis/" $.GVR.Group) (not $.GVR.Group)) -}}
|
|
|
|
{{- /* Search both cluster-scoped and namespaced-scoped paths for the GVR to find its GVK */ -}}
|
|
{{- /* Looks for path /apis/<group>/<version>/<resource> or /apis/<group>/<version>/<version>/namespaces/{namespace}/<resource> */ -}}
|
|
{{- $clusterScopedSearchPath := join "/" $prefix $.GVR.Version $.GVR.Resource -}}
|
|
{{- $namespaceScopedSearchPath := join "/" $prefix $.GVR.Version "namespaces" "\\{namespace\\}" $.GVR.Resource -}}
|
|
{{- $path := or (index $.Document "paths" $clusterScopedSearchPath) (index $.Document "paths" $clusterScopedSearchPath) -}}
|
|
|
|
{{- /* Pull GVK from operation */ -}}
|
|
{{- with $gvk := and $path (index $path "get" "x-kubernetes-group-version-kind") -}}
|
|
{{- if $gvk.group -}}
|
|
GROUP: {{ $gvk.group }}{{"\n" -}}
|
|
{{- end -}}
|
|
KIND: {{ $gvk.kind}}{{"\n" -}}
|
|
VERSION: {{ $gvk.version }}{{"\n" -}}
|
|
{{- "\n" -}}
|
|
|
|
{{- with include "schema" (dict "gvk" $gvk "Document" $.Document "FieldPath" $.FieldPath "Recursive" $.Recursive) -}}
|
|
{{- . -}}
|
|
{{- else -}}
|
|
{{- throw "error: GVK %v not found in OpenAPI schema" $gvk -}}
|
|
{{- end -}}
|
|
{{- else -}}
|
|
{{- throw "error: GVR (%v) not found in OpenAPI schema" $.GVR.String -}}
|
|
{{- end -}}
|
|
{{- "\n" -}}
|
|
|
|
{{- /*
|
|
Finds a schema with the given GVK and prints its explain output or empty string
|
|
if GVK was not found
|
|
|
|
Takes dictionary as argument with keys:
|
|
gvk: openapiv3 JSON schema
|
|
Document: entire doc
|
|
FieldPath: field path to follow
|
|
Recursive: print recursive
|
|
*/ -}}
|
|
{{- define "schema" -}}
|
|
{{- /* Find definition with this GVK by filtering out the components/schema with the given x-kubernetes-group-version-kind */ -}}
|
|
{{- range index $.Document "components" "schemas" -}}
|
|
{{- if contains (index . "x-kubernetes-group-version-kind") $.gvk -}}
|
|
{{- with include "output" (set $ "schema" .) -}}
|
|
{{- . -}}
|
|
{{- else -}}
|
|
{{- $fieldName := (index $.FieldPath (sub (len $.FieldPath) 1)) -}}
|
|
{{- throw "error: field \"%v\" does not exist" $fieldName}}
|
|
{{- end -}}
|
|
{{- break -}}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
|
|
{{- /*
|
|
Follows FieldPath until the FieldPath is empty. Then prints field name and field
|
|
list of resultant schema. If field path is not found. Prints nothing.
|
|
Example output:
|
|
|
|
FIELD: spec
|
|
|
|
DESCRIPTION:
|
|
<template "description">
|
|
|
|
FIELDS:
|
|
<template "fieldList">
|
|
|
|
Takes dictionary as argument with keys:
|
|
schema: openapiv3 JSON schema
|
|
history: map[string]int
|
|
Document: entire doc
|
|
FieldPath: field path to follow
|
|
Recursive: print recursive
|
|
*/ -}}
|
|
{{- define "output" -}}
|
|
{{- $refString := or (index $.schema "$ref") "" -}}
|
|
{{- $nextContext := set $ "history" (set $.history $refString 1) -}}
|
|
{{- $resolved := or (resolveRef $refString $.Document) $.schema -}}
|
|
{{- if not $.FieldPath -}}
|
|
DESCRIPTION:{{- "\n" -}}
|
|
{{- or (include "description" (dict "schema" $resolved "Document" $.Document)) "<empty>" | wrap 76 | indent 4 -}}{{- "\n" -}}
|
|
{{- with include "fieldList" (dict "schema" $resolved "level" 1 "Document" $.Document "Recursive" $.Recursive) -}}
|
|
FIELDS:{{- "\n" -}}
|
|
{{- . -}}
|
|
{{- end -}}
|
|
{{- else if and $refString (index $.history $refString) -}}
|
|
{{- /* Stop and do nothing. Hit a cycle */ -}}
|
|
{{- else if and $resolved.properties (index $resolved.properties (first $.FieldPath)) -}}
|
|
{{- /* Schema has this property directly. Traverse to next schema */ -}}
|
|
{{- $subschema := index $resolved.properties (first $.FieldPath) -}}
|
|
{{- if eq 1 (len $.FieldPath) -}}
|
|
{{- /* TODO: The original explain would say RESOURCE instead of FIELD here under some circumstances */ -}}
|
|
FIELD: {{first $.FieldPath}} <{{ template "typeGuess" (dict "schema" $subschema "Document" $.Document) }}>{{"\n"}}
|
|
{{- "\n" -}}
|
|
{{- end -}}
|
|
{{- template "output" (set $nextContext "history" (dict) "FieldPath" (slice $.FieldPath 1) "schema" $subschema ) -}}
|
|
{{- else if $resolved.items -}}
|
|
{{- /* If the schema is an array then traverse the array item fields */ -}}
|
|
{{- template "output" (set $nextContext "schema" $resolved.items) -}}
|
|
{{- else if $resolved.additionalProperties -}}
|
|
{{- /* If the schema is a map then traverse the map item fields */ -}}
|
|
{{- template "output" (set $nextContext "schema" $resolved.additionalProperties) -}}
|
|
{{- else -}}
|
|
{{- /* Last thing to try is all the alternatives in the allOf case */ -}}
|
|
{{- /* Stop when one of the alternatives has an output at all */ -}}
|
|
{{- range $index, $subschema := $resolved.allOf -}}
|
|
{{- with include "output" (set $nextContext "schema" $subschema) -}}
|
|
{{- . -}}
|
|
{{- break -}}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
|
|
{{- /*
|
|
Prints list of fields of a given open api schema in following form:
|
|
|
|
field1 <type> -required-
|
|
DESCRIPTION
|
|
|
|
field2 <type> -required-
|
|
DESCRIPTION
|
|
|
|
or if Recursive is enabled:
|
|
field1 <type> -required-
|
|
subfield1 <type>
|
|
subsubfield1 <type>
|
|
subsubfield2 <type>
|
|
subfield2 <type>
|
|
field2 <type> -required-
|
|
subfield1 <type>
|
|
subfield2 <type>
|
|
|
|
Follows refs for field traversal. If there are cycles in the schema, they are
|
|
detected and traversal ends.
|
|
|
|
Takes dictionary as argument with keys:
|
|
schema: openapiv3 JSON schema
|
|
level: indentation level
|
|
history: map[string]int containing all ref names so far
|
|
Document: entire doc
|
|
Recursive: print recursive
|
|
*/ -}}
|
|
{{- define "fieldList" -}}
|
|
{{- /* Resolve schema if it is a ref */}}
|
|
{{- /* If this is a ref seen before, then ignore it */}}
|
|
{{- $refString := or (index $.schema "$ref") "" }}
|
|
{{- if and $refString (index (or $.history (dict)) $refString) -}}
|
|
{{- /* Do nothing for cycle */}}
|
|
{{- else -}}
|
|
{{- $nextContext := set $ "history" (set $.history $refString 1) -}}
|
|
{{- $resolved := or (resolveRef $refString $.Document) $.schema -}}
|
|
{{- range $k, $v := $resolved.properties -}}
|
|
{{- template "fieldDetail" (dict "name" $k "schema" $resolved "short" $.Recursive "level" $.level "Document" $.Document) -}}
|
|
{{- if $.Recursive -}}
|
|
{{- /* Check if we already know about this element */}}
|
|
{{- template "fieldList" (set $nextContext "schema" $v "level" (add $.level 1)) -}}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
{{- range $resolved.allOf -}}
|
|
{{- template "fieldList" (set $nextContext "schema" .)}}
|
|
{{- end -}}
|
|
{{- if $resolved.items}}{{- template "fieldList" (set $nextContext "schema" $resolved.items)}}{{end}}
|
|
{{- if $resolved.additionalProperties}}{{- template "fieldList" (set $nextContext "schema" $resolved.additionalProperties)}}{{end}}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
|
|
|
|
{{- /*
|
|
|
|
Prints a single field of the given schema
|
|
Optionally prints in a one-line style
|
|
|
|
Takes dictionary as argument with keys:
|
|
schema: openapiv3 JSON schema which contains the field
|
|
name: name of field
|
|
short: limit printing to a single-line summary
|
|
level: indentation amount
|
|
Document: openapi document
|
|
*/ -}}
|
|
{{- define "fieldDetail" -}}
|
|
{{- $level := or $.level 0 -}}
|
|
{{- $indentAmount := mul $level 2 -}}
|
|
{{- $fieldSchema := index $.schema.properties $.name -}}
|
|
{{- $.name | indent $indentAmount -}}{{"\t"}}<{{ template "typeGuess" (dict "schema" $fieldSchema "Document" $.Document) }}>
|
|
{{- if contains $.schema.required $.name}} -required-{{- end -}}
|
|
{{- "\n" -}}
|
|
{{- if not $.short -}}
|
|
{{- or $fieldSchema.description "<no description>" | wrap (sub 78 $indentAmount) | indent (add $indentAmount 2) -}}{{- "\n" -}}
|
|
{{- "\n" -}}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
|
|
{{- /*
|
|
|
|
Prints the description of the given OpenAPI v3 schema. Also walks through all
|
|
sibling schemas to the provided schema and prints the description of those schemas
|
|
too
|
|
|
|
Takes dictionary as argument with keys:
|
|
schema: openapiv3 JSON schema
|
|
Document: document to resolve refs within
|
|
*/ -}}
|
|
{{- define "description" -}}
|
|
{{- with or (resolveRef (index $.schema "$ref") $.Document) $.schema -}}
|
|
{{- if .description -}}
|
|
{{- .description -}}
|
|
{{- "\n" -}}
|
|
{{- end -}}
|
|
{{- range .allOf -}}
|
|
{{- template "description" (set $ "schema" .)}}
|
|
{{- end -}}
|
|
{{- if .items -}}
|
|
{{- template "description" (set $ "schema" .items) -}}
|
|
{{- end -}}
|
|
{{- if .additionalProperties -}}
|
|
{{- template "description" (set $ "schema" .additionalProperties) -}}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
|
|
{{- /* Renders a shortstring representing an interpretation of what is the "type"
|
|
of a subschema e.g.:
|
|
|
|
`string` `number`, `Object`, `[]Object`, `map[string]string`, etc.
|
|
|
|
Serves as a more helpful type hint than raw typical openapi `type` field
|
|
|
|
Takes dictionary as argument with keys:
|
|
schema: openapiv3 JSON schema
|
|
Document: openapi document
|
|
*/ -}}
|
|
{{- define "typeGuess" -}}
|
|
{{- with $.schema -}}
|
|
{{- if .items -}}
|
|
[]{{template "typeGuess" (set $ "schema" .items)}}
|
|
{{- else if .additionalProperties -}}
|
|
map[string]{{template "typeGuess" (set $ "schema" .additionalProperties)}}
|
|
{{- else if and .allOf (not .properties) (eq (len .allOf) 1) -}}
|
|
{{- /* If allOf has a single element and there are no direct
|
|
properties on the schema, defer to the allOf */ -}}
|
|
{{- template "typeGuess" (set $ "schema" (first .allOf)) -}}
|
|
{{- else if index . "$ref"}}
|
|
{{- /* Parse the #!/components/schemas/io.k8s.Kind string into just the Kind name */ -}}
|
|
{{- $ref := index . "$ref" -}}
|
|
{{- /* Look up ref schema to see primitive type. Only put the ref type name if it is an object. */ -}}
|
|
{{- $refSchema := resolveRef $ref $.Document -}}
|
|
{{- if (or (not $refSchema) (or (not $refSchema.type) (eq $refSchema.type "object"))) -}}
|
|
{{- $name := split $ref "/" | last -}}
|
|
{{- or (split $name "." | last) "Object" -}}
|
|
{{- else if $refSchema.type -}}
|
|
{{- or $refSchema.type "Object" -}}
|
|
{{- else -}}
|
|
{{- or .type "Object" -}}
|
|
{{- end -}}
|
|
{{- else -}}
|
|
{{/* Old explain used capitalized "Object". Just follow suit */}}
|
|
{{- if eq .type "object" -}}Object
|
|
{{- else -}}{{- or .type "Object" -}}{{- end -}}
|
|
{{- end -}}
|
|
{{- else -}}
|
|
{{- fail "expected schema argument to subtemplate 'typeguess'" -}}
|
|
{{- end -}}
|
|
{{- end -}} |