mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-10 04:20:24 +00:00
Added new extraction functions to control extensions
New extraction functions added (that just wrap the old ones). The difference here is that the extensions can be included or ignored now. This has been added to address issue #24 where header keys can in fact include an extension prefix. Signed-off-by: Dave Shanley <dave@quobix.com>
This commit is contained in:
@@ -354,14 +354,15 @@ func ExtractExample(expNode, expLabel *yaml.Node) NodeReference[any] {
|
|||||||
return ref
|
return ref
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExtractMapNoLookup will extract a map of KeyReference and ValueReference from a root yaml.Node. The 'NoLookup' part
|
// ExtractMapNoLookupExtensions will extract a map of KeyReference and ValueReference from a root yaml.Node. The 'NoLookup' part
|
||||||
// refers to the fact that there is no key supplied as part of the extraction, there is no lookup performed and the
|
// refers to the fact that there is no key supplied as part of the extraction, there is no lookup performed and the
|
||||||
// root yaml.Node pointer is used directly.
|
// root yaml.Node pointer is used directly. Pass a true bit to includeExtensions to include extension keys in the map.
|
||||||
//
|
//
|
||||||
// This is useful when the node to be extracted, is already known and does not require a search.
|
// This is useful when the node to be extracted, is already known and does not require a search.
|
||||||
func ExtractMapNoLookup[PT Buildable[N], N any](
|
func ExtractMapNoLookupExtensions[PT Buildable[N], N any](
|
||||||
root *yaml.Node,
|
root *yaml.Node,
|
||||||
idx *index.SpecIndex,
|
idx *index.SpecIndex,
|
||||||
|
includeExtensions bool,
|
||||||
) (map[KeyReference[string]]ValueReference[PT], error) {
|
) (map[KeyReference[string]]ValueReference[PT], error) {
|
||||||
valueMap := make(map[KeyReference[string]]ValueReference[PT])
|
valueMap := make(map[KeyReference[string]]ValueReference[PT])
|
||||||
var circError error
|
var circError error
|
||||||
@@ -369,9 +370,11 @@ func ExtractMapNoLookup[PT Buildable[N], N any](
|
|||||||
var currentKey *yaml.Node
|
var currentKey *yaml.Node
|
||||||
skip := false
|
skip := false
|
||||||
for i, node := range root.Content {
|
for i, node := range root.Content {
|
||||||
if strings.HasPrefix(strings.ToLower(node.Value), "x-") {
|
if !includeExtensions {
|
||||||
skip = true
|
if strings.HasPrefix(strings.ToLower(node.Value), "x-") {
|
||||||
continue
|
skip = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if skip {
|
if skip {
|
||||||
skip = false
|
skip = false
|
||||||
@@ -430,6 +433,19 @@ func ExtractMapNoLookup[PT Buildable[N], N any](
|
|||||||
return valueMap, circError
|
return valueMap, circError
|
||||||
}
|
}
|
||||||
return valueMap, nil
|
return valueMap, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractMapNoLookup will extract a map of KeyReference and ValueReference from a root yaml.Node. The 'NoLookup' part
|
||||||
|
// refers to the fact that there is no key supplied as part of the extraction, there is no lookup performed and the
|
||||||
|
// root yaml.Node pointer is used directly.
|
||||||
|
//
|
||||||
|
// This is useful when the node to be extracted, is already known and does not require a search.
|
||||||
|
func ExtractMapNoLookup[PT Buildable[N], N any](
|
||||||
|
root *yaml.Node,
|
||||||
|
idx *index.SpecIndex,
|
||||||
|
) (map[KeyReference[string]]ValueReference[PT], error) {
|
||||||
|
return ExtractMapNoLookupExtensions[PT, N](root, idx, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
type mappingResult[T any] struct {
|
type mappingResult[T any] struct {
|
||||||
@@ -437,15 +453,17 @@ type mappingResult[T any] struct {
|
|||||||
v ValueReference[T]
|
v ValueReference[T]
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExtractMap will extract a map of KeyReference and ValueReference from a root yaml.Node. The 'label' is
|
// ExtractMapExtensions will extract a map of KeyReference and ValueReference from a root yaml.Node. The 'label' is
|
||||||
// used to locate the node to be extracted from the root node supplied.
|
// used to locate the node to be extracted from the root node supplied. Supply a bit to decide if extensions should
|
||||||
|
// be included or not. required in some use cases.
|
||||||
//
|
//
|
||||||
// The second return value is the yaml.Node found for the 'label' and the third return value is the yaml.Node
|
// The second return value is the yaml.Node found for the 'label' and the third return value is the yaml.Node
|
||||||
// found for the value extracted from the label node.
|
// found for the value extracted from the label node.
|
||||||
func ExtractMap[PT Buildable[N], N any](
|
func ExtractMapExtensions[PT Buildable[N], N any](
|
||||||
label string,
|
label string,
|
||||||
root *yaml.Node,
|
root *yaml.Node,
|
||||||
idx *index.SpecIndex,
|
idx *index.SpecIndex,
|
||||||
|
extensions bool,
|
||||||
) (map[KeyReference[string]]ValueReference[PT], *yaml.Node, *yaml.Node, error) {
|
) (map[KeyReference[string]]ValueReference[PT], *yaml.Node, *yaml.Node, error) {
|
||||||
//var isReference bool
|
//var isReference bool
|
||||||
var referenceValue string
|
var referenceValue string
|
||||||
@@ -547,8 +565,10 @@ func ExtractMap[PT Buildable[N], N any](
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(currentLabelNode.Value, "x-") {
|
if !extensions {
|
||||||
continue // yo, don't pay any attention to extensions, not here anyway.
|
if strings.HasPrefix(currentLabelNode.Value, "x-") {
|
||||||
|
continue // yo, don't pay any attention to extensions, not here anyway.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
totalKeys++
|
totalKeys++
|
||||||
go buildMap(currentLabelNode, en, bChan, eChan, referenceValue)
|
go buildMap(currentLabelNode, en, bChan, eChan, referenceValue)
|
||||||
@@ -572,6 +592,19 @@ func ExtractMap[PT Buildable[N], N any](
|
|||||||
return nil, labelNode, valueNode, nil
|
return nil, labelNode, valueNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExtractMap will extract a map of KeyReference and ValueReference from a root yaml.Node. The 'label' is
|
||||||
|
// used to locate the node to be extracted from the root node supplied.
|
||||||
|
//
|
||||||
|
// The second return value is the yaml.Node found for the 'label' and the third return value is the yaml.Node
|
||||||
|
// found for the value extracted from the label node.
|
||||||
|
func ExtractMap[PT Buildable[N], N any](
|
||||||
|
label string,
|
||||||
|
root *yaml.Node,
|
||||||
|
idx *index.SpecIndex,
|
||||||
|
) (map[KeyReference[string]]ValueReference[PT], *yaml.Node, *yaml.Node, error) {
|
||||||
|
return ExtractMapExtensions[PT, N](label, root, idx, false)
|
||||||
|
}
|
||||||
|
|
||||||
// ExtractExtensions will extract any 'x-' prefixed key nodes from a root node into a map. Requirements have been pre-cast:
|
// ExtractExtensions will extract any 'x-' prefixed key nodes from a root node into a map. Requirements have been pre-cast:
|
||||||
//
|
//
|
||||||
// Maps
|
// Maps
|
||||||
|
|||||||
@@ -973,6 +973,106 @@ one:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestExtractMap_NoLookupWithExtensions(t *testing.T) {
|
||||||
|
|
||||||
|
yml := `components:`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
mErr := yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
assert.NoError(t, mErr)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
yml = `x-hey: you
|
||||||
|
one:
|
||||||
|
x-choo: choo`
|
||||||
|
|
||||||
|
var cNode yaml.Node
|
||||||
|
e := yaml.Unmarshal([]byte(yml), &cNode)
|
||||||
|
assert.NoError(t, e)
|
||||||
|
|
||||||
|
things, err := ExtractMapNoLookupExtensions[*test_Good](cNode.Content[0], idx, true)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, things, 2)
|
||||||
|
|
||||||
|
for k, v := range things {
|
||||||
|
if k.Value == "x-hey" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
assert.Equal(t, "one", k.Value)
|
||||||
|
assert.Len(t, v.ValueNode.Content, 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExtractMap_NoLookupWithoutExtensions(t *testing.T) {
|
||||||
|
|
||||||
|
yml := `components:`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
mErr := yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
assert.NoError(t, mErr)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
yml = `x-hey: you
|
||||||
|
one:
|
||||||
|
x-choo: choo`
|
||||||
|
|
||||||
|
var cNode yaml.Node
|
||||||
|
e := yaml.Unmarshal([]byte(yml), &cNode)
|
||||||
|
assert.NoError(t, e)
|
||||||
|
|
||||||
|
things, err := ExtractMapNoLookupExtensions[*test_Good](cNode.Content[0], idx, false)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, things, 1)
|
||||||
|
|
||||||
|
for k, _ := range things {
|
||||||
|
assert.Equal(t, "one", k.Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExtractMap_WithExtensions(t *testing.T) {
|
||||||
|
|
||||||
|
yml := `components:`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
mErr := yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
assert.NoError(t, mErr)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
yml = `x-hey: you
|
||||||
|
one:
|
||||||
|
x-choo: choo`
|
||||||
|
|
||||||
|
var cNode yaml.Node
|
||||||
|
e := yaml.Unmarshal([]byte(yml), &cNode)
|
||||||
|
assert.NoError(t, e)
|
||||||
|
|
||||||
|
things, _, _, err := ExtractMapExtensions[*test_Good]("one", cNode.Content[0], idx, true)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, things, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExtractMap_WithoutExtensions(t *testing.T) {
|
||||||
|
|
||||||
|
yml := `components:`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
mErr := yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
assert.NoError(t, mErr)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
yml = `x-hey: you
|
||||||
|
one:
|
||||||
|
x-choo: choo`
|
||||||
|
|
||||||
|
var cNode yaml.Node
|
||||||
|
e := yaml.Unmarshal([]byte(yml), &cNode)
|
||||||
|
assert.NoError(t, e)
|
||||||
|
|
||||||
|
things, _, _, err := ExtractMapExtensions[*test_Good]("one", cNode.Content[0], idx, false)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, things, 0)
|
||||||
|
}
|
||||||
|
|
||||||
func TestExtractMapFlatNoLookup_Ref(t *testing.T) {
|
func TestExtractMapFlatNoLookup_Ref(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import (
|
|||||||
//
|
//
|
||||||
// Describes a single response from an API Operation, including design-time, static links to
|
// Describes a single response from an API Operation, including design-time, static links to
|
||||||
// operations based on the response.
|
// operations based on the response.
|
||||||
// - https://spec.openapis.org/oas/v3.1.0#response-object
|
// - https://spec.openapis.org/oas/v3.1.0#response-object
|
||||||
type Response struct {
|
type Response struct {
|
||||||
Description low.NodeReference[string]
|
Description low.NodeReference[string]
|
||||||
Headers low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Header]]
|
Headers low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Header]]
|
||||||
@@ -58,7 +58,7 @@ func (r *Response) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
|||||||
r.Extensions = low.ExtractExtensions(root)
|
r.Extensions = low.ExtractExtensions(root)
|
||||||
|
|
||||||
//extract headers
|
//extract headers
|
||||||
headers, lN, kN, err := low.ExtractMap[*Header](HeadersLabel, root, idx)
|
headers, lN, kN, err := low.ExtractMapExtensions[*Header](HeadersLabel, root, idx, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ default:
|
|||||||
assert.Equal(t, "c009b2046101bc03df802b4cf23f78176931137e6115bf7b445ca46856c06b51",
|
assert.Equal(t, "c009b2046101bc03df802b4cf23f78176931137e6115bf7b445ca46856c06b51",
|
||||||
low.GenerateHashString(&n))
|
low.GenerateHashString(&n))
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestResponses_NoDefault(t *testing.T) {
|
func TestResponses_NoDefault(t *testing.T) {
|
||||||
@@ -217,6 +216,30 @@ func TestResponses_Build_FailBadLinks(t *testing.T) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestResponses_Build_AllowXPrefixHeader(t *testing.T) {
|
||||||
|
|
||||||
|
yml := `"200":
|
||||||
|
headers:
|
||||||
|
x-header1:
|
||||||
|
schema:
|
||||||
|
type: string`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Responses
|
||||||
|
err := low.BuildModel(&idxNode, &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, "string",
|
||||||
|
n.FindResponseByCode("200").Value.FindHeader("x-header1").Value.Schema.Value.Schema().Type.Value.A)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func TestResponse_Hash(t *testing.T) {
|
func TestResponse_Hash(t *testing.T) {
|
||||||
|
|
||||||
yml := `description: nice toast
|
yml := `description: nice toast
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import (
|
|||||||
//
|
//
|
||||||
// The Responses Object MUST contain at least one response code, and if only one response code is provided it SHOULD
|
// The Responses Object MUST contain at least one response code, and if only one response code is provided it SHOULD
|
||||||
// be the response for a successful operation call.
|
// be the response for a successful operation call.
|
||||||
// - https://spec.openapis.org/oas/v3.1.0#responses-object
|
// - https://spec.openapis.org/oas/v3.1.0#responses-object
|
||||||
//
|
//
|
||||||
// This structure is identical to the v2 version, however they use different response types, hence
|
// This structure is identical to the v2 version, however they use different response types, hence
|
||||||
// the duplication. Perhaps in the future we could use generics here, but for now to keep things
|
// the duplication. Perhaps in the future we could use generics here, but for now to keep things
|
||||||
|
|||||||
Reference in New Issue
Block a user