mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-06 12:37:49 +00:00
Added oAuth rendering, updated node builder.
This commit is contained in:
@@ -148,9 +148,13 @@ func (n *NodeBuilder) add(key string) {
|
||||
value = reflect.ValueOf(fLow)
|
||||
switch value.Kind() {
|
||||
case reflect.Struct:
|
||||
nb := value.Interface().(low.HasValueNodeUntyped).GetValueNode()
|
||||
if nb != nil {
|
||||
nodeEntry.Line = nb.Line
|
||||
y := value.Interface()
|
||||
if nb, ok := y.(low.HasValueNodeUntyped); ok {
|
||||
if nb.GetValueNode() != nil {
|
||||
nodeEntry.Line = nb.GetValueNode().Line
|
||||
}
|
||||
} else {
|
||||
panic("not supported yet")
|
||||
}
|
||||
default:
|
||||
// everything else, weight it to the bottom of the rendered object.
|
||||
@@ -265,10 +269,12 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, tag, key string, value any)
|
||||
// extract low level key line number
|
||||
if pr, ok := gh.(low.HasValueUnTyped); ok {
|
||||
fg := reflect.ValueOf(pr.GetValueUntyped())
|
||||
found := false
|
||||
for _, ky := range fg.MapKeys() {
|
||||
if we, wok := ky.Interface().(low.HasKeyNode); wok {
|
||||
er := we.GetKeyNode().Value
|
||||
if er == x {
|
||||
found = true
|
||||
orderedCollection = append(orderedCollection, &NodeEntry{
|
||||
Tag: x,
|
||||
Key: x,
|
||||
@@ -278,6 +284,7 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, tag, key string, value any)
|
||||
}
|
||||
} else {
|
||||
// this is a map, without any low level details available
|
||||
found = true
|
||||
orderedCollection = append(orderedCollection, &NodeEntry{
|
||||
Tag: x,
|
||||
Key: x,
|
||||
@@ -286,10 +293,21 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, tag, key string, value any)
|
||||
})
|
||||
}
|
||||
}
|
||||
if found != true {
|
||||
// this is something new, add it.
|
||||
orderedCollection = append(orderedCollection, &NodeEntry{
|
||||
Tag: x,
|
||||
Key: x,
|
||||
Line: 9999,
|
||||
Value: m.MapIndex(k).Interface(),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// this is a map, without an enclosing struct
|
||||
// this is a map, but it may be wrapped still.
|
||||
bj := reflect.ValueOf(gh)
|
||||
for _, ky := range bj.MapKeys() {
|
||||
yh := bj.Interface()
|
||||
calc := func(iu reflect.Value) {
|
||||
for _, ky := range iu.MapKeys() {
|
||||
er := ky.Interface().(low.HasKeyNode).GetKeyNode().Value
|
||||
if er == x {
|
||||
orderedCollection = append(orderedCollection, &NodeEntry{
|
||||
@@ -301,6 +319,13 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, tag, key string, value any)
|
||||
}
|
||||
}
|
||||
}
|
||||
if vg, jo := yh.(low.HasKeyNode); jo {
|
||||
fv := reflect.ValueOf(vg.GetKeyNode())
|
||||
calc(fv)
|
||||
} else {
|
||||
calc(bj)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// this is a map, without any low level details available (probably an extension map).
|
||||
orderedCollection = append(orderedCollection, &NodeEntry{
|
||||
|
||||
@@ -13,18 +13,18 @@ import (
|
||||
// Header represents a high-level OpenAPI 3+ Header object that is backed by a low-level one.
|
||||
// - https://spec.openapis.org/oas/v3.1.0#header-object
|
||||
type Header struct {
|
||||
Description string
|
||||
Required bool
|
||||
Deprecated bool
|
||||
AllowEmptyValue bool
|
||||
Style string
|
||||
Explode bool
|
||||
AllowReserved bool
|
||||
Schema *highbase.SchemaProxy
|
||||
Example any
|
||||
Examples map[string]*highbase.Example
|
||||
Content map[string]*MediaType
|
||||
Extensions map[string]any
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Required bool `json:"required,omitempty" yaml:"required,omitempty"`
|
||||
Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
|
||||
AllowEmptyValue bool `json:"allowEmptyValue,omitempty" yaml:"allowEmptyValue,omitempty"`
|
||||
Style string `json:"style,omitempty" yaml:"style,omitempty"`
|
||||
Explode bool `json:"explode,omitempty" yaml:"explode,omitempty"`
|
||||
AllowReserved bool `json:"allowReserved,omitempty" yaml:"allowReserved,omitempty"`
|
||||
Schema *highbase.SchemaProxy `json:"schema,omitempty" yaml:"schema,omitempty"`
|
||||
Example any `json:"example,omitempty" yaml:"example,omitempty"`
|
||||
Examples map[string]*highbase.Example `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||
Content map[string]*MediaType `json:"content,omitempty" yaml:"content,omitempty"`
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
low *low.Header
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
// OAuthFlows represents a high-level OpenAPI 3+ OAuthFlows object that is backed by a low-level one.
|
||||
// - https://spec.openapis.org/oas/v3.1.0#oauth-flows-object
|
||||
type OAuthFlows struct {
|
||||
Implicit *OAuthFlow
|
||||
Password *OAuthFlow
|
||||
ClientCredentials *OAuthFlow
|
||||
AuthorizationCode *OAuthFlow
|
||||
Extensions map[string]any
|
||||
Implicit *OAuthFlow `json:"implicit,omitempty" yaml:"implicit,omitempty"`
|
||||
Password *OAuthFlow `json:"password,omitempty" yaml:"password,omitempty"`
|
||||
ClientCredentials *OAuthFlow `json:"clientCredentials,omitempty" yaml:"clientCredentials,omitempty"`
|
||||
AuthorizationCode *OAuthFlow `json:"authorizationCode,omitempty" yaml:"authorizationCode,omitempty"`
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
low *low.OAuthFlows
|
||||
}
|
||||
|
||||
@@ -46,3 +47,18 @@ func NewOAuthFlows(flows *low.OAuthFlows) *OAuthFlows {
|
||||
func (o *OAuthFlows) GoLow() *low.OAuthFlows {
|
||||
return o.low
|
||||
}
|
||||
|
||||
// Render will return a YAML representation of the OAuthFlows object as a byte slice.
|
||||
func (o *OAuthFlows) Render() ([]byte, error) {
|
||||
return yaml.Marshal(o)
|
||||
}
|
||||
|
||||
// MarshalYAML will create a ready to render YAML representation of the OAuthFlows object.
|
||||
func (o *OAuthFlows) MarshalYAML() (interface{}, error) {
|
||||
if o == nil {
|
||||
return nil, nil
|
||||
}
|
||||
nb := high.NewNodeBuilder(o, o.low)
|
||||
return nb.Render(), nil
|
||||
}
|
||||
|
||||
|
||||
@@ -9,32 +9,33 @@ import (
|
||||
"github.com/pb33f/libopenapi/index"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v3"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewOAuthFlows(t *testing.T) {
|
||||
|
||||
yml := `implicit:
|
||||
authorizationUrl: https://pb33f.io/oauth
|
||||
authorizationUrl: https://pb33f.io/oauth/implicit
|
||||
scopes:
|
||||
write:burgers: modify and add new burgers
|
||||
write:burgers: modify and add new burgers implicitly
|
||||
read:burgers: read all burgers
|
||||
authorizationCode:
|
||||
authorizationUrl: https://pb33f.io/oauth
|
||||
authorizationUrl: https://pb33f.io/oauth/authCode
|
||||
tokenUrl: https://api.pb33f.io/oauth/token
|
||||
scopes:
|
||||
write:burgers: modify burgers and stuff
|
||||
write:burgers: modify burgers and stuff with a code
|
||||
read:burgers: read all the burgers
|
||||
password:
|
||||
authorizationUrl: https://pb33f.io/oauth
|
||||
authorizationUrl: https://pb33f.io/oauth/password
|
||||
scopes:
|
||||
write:burgers: modify and add new burgers
|
||||
write:burgers: modify and add new burgers with a password
|
||||
read:burgers: read all burgers
|
||||
clientCredentials:
|
||||
authorizationUrl: https://pb33f.io/oauth
|
||||
authorizationUrl: https://pb33f.io/oauth/clientCreds
|
||||
scopes:
|
||||
write:burgers: modify burgers and stuff
|
||||
read:burgers: read all the burgers `
|
||||
write:burgers: modify burgers and stuff with creds
|
||||
read:burgers: read all the burgers`
|
||||
|
||||
var idxNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||
@@ -52,4 +53,36 @@ clientCredentials:
|
||||
assert.Len(t, r.ClientCredentials.Scopes, 2)
|
||||
assert.Equal(t, 2, r.GoLow().Implicit.Value.AuthorizationUrl.KeyNode.Line)
|
||||
|
||||
// now render it back out, and it should be identical!
|
||||
rBytes, _ := r.Render()
|
||||
assert.Equal(t, yml, strings.TrimSpace(string(rBytes)))
|
||||
|
||||
modified := `implicit:
|
||||
authorizationUrl: https://pb33f.io/oauth/implicit
|
||||
scopes:
|
||||
write:burgers: modify and add new burgers implicitly
|
||||
read:burgers: read all burgers
|
||||
authorizationCode:
|
||||
authorizationUrl: https://pb33f.io/oauth/authCode
|
||||
tokenUrl: https://api.pb33f.io/oauth/token
|
||||
scopes:
|
||||
write:burgers: modify burgers and stuff with a code
|
||||
read:burgers: read all the burgers
|
||||
password:
|
||||
authorizationUrl: https://pb33f.io/oauth/password
|
||||
scopes:
|
||||
write:burgers: modify and add new burgers with a password
|
||||
read:burgers: read all burgers
|
||||
clientCredentials:
|
||||
authorizationUrl: https://pb33f.io/oauth/clientCreds
|
||||
scopes:
|
||||
write:burgers: modify burgers and stuff with creds
|
||||
read:burgers: read all the burgers
|
||||
CHIP:CHOP: microwave a sock`
|
||||
|
||||
// now modify it and render it back out, and it should be identical!
|
||||
r.ClientCredentials.Scopes["CHIP:CHOP"] = "microwave a sock"
|
||||
rBytes, _ = r.Render()
|
||||
assert.Equal(t, modified, strings.TrimSpace(string(rBytes)))
|
||||
|
||||
}
|
||||
|
||||
@@ -386,7 +386,32 @@ func SetField(field *reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) er
|
||||
field.Set(reflect.ValueOf(ref))
|
||||
}
|
||||
}
|
||||
|
||||
case reflect.TypeOf(NodeReference[map[KeyReference[string]]ValueReference[string]]{}):
|
||||
if utils.IsNodeMap(valueNode) {
|
||||
if field.CanSet() {
|
||||
items := make(map[KeyReference[string]]ValueReference[string])
|
||||
var cf *yaml.Node
|
||||
for i, sliceItem := range valueNode.Content {
|
||||
if i%2 == 0 {
|
||||
cf = sliceItem
|
||||
continue
|
||||
}
|
||||
items[KeyReference[string]{
|
||||
Value: cf.Value,
|
||||
KeyNode: cf,
|
||||
}] = ValueReference[string]{
|
||||
Value: sliceItem.Value,
|
||||
ValueNode: sliceItem,
|
||||
}
|
||||
}
|
||||
ref := NodeReference[map[KeyReference[string]]ValueReference[string]]{
|
||||
Value: items,
|
||||
KeyNode: keyNode,
|
||||
ValueNode: valueNode,
|
||||
}
|
||||
field.Set(reflect.ValueOf(ref))
|
||||
}
|
||||
}
|
||||
case reflect.TypeOf(NodeReference[[]ValueReference[string]]{}):
|
||||
|
||||
if utils.IsNodeArray(valueNode) {
|
||||
|
||||
@@ -90,7 +90,7 @@ type OAuthFlow struct {
|
||||
AuthorizationUrl low.NodeReference[string]
|
||||
TokenUrl low.NodeReference[string]
|
||||
RefreshUrl low.NodeReference[string]
|
||||
Scopes low.KeyReference[map[low.KeyReference[string]]low.ValueReference[string]]
|
||||
Scopes low.NodeReference[map[low.KeyReference[string]]low.ValueReference[string]]
|
||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user