mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-10 04:20:24 +00:00
Churning through v3 models now.
mutations everywhere, for everyone!
This commit is contained in:
@@ -67,6 +67,16 @@ func (sp *SchemaProxy) Schema() *Schema {
|
||||
return sch
|
||||
}
|
||||
|
||||
// IsReference returns true if the SchemaProxy is a reference to another Schema.
|
||||
func (sp *SchemaProxy) IsReference() bool {
|
||||
return sp.schema.Value.IsSchemaReference()
|
||||
}
|
||||
|
||||
// GetReference returns the location of the $ref if this SchemaProxy is a reference to another Schema.
|
||||
func (sp *SchemaProxy) GetReference() string {
|
||||
return sp.schema.Value.GetSchemaReference()
|
||||
}
|
||||
|
||||
// BuildSchema operates the same way as Schema, except it will return any error along with the *Schema
|
||||
func (sp *SchemaProxy) BuildSchema() (*Schema, error) {
|
||||
schema := sp.Schema()
|
||||
@@ -96,12 +106,23 @@ func (sp *SchemaProxy) MarshalYAML() (interface{}, error) {
|
||||
if sp == nil {
|
||||
return nil, nil
|
||||
}
|
||||
s, err := sp.BuildSchema()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var s *Schema
|
||||
var err error
|
||||
// if this schema isn't a reference, then build it out.
|
||||
if !sp.IsReference() {
|
||||
s, err = sp.BuildSchema()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nb := high.NewNodeBuilder(s, s.low)
|
||||
return nb.Render(), nil
|
||||
} else {
|
||||
// do not build out a reference, just marshal the reference.
|
||||
mp := high.CreateEmptyMapNode()
|
||||
mp.Content = append(mp.Content,
|
||||
high.CreateStringNode("$ref"),
|
||||
high.CreateStringNode(sp.GetReference()))
|
||||
return mp, nil
|
||||
}
|
||||
nb := high.NewNodeBuilder(s, s.low)
|
||||
return nb.Render(), nil
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -211,6 +211,33 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, tag, key string, value any)
|
||||
valueNode = CreateBoolNode("true")
|
||||
break
|
||||
|
||||
case reflect.Int:
|
||||
if value != nil {
|
||||
val := strconv.Itoa(value.(int))
|
||||
valueNode = CreateIntNode(val)
|
||||
} else {
|
||||
return parent
|
||||
}
|
||||
break
|
||||
|
||||
case reflect.Int64:
|
||||
if value != nil {
|
||||
val := strconv.FormatInt(value.(int64), 10)
|
||||
valueNode = CreateIntNode(val)
|
||||
} else {
|
||||
return parent
|
||||
}
|
||||
break
|
||||
|
||||
case reflect.Float64:
|
||||
if value != nil {
|
||||
val := strconv.FormatFloat(value.(float64), 'f', 2, 64)
|
||||
valueNode = CreateFloatNode(val)
|
||||
} else {
|
||||
return parent
|
||||
}
|
||||
break
|
||||
|
||||
case reflect.Map:
|
||||
|
||||
// the keys will be rendered randomly, if we don't find out the original line
|
||||
@@ -239,12 +266,22 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, tag, key string, value any)
|
||||
if pr, ok := gh.(low.HasValueUnTyped); ok {
|
||||
fg := reflect.ValueOf(pr.GetValueUntyped())
|
||||
for _, ky := range fg.MapKeys() {
|
||||
er := ky.Interface().(low.HasKeyNode).GetKeyNode().Value
|
||||
if er == x {
|
||||
if we, wok := ky.Interface().(low.HasKeyNode); wok {
|
||||
er := we.GetKeyNode().Value
|
||||
if er == x {
|
||||
orderedCollection = append(orderedCollection, &NodeEntry{
|
||||
Tag: x,
|
||||
Key: x,
|
||||
Line: we.GetKeyNode().Line,
|
||||
Value: m.MapIndex(k).Interface(),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// this is a map, without any low level details available
|
||||
orderedCollection = append(orderedCollection, &NodeEntry{
|
||||
Tag: x,
|
||||
Key: x,
|
||||
Line: ky.Interface().(low.HasKeyNode).GetKeyNode().Line,
|
||||
Line: 9999,
|
||||
Value: m.MapIndex(k).Interface(),
|
||||
})
|
||||
}
|
||||
@@ -296,7 +333,11 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, tag, key string, value any)
|
||||
for _, cv := range orderedCollection {
|
||||
n.AddYAMLNode(p, cv.Tag, cv.Key, cv.Value)
|
||||
}
|
||||
valueNode = p
|
||||
if len(p.Content) > 0 {
|
||||
valueNode = p
|
||||
} else {
|
||||
return parent
|
||||
}
|
||||
|
||||
case reflect.Slice:
|
||||
if vo.IsNil() {
|
||||
@@ -383,6 +424,24 @@ func CreateBoolNode(str string) *yaml.Node {
|
||||
return n
|
||||
}
|
||||
|
||||
func CreateIntNode(str string) *yaml.Node {
|
||||
n := &yaml.Node{
|
||||
Kind: yaml.ScalarNode,
|
||||
Tag: "!!int",
|
||||
Value: str,
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func CreateFloatNode(str string) *yaml.Node {
|
||||
n := &yaml.Node{
|
||||
Kind: yaml.ScalarNode,
|
||||
Tag: "!!float",
|
||||
Value: str,
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
type Renderable interface {
|
||||
MarshalYAML() (interface{}, error)
|
||||
}
|
||||
|
||||
@@ -22,26 +22,26 @@ type Document struct {
|
||||
|
||||
// Version is the version of OpenAPI being used, extracted from the 'openapi: x.x.x' definition.
|
||||
// This is not a standard property of the OpenAPI model, it's a convenience mechanism only.
|
||||
Version string
|
||||
Version string `json:"openapi,omitempty" yaml:"openapi,omitempty"`
|
||||
|
||||
// Info represents a specification Info definitions
|
||||
// Provides metadata about the API. The metadata MAY be used by tooling as required.
|
||||
// - https://spec.openapis.org/oas/v3.1.0#info-object
|
||||
Info *base.Info
|
||||
Info *base.Info `json:"info,omitempty" yaml:"info,omitempty"`
|
||||
|
||||
// Servers is a slice of Server instances which provide connectivity information to a target server. If the servers
|
||||
// property is not provided, or is an empty array, the default value would be a Server Object with a url value of /.
|
||||
// - https://spec.openapis.org/oas/v3.1.0#server-object
|
||||
Servers []*Server
|
||||
Servers []*Server `json:"servers,omitempty" yaml:"servers,omitempty"`
|
||||
|
||||
// Paths contains all the PathItem definitions for the specification.
|
||||
// The available paths and operations for the API, The most important part of ths spec.
|
||||
// - https://spec.openapis.org/oas/v3.1.0#paths-object
|
||||
Paths *Paths
|
||||
Paths *Paths `json:"-" yaml:"-"`
|
||||
|
||||
// Components is an element to hold various schemas for the document.
|
||||
// - https://spec.openapis.org/oas/v3.1.0#components-object
|
||||
Components *Components
|
||||
Components *Components `json:"-" yaml:"-"`
|
||||
|
||||
// Security contains global security requirements/roles for the specification
|
||||
// A declaration of which security mechanisms can be used across the API. The list of values includes alternative
|
||||
@@ -49,7 +49,7 @@ type Document struct {
|
||||
// to authorize a request. Individual operations can override this definition. To make security optional,
|
||||
// an empty security requirement ({}) can be included in the array.
|
||||
// - https://spec.openapis.org/oas/v3.1.0#security-requirement-object
|
||||
Security []*base.SecurityRequirement
|
||||
Security []*base.SecurityRequirement `json:"security,omitempty" yaml:"security,omitempty"`
|
||||
|
||||
// Tags is a slice of base.Tag instances defined by the specification
|
||||
// A list of tags used by the document with additional metadata. The order of the tags can be used to reflect on
|
||||
@@ -57,20 +57,20 @@ type Document struct {
|
||||
// The tags that are not declared MAY be organized randomly or based on the tools’ logic.
|
||||
// Each tag name in the list MUST be unique.
|
||||
// - https://spec.openapis.org/oas/v3.1.0#tag-object
|
||||
Tags []*base.Tag
|
||||
Tags []*base.Tag `json:"tags,omitempty" yaml:"tags,omitempty"`
|
||||
|
||||
// ExternalDocs is an instance of base.ExternalDoc for.. well, obvious really, innit.
|
||||
// - https://spec.openapis.org/oas/v3.1.0#external-documentation-object
|
||||
ExternalDocs *base.ExternalDoc
|
||||
ExternalDocs *base.ExternalDoc `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
|
||||
|
||||
// Extensions contains all custom extensions defined for the top-level document.
|
||||
Extensions map[string]any
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
|
||||
// JsonSchemaDialect is a 3.1+ property that sets the dialect to use for validating *base.Schema definitions
|
||||
// The default value for the $schema keyword within Schema Objects contained within this OAS document.
|
||||
// This MUST be in the form of a URI.
|
||||
// - https://spec.openapis.org/oas/v3.1.0#schema-object
|
||||
JsonSchemaDialect string
|
||||
JsonSchemaDialect string `json:"$schema,omitempty" yaml:"$schema,omitempty"`
|
||||
|
||||
// Webhooks is a 3.1+ property that is similar to callbacks, except, this defines incoming webhooks.
|
||||
// The incoming webhooks that MAY be received as part of this API and that the API consumer MAY choose to implement.
|
||||
@@ -78,15 +78,15 @@ type Document struct {
|
||||
// for example by an out-of-band registration. The key name is a unique string to refer to each webhook,
|
||||
// while the (optionally referenced) Path Item Object describes a request that may be initiated by the API provider
|
||||
// and the expected responses. An example is available.
|
||||
Webhooks map[string]*PathItem
|
||||
Webhooks map[string]*PathItem `json:"-" yaml:"-"`
|
||||
|
||||
// Index is a reference to the *index.SpecIndex that was created for the document and used
|
||||
// as a guide when building out the Document. Ideal if further processing is required on the model and
|
||||
// the original details are required to continue the work.
|
||||
//
|
||||
// This property is not a part of the OpenAPI schema, this is custom to libopenapi.
|
||||
Index *index.SpecIndex
|
||||
low *low.Document
|
||||
Index *index.SpecIndex `json:"-" yaml:"-"`
|
||||
low *low.Document `json:"-" yaml:"-"`
|
||||
}
|
||||
|
||||
// NewDocument will create a new high-level Document from a low-level one.
|
||||
@@ -154,18 +154,9 @@ func (d *Document) Render() ([]byte, error) {
|
||||
|
||||
// MarshalYAML will create a ready to render YAML representation of the Document object.
|
||||
func (d *Document) MarshalYAML() (interface{}, error) {
|
||||
n := high.CreateEmptyMapNode()
|
||||
//high.AddYAMLNode(n, low.SchemaDialectLabel, d.JsonSchemaDialect)
|
||||
//high.AddYAMLNode(n, low.OpenAPILabel, d.Version)
|
||||
//high.AddYAMLNode(n, low.InfoLabel, d.Info)
|
||||
//high.AddYAMLNode(n, low.TagsLabel, d.Tags)
|
||||
//high.AddYAMLNode(n, low.ServersLabel, d.Servers)
|
||||
//high.AddYAMLNode(n, low.SecurityLabel, d.Security)
|
||||
//high.AddYAMLNode(n, low.ServersLabel, d.Servers)
|
||||
//high.AddYAMLNode(n, low.ExternalDocsLabel, d.ExternalDocs)
|
||||
//high.AddYAMLNode(n, low.PathsLabel, d.Paths)
|
||||
//high.AddYAMLNode(n, low.ComponentsLabel, d.Components)
|
||||
//high.AddYAMLNode(n, low.WebhooksLabel, d.Webhooks)
|
||||
//high.MarshalExtensions(n, d.Extensions)
|
||||
return n, nil
|
||||
if d == nil {
|
||||
return nil, nil
|
||||
}
|
||||
nb := high.NewNodeBuilder(d, d.low)
|
||||
return nb.Render(), nil
|
||||
}
|
||||
|
||||
@@ -485,9 +485,10 @@ func TestDocument_MarshalYAML(t *testing.T) {
|
||||
r, _ := h.Render()
|
||||
|
||||
info, _ := datamodel.ExtractSpecInfo(r)
|
||||
lowDoc, _ = lowv3.CreateDocumentFromConfig(info, datamodel.NewOpenDocumentConfiguration())
|
||||
highDoc := NewDocument(lowDoc)
|
||||
lDoc, e := lowv3.CreateDocumentFromConfig(info, datamodel.NewOpenDocumentConfiguration())
|
||||
assert.Nil(t, e)
|
||||
|
||||
highDoc := NewDocument(lDoc)
|
||||
assert.Equal(t, "3.1.0", highDoc.Version)
|
||||
|
||||
// TODO: COMPLETE THIS
|
||||
|
||||
@@ -6,6 +6,7 @@ package v3
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/high"
|
||||
low "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Link represents a high-level OpenAPI 3+ Link object that is backed by a low-level one.
|
||||
@@ -21,13 +22,13 @@ import (
|
||||
// in an operation and using them as parameters while invoking the linked operation.
|
||||
// - https://spec.openapis.org/oas/v3.1.0#link-object
|
||||
type Link struct {
|
||||
OperationRef string
|
||||
OperationId string
|
||||
Parameters map[string]string
|
||||
RequestBody string
|
||||
Description string
|
||||
Server *Server
|
||||
Extensions map[string]any
|
||||
OperationRef string `json:"operationRef,omitempty" yaml:"operationRef,omitempty"`
|
||||
OperationId string `json:"operationId,omitempty" yaml:"operationId,omitempty"`
|
||||
Parameters map[string]string `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
||||
RequestBody string `json:"requestBody,omitempty" yaml:"requestBody,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Server *Server `json:"server,omitempty" yaml:"server,omitempty"`
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
low *low.Link
|
||||
}
|
||||
|
||||
@@ -55,3 +56,17 @@ func NewLink(link *low.Link) *Link {
|
||||
func (l *Link) GoLow() *low.Link {
|
||||
return l.low
|
||||
}
|
||||
|
||||
// Render will return a YAML representation of the Link object as a byte slice.
|
||||
func (l *Link) Render() ([]byte, error) {
|
||||
return yaml.Marshal(l)
|
||||
}
|
||||
|
||||
// MarshalYAML will create a ready to render YAML representation of the Link object.
|
||||
func (l *Link) MarshalYAML() (interface{}, error) {
|
||||
if l == nil {
|
||||
return nil, nil
|
||||
}
|
||||
nb := high.NewNodeBuilder(l, l.low)
|
||||
return nb.Render(), nil
|
||||
}
|
||||
37
datamodel/high/v3/link_test.go
Normal file
37
datamodel/high/v3/link_test.go
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright 2023 Princess B33f Heavy Industries / Dave Shanley
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v3
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLink_MarshalYAML(t *testing.T) {
|
||||
link := Link{
|
||||
OperationRef: "somewhere",
|
||||
OperationId: "somewhereOutThere",
|
||||
Parameters: map[string]string{
|
||||
"over": "theRainbow",
|
||||
},
|
||||
RequestBody: "hello?",
|
||||
Description: "are you there?",
|
||||
Server: &Server{
|
||||
URL: "https://pb33f.io",
|
||||
},
|
||||
}
|
||||
|
||||
dat, _ := link.Render()
|
||||
desired := `operationRef: somewhere
|
||||
operationId: somewhereOutThere
|
||||
parameters:
|
||||
over: theRainbow
|
||||
requestBody: hello?
|
||||
description: are you there?
|
||||
server:
|
||||
url: https://pb33f.io`
|
||||
|
||||
assert.Equal(t, desired, strings.TrimSpace(string(dat)))
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/pb33f/libopenapi/datamodel/high/base"
|
||||
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
|
||||
low "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"gopkg.in/yaml.v3"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@@ -16,11 +17,11 @@ import (
|
||||
// Each Media Type Object provides schema and examples for the media type identified by its key.
|
||||
// - https://spec.openapis.org/oas/v3.1.0#media-type-object
|
||||
type MediaType struct {
|
||||
Schema *base.SchemaProxy
|
||||
Example any
|
||||
Examples map[string]*base.Example
|
||||
Encoding map[string]*Encoding
|
||||
Extensions map[string]any
|
||||
Schema *base.SchemaProxy `json:"schema,omitempty" yaml:"schema,omitempty"`
|
||||
Example any `json:"example,omitempty" yaml:"example,omitempty"`
|
||||
Examples map[string]*base.Example `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||
Encoding map[string]*Encoding `json:"encoding,omitempty" yaml:"encoding,omitempty"`
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
low *low.MediaType
|
||||
}
|
||||
|
||||
@@ -43,6 +44,20 @@ func (m *MediaType) GoLow() *low.MediaType {
|
||||
return m.low
|
||||
}
|
||||
|
||||
// Render will return a YAML representation of the MediaType object as a byte slice.
|
||||
func (m *MediaType) Render() ([]byte, error) {
|
||||
return yaml.Marshal(m)
|
||||
}
|
||||
|
||||
// MarshalYAML will create a ready to render YAML representation of the MediaType object.
|
||||
func (m *MediaType) MarshalYAML() (interface{}, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
nb := high.NewNodeBuilder(m, m.low)
|
||||
return nb.Render(), nil
|
||||
}
|
||||
|
||||
// ExtractContent takes in a complex and hard to navigate low-level content map, and converts it in to a much simpler
|
||||
// and easier to navigate high-level one.
|
||||
func ExtractContent(elements map[lowmodel.KeyReference[string]]lowmodel.ValueReference[*low.MediaType]) map[string]*MediaType {
|
||||
|
||||
49
datamodel/high/v3/media_type_test.go
Normal file
49
datamodel/high/v3/media_type_test.go
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright 2023 Princess B33f Heavy Industries / Dave Shanley
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v3
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMediaType_MarshalYAML(t *testing.T) {
|
||||
// load the petstore spec
|
||||
data, _ := ioutil.ReadFile("../../../test_specs/petstorev3.json")
|
||||
info, _ := datamodel.ExtractSpecInfo(data)
|
||||
var err []error
|
||||
lowDoc, err = v3.CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{})
|
||||
if err != nil {
|
||||
panic("broken something")
|
||||
}
|
||||
|
||||
// create a new document and extract a media type object from it.
|
||||
d := NewDocument(lowDoc)
|
||||
mt := d.Paths.PathItems["/pet"].Put.RequestBody.Content["application/json"]
|
||||
|
||||
// render out the media type
|
||||
yml, _ := mt.Render()
|
||||
|
||||
// the rendered output should be a ref to the media type.
|
||||
op := `schema:
|
||||
$ref: '#/components/schemas/Pet'`
|
||||
|
||||
assert.Equal(t, op, strings.TrimSpace(string(yml)))
|
||||
|
||||
// modify the media type to have an example
|
||||
mt.Example = "testing a nice mutation"
|
||||
|
||||
op = `example: testing a nice mutation
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'`
|
||||
|
||||
yml, _ = mt.Render()
|
||||
|
||||
assert.Equal(t, op, strings.TrimSpace(string(yml)))
|
||||
|
||||
}
|
||||
@@ -6,16 +6,17 @@ package v3
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/high"
|
||||
low "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// OAuthFlow represents a high-level OpenAPI 3+ OAuthFlow object that is backed by a low-level one.
|
||||
// - https://spec.openapis.org/oas/v3.1.0#oauth-flow-object
|
||||
type OAuthFlow struct {
|
||||
AuthorizationUrl string
|
||||
TokenUrl string
|
||||
RefreshUrl string
|
||||
Scopes map[string]string
|
||||
Extensions map[string]any
|
||||
AuthorizationUrl string `json:"authorizationUrl,omitempty" yaml:"authorizationUrl,omitempty"`
|
||||
TokenUrl string `json:"tokenUrl,omitempty" yaml:"tokenUrl,omitempty"`
|
||||
RefreshUrl string `json:"refreshUrl,omitempty" yaml:"refreshUrl,omitempty"`
|
||||
Scopes map[string]string `json:"scopes,omitempty" yaml:"scopes,omitempty"`
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
low *low.OAuthFlow
|
||||
}
|
||||
|
||||
@@ -39,3 +40,17 @@ func NewOAuthFlow(flow *low.OAuthFlow) *OAuthFlow {
|
||||
func (o *OAuthFlow) GoLow() *low.OAuthFlow {
|
||||
return o.low
|
||||
}
|
||||
|
||||
// Render will return a YAML representation of the OAuthFlow object as a byte slice.
|
||||
func (o *OAuthFlow) Render() ([]byte, error) {
|
||||
return yaml.Marshal(o)
|
||||
}
|
||||
|
||||
// MarshalYAML will create a ready to render YAML representation of the OAuthFlow object.
|
||||
func (o *OAuthFlow) MarshalYAML() (interface{}, error) {
|
||||
if o == nil {
|
||||
return nil, nil
|
||||
}
|
||||
nb := high.NewNodeBuilder(o, o.low)
|
||||
return nb.Render(), nil
|
||||
}
|
||||
|
||||
44
datamodel/high/v3/oauth_flow_test.go
Normal file
44
datamodel/high/v3/oauth_flow_test.go
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright 2023 Princess B33f Heavy Industries / Dave Shanley
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v3
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestOAuthFlow_MarshalYAML(t *testing.T) {
|
||||
|
||||
oflow := &OAuthFlow{
|
||||
AuthorizationUrl: "https://pb33f.io",
|
||||
TokenUrl: "https://pb33f.io/token",
|
||||
RefreshUrl: "https://pb33f.io/refresh",
|
||||
Scopes: map[string]string{"chicken": "nuggets", "beefy": "soup"},
|
||||
}
|
||||
|
||||
rend, _ := oflow.Render()
|
||||
|
||||
desired := `authorizationUrl: https://pb33f.io
|
||||
tokenUrl: https://pb33f.io/token
|
||||
refreshUrl: https://pb33f.io/refresh
|
||||
scopes:
|
||||
chicken: nuggets
|
||||
beefy: soup`
|
||||
|
||||
assert.Equal(t, desired, strings.TrimSpace(string(rend)))
|
||||
|
||||
// mutate
|
||||
oflow.Scopes = nil
|
||||
oflow.Extensions = map[string]interface{}{"x-burgers": "why not?"}
|
||||
|
||||
desired = `authorizationUrl: https://pb33f.io
|
||||
tokenUrl: https://pb33f.io/token
|
||||
refreshUrl: https://pb33f.io/refresh
|
||||
x-burgers: why not?`
|
||||
|
||||
rend, _ = oflow.Render()
|
||||
assert.Equal(t, desired, strings.TrimSpace(string(rend)))
|
||||
|
||||
}
|
||||
@@ -6,15 +6,16 @@ package v3
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/high"
|
||||
low "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Server represents a high-level OpenAPI 3+ Server object, that is backed by a low level one.
|
||||
// - https://spec.openapis.org/oas/v3.1.0#server-object
|
||||
type Server struct {
|
||||
URL string
|
||||
Description string
|
||||
Variables map[string]*ServerVariable
|
||||
Extensions map[string]any
|
||||
URL string `json:"url,omitempty" yaml:"url,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Variables map[string]*ServerVariable `json:"variables,omitempty" yaml:"variables,omitempty"`
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
low *low.Server
|
||||
}
|
||||
|
||||
@@ -37,3 +38,17 @@ func NewServer(server *low.Server) *Server {
|
||||
func (s *Server) GoLow() *low.Server {
|
||||
return s.low
|
||||
}
|
||||
|
||||
// Render will return a YAML representation of the Server object as a byte slice.
|
||||
func (s *Server) Render() ([]byte, error) {
|
||||
return yaml.Marshal(s)
|
||||
}
|
||||
|
||||
// MarshalYAML will create a ready to render YAML representation of the Server object.
|
||||
func (s *Server) MarshalYAML() (interface{}, error) {
|
||||
if s == nil {
|
||||
return nil, nil
|
||||
}
|
||||
nb := high.NewNodeBuilder(s, s.low)
|
||||
return nb.Render(), nil
|
||||
}
|
||||
43
datamodel/high/v3/server_test.go
Normal file
43
datamodel/high/v3/server_test.go
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright 2023 Princess B33f Heavy Industries / Dave Shanley
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v3
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestServer_MarshalYAML(t *testing.T) {
|
||||
|
||||
server := &Server{
|
||||
URL: "https://pb33f.io",
|
||||
Description: "the b33f",
|
||||
}
|
||||
|
||||
desired := `url: https://pb33f.io
|
||||
description: the b33f`
|
||||
|
||||
rend, _ := server.Render()
|
||||
assert.Equal(t, desired, strings.TrimSpace(string(rend)))
|
||||
|
||||
// mutate
|
||||
server.Variables = map[string]*ServerVariable{
|
||||
"rainbow": {
|
||||
Enum: []string{"one", "two", "three"},
|
||||
},
|
||||
}
|
||||
|
||||
desired = `url: https://pb33f.io
|
||||
description: the b33f
|
||||
variables:
|
||||
rainbow:
|
||||
enum:
|
||||
- one
|
||||
- two
|
||||
- three`
|
||||
|
||||
rend, _ = server.Render()
|
||||
assert.Equal(t, desired, strings.TrimSpace(string(rend)))
|
||||
}
|
||||
@@ -3,16 +3,20 @@
|
||||
|
||||
package v3
|
||||
|
||||
import low "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/high"
|
||||
low "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// ServerVariable represents a high-level OpenAPI 3+ ServerVariable object, that is backed by a low-level one.
|
||||
//
|
||||
// ServerVariable is an object representing a Server Variable for server URL template substitution.
|
||||
// - https://spec.openapis.org/oas/v3.1.0#server-variable-object
|
||||
type ServerVariable struct {
|
||||
Enum []string
|
||||
Default string
|
||||
Description string
|
||||
Enum []string `json:"enum,omitempty" yaml:"enum,omitempty"`
|
||||
Default string `json:"default,omitempty" yaml:"default,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
low *low.ServerVariable
|
||||
}
|
||||
|
||||
@@ -32,7 +36,21 @@ func NewServerVariable(variable *low.ServerVariable) *ServerVariable {
|
||||
return v
|
||||
}
|
||||
|
||||
// GoLow returns the low-level ServerVariable used to to create the high\-level one.
|
||||
// GoLow returns the low-level ServerVariable used to create the high\-level one.
|
||||
func (s *ServerVariable) GoLow() *low.ServerVariable {
|
||||
return s.low
|
||||
}
|
||||
|
||||
// Render will return a YAML representation of the ServerVariable object as a byte slice.
|
||||
func (s *ServerVariable) Render() ([]byte, error) {
|
||||
return yaml.Marshal(s)
|
||||
}
|
||||
|
||||
// MarshalYAML will create a ready to render YAML representation of the ServerVariable object.
|
||||
func (s *ServerVariable) MarshalYAML() (interface{}, error) {
|
||||
if s == nil {
|
||||
return nil, nil
|
||||
}
|
||||
nb := high.NewNodeBuilder(s, s.low)
|
||||
return nb.Render(), nil
|
||||
}
|
||||
43
datamodel/high/v3/server_variable_test.go
Normal file
43
datamodel/high/v3/server_variable_test.go
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright 2023 Princess B33f Heavy Industries / Dave Shanley
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v3
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestServerVariable_MarshalYAML(t *testing.T) {
|
||||
|
||||
svar := &ServerVariable{
|
||||
Enum: []string{"one", "two", "three"},
|
||||
Description: "money day",
|
||||
}
|
||||
|
||||
desired := `enum:
|
||||
- one
|
||||
- two
|
||||
- three
|
||||
description: money day`
|
||||
|
||||
svarRend, _ := svar.Render()
|
||||
|
||||
assert.Equal(t, desired, strings.TrimSpace(string(svarRend)))
|
||||
|
||||
// mutate
|
||||
|
||||
svar.Default = "is moments away"
|
||||
|
||||
desired = `enum:
|
||||
- one
|
||||
- two
|
||||
- three
|
||||
default: is moments away
|
||||
description: money day`
|
||||
|
||||
svarRend, _ = svar.Render()
|
||||
|
||||
assert.Equal(t, desired, strings.TrimSpace(string(svarRend)))
|
||||
}
|
||||
@@ -424,8 +424,6 @@ func (index *SpecIndex) checkPolymorphicNode(name string) (bool, string) {
|
||||
return false, ""
|
||||
}
|
||||
|
||||
|
||||
|
||||
// GetPathCount will return the number of paths found in the spec
|
||||
func (index *SpecIndex) GetPathCount() int {
|
||||
if index.root == nil {
|
||||
|
||||
Reference in New Issue
Block a user