We-worked model to remove resolver.

lookups are performed inline now. keeps things simpler, however it has a performance knock, so it's time to refine async building were possible.
This commit is contained in:
Dave Shanley
2022-08-11 14:54:25 -04:00
parent 7f0e966bd3
commit 248b4daa80
28 changed files with 462 additions and 279 deletions

View File

@@ -2,6 +2,8 @@ package v3
import ( import (
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@@ -14,22 +16,28 @@ func (cb *Callback) FindExpression(exp string) *low.ValueReference[*PathItem] {
return FindItemInMap[*PathItem](exp, cb.Expression.Value) return FindItemInMap[*PathItem](exp, cb.Expression.Value)
} }
func (cb *Callback) Build(root *yaml.Node) error { func (cb *Callback) Build(root *yaml.Node, idx *index.SpecIndex) error {
extensionMap, err := ExtractExtensions(root) cb.Extensions = ExtractExtensions(root)
if err != nil {
return err
}
cb.Extensions = extensionMap
// handle callback // handle callback
var currentCB *yaml.Node var currentCB *yaml.Node
callbacks := make(map[low.KeyReference[string]]low.ValueReference[*PathItem]) callbacks := make(map[low.KeyReference[string]]low.ValueReference[*PathItem])
if ok, _, _ := utils.IsNodeRefValue(root); ok {
r := LocateRefNode(root, idx)
if r != nil {
root = r
} else {
return nil
}
}
for i, callbackNode := range root.Content { for i, callbackNode := range root.Content {
if i%2 == 0 { if i%2 == 0 {
currentCB = callbackNode currentCB = callbackNode
continue continue
} }
callback, eErr := ExtractObjectRaw[*PathItem](callbackNode) callback, eErr := ExtractObjectRaw[*PathItem](callbackNode, idx)
if eErr != nil { if eErr != nil {
return eErr return eErr
} }

View File

@@ -0,0 +1,36 @@
package v3
import (
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
"testing"
)
func TestCallback_Build_Success(t *testing.T) {
yml := `'{$request.query.queryUrl}':
post:
requestBody:
description: Callback payload
content:
'application/json':
schema:
type: string
responses:
'200':
description: callback successfully processed`
var rootNode yaml.Node
mErr := yaml.Unmarshal([]byte(yml), &rootNode)
assert.NoError(t, mErr)
var n Callback
err := BuildModel(rootNode.Content[0], &n)
assert.NoError(t, err)
err = n.Build(rootNode.Content[0], nil)
assert.NoError(t, err)
assert.Len(t, n.Expression.Value, 1)
}

View File

@@ -2,6 +2,7 @@ package v3
import ( import (
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils" "github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@@ -56,12 +57,8 @@ func (co *Components) FindCallback(callback string) *low.ValueReference[*Callbac
return FindItemInMap[*Callback](callback, co.Callbacks.Value) return FindItemInMap[*Callback](callback, co.Callbacks.Value)
} }
func (co *Components) Build(root *yaml.Node) error { func (co *Components) Build(root *yaml.Node, idx *index.SpecIndex) error {
extensionMap, err := ExtractExtensions(root) co.Extensions = ExtractExtensions(root)
if err != nil {
return err
}
co.Extensions = extensionMap
// build out components asynchronously for speed. There could be some significant weight here. // build out components asynchronously for speed. There could be some significant weight here.
skipChan := make(chan bool) skipChan := make(chan bool)
@@ -76,15 +73,15 @@ func (co *Components) Build(root *yaml.Node) error {
linkChan := make(chan low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Link]]) linkChan := make(chan low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Link]])
callbackChan := make(chan low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Callback]]) callbackChan := make(chan low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Callback]])
go extractComponentValues[*Schema](SchemasLabel, root, skipChan, errorChan, schemaChan) go extractComponentValues[*Schema](SchemasLabel, root, skipChan, errorChan, schemaChan, idx)
go extractComponentValues[*Parameter](ParametersLabel, root, skipChan, errorChan, paramChan) go extractComponentValues[*Parameter](ParametersLabel, root, skipChan, errorChan, paramChan, idx)
go extractComponentValues[*Response](ResponsesLabel, root, skipChan, errorChan, responsesChan) go extractComponentValues[*Response](ResponsesLabel, root, skipChan, errorChan, responsesChan, idx)
go extractComponentValues[*Example](ExamplesLabel, root, skipChan, errorChan, examplesChan) go extractComponentValues[*Example](ExamplesLabel, root, skipChan, errorChan, examplesChan, idx)
go extractComponentValues[*RequestBody](RequestBodiesLabel, root, skipChan, errorChan, requestBodiesChan) go extractComponentValues[*RequestBody](RequestBodiesLabel, root, skipChan, errorChan, requestBodiesChan, idx)
go extractComponentValues[*Header](HeadersLabel, root, skipChan, errorChan, headersChan) go extractComponentValues[*Header](HeadersLabel, root, skipChan, errorChan, headersChan, idx)
go extractComponentValues[*SecurityScheme](SecuritySchemesLabel, root, skipChan, errorChan, securitySchemesChan) go extractComponentValues[*SecurityScheme](SecuritySchemesLabel, root, skipChan, errorChan, securitySchemesChan, idx)
go extractComponentValues[*Link](LinksLabel, root, skipChan, errorChan, linkChan) go extractComponentValues[*Link](LinksLabel, root, skipChan, errorChan, linkChan, idx)
go extractComponentValues[*Callback](CallbacksLabel, root, skipChan, errorChan, callbackChan) go extractComponentValues[*Callback](CallbacksLabel, root, skipChan, errorChan, callbackChan, idx)
n := 0 n := 0
total := 9 total := 9
@@ -159,7 +156,7 @@ allDone:
} }
func extractComponentValues[T low.Buildable[N], N any](label string, root *yaml.Node, func extractComponentValues[T low.Buildable[N], N any](label string, root *yaml.Node,
skip chan bool, errorChan chan<- error, resultChan chan<- low.NodeReference[map[low.KeyReference[string]]low.ValueReference[T]]) { skip chan bool, errorChan chan<- error, resultChan chan<- low.NodeReference[map[low.KeyReference[string]]low.ValueReference[T]], idx *index.SpecIndex) {
_, nodeLabel, nodeValue := utils.FindKeyNodeFull(label, root.Content) _, nodeLabel, nodeValue := utils.FindKeyNodeFull(label, root.Content)
if nodeValue == nil { if nodeValue == nil {
skip <- true skip <- true
@@ -177,7 +174,7 @@ func extractComponentValues[T low.Buildable[N], N any](label string, root *yaml.
if err != nil { if err != nil {
errorChan <- err errorChan <- err
} }
err = n.Build(v) err = n.Build(v, idx)
if err != nil { if err != nil {
errorChan <- err errorChan <- err
} }

View File

@@ -2,6 +2,7 @@ package v3
import ( import (
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@@ -21,9 +22,9 @@ func (en *Encoding) FindHeader(hType string) *low.ValueReference[*Header] {
return FindItemInMap[*Header](hType, en.Headers.Value) return FindItemInMap[*Header](hType, en.Headers.Value)
} }
func (en *Encoding) Build(root *yaml.Node) error { func (en *Encoding) Build(root *yaml.Node, idx *index.SpecIndex) error {
headers, hL, hN, err := ExtractMapFlat[*Header](HeadersLabel, root) headers, hL, hN, err := ExtractMapFlat[*Header](HeadersLabel, root, idx)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -2,6 +2,7 @@ package v3
import ( import (
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils" "github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@@ -20,19 +21,14 @@ type Example struct {
Extensions map[low.KeyReference[string]]low.ValueReference[any] Extensions map[low.KeyReference[string]]low.ValueReference[any]
} }
func (ex *Example) Build(root *yaml.Node) error { func (ex *Example) Build(root *yaml.Node, idx *index.SpecIndex) error {
// extract extensions ex.Extensions = ExtractExtensions(root)
extensionMap, err := ExtractExtensions(root)
if err != nil {
return err
}
ex.Extensions = extensionMap
// extract value // extract value
_, ln, vn := utils.FindKeyNodeFull(ValueLabel, root.Content) _, ln, vn := utils.FindKeyNodeFull(ValueLabel, root.Content)
if vn != nil { if vn != nil {
var n map[string]interface{} var n map[string]interface{}
err = vn.Decode(&n) err := vn.Decode(&n)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -2,6 +2,7 @@ package v3
import ( import (
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@@ -11,12 +12,7 @@ type ExternalDoc struct {
Extensions map[low.KeyReference[string]]low.ValueReference[any] Extensions map[low.KeyReference[string]]low.ValueReference[any]
} }
func (ex *ExternalDoc) Build(root *yaml.Node) error { func (ex *ExternalDoc) Build(root *yaml.Node, idx *index.SpecIndex) error {
// extract extensions ex.Extensions = ExtractExtensions(root)
extensionMap, err := ExtractExtensions(root)
if err != nil {
return err
}
ex.Extensions = extensionMap
return nil return nil
} }

View File

@@ -2,6 +2,7 @@ package v3
import ( import (
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils" "github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"strconv" "strconv"
@@ -9,6 +10,13 @@ import (
"sync" "sync"
) )
var KnownSchemas map[string]low.NodeReference[*Schema]
func init() {
KnownSchemas = make(map[string]low.NodeReference[*Schema])
}
func FindItemInMap[T any](item string, collection map[low.KeyReference[string]]low.ValueReference[T]) *low.ValueReference[T] { func FindItemInMap[T any](item string, collection map[low.KeyReference[string]]low.ValueReference[T]) *low.ValueReference[T] {
for n, o := range collection { for n, o := range collection {
if n.Value == item { if n.Value == item {
@@ -18,15 +26,34 @@ func FindItemInMap[T any](item string, collection map[low.KeyReference[string]]l
return nil return nil
} }
func ExtractSchema(root *yaml.Node) (*low.NodeReference[*Schema], error) { func ExtractSchema(root *yaml.Node, idx *index.SpecIndex) (*low.NodeReference[*Schema], error) {
_, schLabel, schNode := utils.FindKeyNodeFull(SchemaLabel, root.Content) var schLabel, schNode *yaml.Node
if rf, rl, _ := utils.IsNodeRefValue(root); rf {
// locate reference in index.
ref := LocateRefNode(root, idx)
if ref != nil {
schNode = ref
schLabel = rl
}
} else {
_, schLabel, schNode = utils.FindKeyNodeFull(SchemaLabel, root.Content)
if schNode != nil {
if h, _, _ := utils.IsNodeRefValue(schNode); h {
ref := LocateRefNode(schNode, idx)
if ref != nil {
schNode = ref
}
}
}
}
if schNode != nil { if schNode != nil {
var schema Schema var schema Schema
err := BuildModel(schNode, &schema) err := BuildModel(schNode, &schema)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = schema.Build(schNode) err = schema.Build(schNode, idx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -37,21 +64,49 @@ func ExtractSchema(root *yaml.Node) (*low.NodeReference[*Schema], error) {
var mapLock sync.Mutex var mapLock sync.Mutex
func ExtractObjectRaw[T low.Buildable[N], N any](root *yaml.Node) (T, error) { func LocateRefNode(root *yaml.Node, idx *index.SpecIndex) *yaml.Node {
if rf, _, rv := utils.IsNodeRefValue(root); rf {
found := idx.GetMappedReferences()
if found != nil && found[rv] != nil {
return found[rv].Node
}
}
return nil
}
func ExtractObjectRaw[T low.Buildable[N], N any](root *yaml.Node, idx *index.SpecIndex) (T, error) {
var n T = new(N) var n T = new(N)
err := BuildModel(root, n) err := BuildModel(root, n)
if err != nil { if err != nil {
return n, err return n, err
} }
err = n.Build(root) err = n.Build(root, idx)
if err != nil { if err != nil {
return n, err return n, err
} }
return n, nil return n, nil
} }
func ExtractObject[T low.Buildable[N], N any](label string, root *yaml.Node) (low.NodeReference[T], error) { func ExtractObject[T low.Buildable[N], N any](label string, root *yaml.Node, idx *index.SpecIndex) (low.NodeReference[T], error) {
_, ln, vn := utils.FindKeyNodeFull(label, root.Content) var ln, vn *yaml.Node
if rf, rl, _ := utils.IsNodeRefValue(root); rf {
// locate reference in index.
ref := LocateRefNode(root, idx)
if ref != nil {
vn = ref
ln = rl
}
} else {
_, ln, vn = utils.FindKeyNodeFull(label, root.Content)
if vn != nil {
if h, _, _ := utils.IsNodeRefValue(vn); h {
ref := LocateRefNode(vn, idx)
if ref != nil {
vn = ref
}
}
}
}
var n T = new(N) var n T = new(N)
err := BuildModel(vn, n) err := BuildModel(vn, n)
if err != nil { if err != nil {
@@ -60,7 +115,7 @@ func ExtractObject[T low.Buildable[N], N any](label string, root *yaml.Node) (lo
if ln == nil { if ln == nil {
return low.NodeReference[T]{}, nil return low.NodeReference[T]{}, nil
} }
err = n.Build(vn) err = n.Build(vn, idx)
if err != nil { if err != nil {
return low.NodeReference[T]{}, err return low.NodeReference[T]{}, err
} }
@@ -71,17 +126,41 @@ func ExtractObject[T low.Buildable[N], N any](label string, root *yaml.Node) (lo
}, nil }, nil
} }
func ExtractArray[T low.Buildable[N], N any](label string, root *yaml.Node) ([]low.ValueReference[T], *yaml.Node, *yaml.Node, error) { func ExtractArray[T low.Buildable[N], N any](label string, root *yaml.Node, idx *index.SpecIndex) ([]low.ValueReference[T], *yaml.Node, *yaml.Node, error) {
_, ln, vn := utils.FindKeyNodeFull(label, root.Content) var ln, vn *yaml.Node
if rf, rl, _ := utils.IsNodeRefValue(root); rf {
// locate reference in index.
ref := LocateRefNode(root, idx)
if ref != nil {
vn = ref
ln = rl
}
} else {
_, ln, vn = utils.FindKeyNodeFull(label, root.Content)
if vn != nil {
if h, _, _ := utils.IsNodeRefValue(vn); h {
ref := LocateRefNode(vn, idx)
if ref != nil {
vn = ref
}
}
}
}
var items []low.ValueReference[T] var items []low.ValueReference[T]
if vn != nil && ln != nil { if vn != nil && ln != nil {
for _, node := range vn.Content { for _, node := range vn.Content {
if rf, _, _ := utils.IsNodeRefValue(node); rf {
ref := LocateRefNode(node, idx)
if ref != nil {
node = ref
}
}
var n T = new(N) var n T = new(N)
err := BuildModel(node, n) err := BuildModel(node, n)
if err != nil { if err != nil {
return []low.ValueReference[T]{}, ln, vn, err return []low.ValueReference[T]{}, ln, vn, err
} }
berr := n.Build(node) berr := n.Build(node, idx)
if berr != nil { if berr != nil {
return nil, ln, vn, berr return nil, ln, vn, berr
} }
@@ -94,7 +173,7 @@ func ExtractArray[T low.Buildable[N], N any](label string, root *yaml.Node) ([]l
return items, ln, vn, nil return items, ln, vn, nil
} }
func ExtractMapFlatNoLookup[PT low.Buildable[N], N any](root *yaml.Node) (map[low.KeyReference[string]]low.ValueReference[PT], error) { func ExtractMapFlatNoLookup[PT low.Buildable[N], N any](root *yaml.Node, idx *index.SpecIndex) (map[low.KeyReference[string]]low.ValueReference[PT], error) {
valueMap := make(map[low.KeyReference[string]]low.ValueReference[PT]) valueMap := make(map[low.KeyReference[string]]low.ValueReference[PT])
if utils.IsNodeMap(root) { if utils.IsNodeMap(root) {
var currentKey *yaml.Node var currentKey *yaml.Node
@@ -108,7 +187,7 @@ func ExtractMapFlatNoLookup[PT low.Buildable[N], N any](root *yaml.Node) (map[lo
if err != nil { if err != nil {
return nil, err return nil, err
} }
berr := n.Build(node) berr := n.Build(node, idx)
if berr != nil { if berr != nil {
return nil, berr return nil, berr
} }
@@ -124,8 +203,26 @@ func ExtractMapFlatNoLookup[PT low.Buildable[N], N any](root *yaml.Node) (map[lo
return valueMap, nil return valueMap, nil
} }
func ExtractMapFlat[PT low.Buildable[N], N any](label string, root *yaml.Node) (map[low.KeyReference[string]]low.ValueReference[PT], *yaml.Node, *yaml.Node, error) { func ExtractMapFlat[PT low.Buildable[N], N any](label string, root *yaml.Node, idx *index.SpecIndex) (map[low.KeyReference[string]]low.ValueReference[PT], *yaml.Node, *yaml.Node, error) {
_, labelNode, valueNode := utils.FindKeyNodeFull(label, root.Content) var labelNode, valueNode *yaml.Node
if rf, rl, _ := utils.IsNodeRefValue(root); rf {
// locate reference in index.
ref := LocateRefNode(root, idx)
if ref != nil {
valueNode = ref
labelNode = rl
}
} else {
_, labelNode, valueNode = utils.FindKeyNodeFull(label, root.Content)
if valueNode != nil {
if h, _, _ := utils.IsNodeRefValue(valueNode); h {
ref := LocateRefNode(valueNode, idx)
if ref != nil {
valueNode = ref
}
}
}
}
if valueNode != nil { if valueNode != nil {
var currentLabelNode *yaml.Node var currentLabelNode *yaml.Node
valueMap := make(map[low.KeyReference[string]]low.ValueReference[PT]) valueMap := make(map[low.KeyReference[string]]low.ValueReference[PT])
@@ -134,6 +231,15 @@ func ExtractMapFlat[PT low.Buildable[N], N any](label string, root *yaml.Node) (
currentLabelNode = en currentLabelNode = en
continue continue
} }
// check our valueNode isn't a reference still.
if h, _, _ := utils.IsNodeRefValue(en); h {
ref := LocateRefNode(en, idx)
if ref != nil {
en = ref
}
}
if strings.HasPrefix(strings.ToLower(currentLabelNode.Value), "x-") { if strings.HasPrefix(strings.ToLower(currentLabelNode.Value), "x-") {
continue // yo, don't pay any attention to extensions, not here anyway. continue // yo, don't pay any attention to extensions, not here anyway.
} }
@@ -142,7 +248,7 @@ func ExtractMapFlat[PT low.Buildable[N], N any](label string, root *yaml.Node) (
if err != nil { if err != nil {
return nil, labelNode, valueNode, err return nil, labelNode, valueNode, err
} }
berr := n.Build(en) berr := n.Build(en, idx)
if berr != nil { if berr != nil {
return nil, labelNode, valueNode, berr return nil, labelNode, valueNode, berr
} }
@@ -159,8 +265,19 @@ func ExtractMapFlat[PT low.Buildable[N], N any](label string, root *yaml.Node) (
return nil, labelNode, valueNode, nil return nil, labelNode, valueNode, nil
} }
func ExtractMap[PT low.Buildable[N], N any](label string, root *yaml.Node) (map[low.KeyReference[string]]map[low.KeyReference[string]]low.ValueReference[PT], error) { func ExtractMap[PT low.Buildable[N], N any](label string, root *yaml.Node, idx *index.SpecIndex) (map[low.KeyReference[string]]map[low.KeyReference[string]]low.ValueReference[PT], error) {
_, labelNode, valueNode := utils.FindKeyNodeFull(label, root.Content) var labelNode, valueNode *yaml.Node
if rf, rl, _ := utils.IsNodeRefValue(root); rf {
// locate reference in index.
ref := LocateRefNode(root, idx)
if ref != nil {
valueNode = ref
labelNode = rl
}
} else {
_, labelNode, valueNode = utils.FindKeyNodeFull(label, root.Content)
}
if valueNode != nil { if valueNode != nil {
var currentLabelNode *yaml.Node var currentLabelNode *yaml.Node
valueMap := make(map[low.KeyReference[string]]low.ValueReference[PT]) valueMap := make(map[low.KeyReference[string]]low.ValueReference[PT])
@@ -177,7 +294,7 @@ func ExtractMap[PT low.Buildable[N], N any](label string, root *yaml.Node) (map[
if err != nil { if err != nil {
return nil, err return nil, err
} }
berr := n.Build(en) berr := n.Build(en, idx)
if berr != nil { if berr != nil {
return nil, berr return nil, berr
} }
@@ -199,16 +316,13 @@ func ExtractMap[PT low.Buildable[N], N any](label string, root *yaml.Node) (map[
return nil, nil return nil, nil
} }
func ExtractExtensions(root *yaml.Node) (map[low.KeyReference[string]]low.ValueReference[any], error) { func ExtractExtensions(root *yaml.Node) map[low.KeyReference[string]]low.ValueReference[any] {
extensions := utils.FindExtensionNodes(root.Content) extensions := utils.FindExtensionNodes(root.Content)
extensionMap := make(map[low.KeyReference[string]]low.ValueReference[any]) extensionMap := make(map[low.KeyReference[string]]low.ValueReference[any])
for _, ext := range extensions { for _, ext := range extensions {
if utils.IsNodeMap(ext.Value) { if utils.IsNodeMap(ext.Value) {
var v interface{} var v interface{}
err := ext.Value.Decode(&v) _ = ext.Value.Decode(&v)
if err != nil {
return nil, err
}
extensionMap[low.KeyReference[string]{ extensionMap[low.KeyReference[string]{
Value: ext.Key.Value, Value: ext.Key.Value,
KeyNode: ext.Key, KeyNode: ext.Key,
@@ -243,15 +357,12 @@ func ExtractExtensions(root *yaml.Node) (map[low.KeyReference[string]]low.ValueR
} }
if utils.IsNodeArray(ext.Value) { if utils.IsNodeArray(ext.Value) {
var v []interface{} var v []interface{}
err := ext.Value.Decode(&v) _ = ext.Value.Decode(&v)
if err != nil {
return nil, err
}
extensionMap[low.KeyReference[string]{ extensionMap[low.KeyReference[string]{
Value: ext.Key.Value, Value: ext.Key.Value,
KeyNode: ext.Key, KeyNode: ext.Key,
}] = low.ValueReference[any]{Value: v, ValueNode: ext.Value} }] = low.ValueReference[any]{Value: v, ValueNode: ext.Value}
} }
} }
return extensionMap, nil return extensionMap
} }

View File

@@ -2,6 +2,7 @@ package v3
import ( import (
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@@ -24,16 +25,11 @@ type Header struct {
Extensions map[low.KeyReference[string]]low.ValueReference[any] Extensions map[low.KeyReference[string]]low.ValueReference[any]
} }
func (h *Header) Build(root *yaml.Node) error { func (h *Header) Build(root *yaml.Node, idx *index.SpecIndex) error {
// extract extensions h.Extensions = ExtractExtensions(root)
extensionMap, err := ExtractExtensions(root)
if err != nil {
return err
}
h.Extensions = extensionMap
// handle examples if set. // handle examples if set.
exps, eErr := ExtractMap[*Example](ExamplesLabel, root) exps, eErr := ExtractMap[*Example](ExamplesLabel, root, idx)
if eErr != nil { if eErr != nil {
return eErr return eErr
} }
@@ -42,7 +38,7 @@ func (h *Header) Build(root *yaml.Node) error {
} }
// handle schema // handle schema
sch, sErr := ExtractSchema(root) sch, sErr := ExtractSchema(root, idx)
if sErr != nil { if sErr != nil {
return nil return nil
} }
@@ -51,7 +47,7 @@ func (h *Header) Build(root *yaml.Node) error {
} }
// handle content, if set. // handle content, if set.
con, cErr := ExtractMap[*MediaType](ContentLabel, root) con, cErr := ExtractMap[*MediaType](ContentLabel, root, idx)
if cErr != nil { if cErr != nil {
return cErr return cErr
} }

View File

@@ -2,6 +2,7 @@ package v3
import ( import (
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils" "github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@@ -20,12 +21,8 @@ func (l *Link) FindParameter(pName string) *low.ValueReference[string] {
return FindItemInMap[string](pName, l.Parameters.Value) return FindItemInMap[string](pName, l.Parameters.Value)
} }
func (l *Link) Build(root *yaml.Node) error { func (l *Link) Build(root *yaml.Node, idx *index.SpecIndex) error {
extensionMap, err := ExtractExtensions(root) l.Extensions = ExtractExtensions(root)
if err != nil {
return err
}
l.Extensions = extensionMap
// extract parameters // extract parameters
_, pl, pv := utils.FindKeyNodeFull(ParametersLabel, root.Content) _, pl, pv := utils.FindKeyNodeFull(ParametersLabel, root.Content)

View File

@@ -2,6 +2,7 @@ package v3
import ( import (
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils" "github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@@ -26,14 +27,8 @@ func (mt *MediaType) GetAllExamples() map[low.KeyReference[string]]low.ValueRefe
return mt.Examples.Value return mt.Examples.Value
} }
func (mt *MediaType) Build(root *yaml.Node) error { func (mt *MediaType) Build(root *yaml.Node, idx *index.SpecIndex) error {
mt.Extensions = ExtractExtensions(root)
// extract extensions
extensionMap, err := ExtractExtensions(root)
if err != nil {
return err
}
mt.Extensions = extensionMap
// handle example if set. // handle example if set.
_, expLabel, expNode := utils.FindKeyNodeFull(ExampleLabel, root.Content) _, expLabel, expNode := utils.FindKeyNodeFull(ExampleLabel, root.Content)
@@ -42,7 +37,7 @@ func (mt *MediaType) Build(root *yaml.Node) error {
} }
// handle schema // handle schema
sch, sErr := ExtractSchema(root) sch, sErr := ExtractSchema(root, idx)
if sErr != nil { if sErr != nil {
return nil return nil
} }
@@ -51,7 +46,7 @@ func (mt *MediaType) Build(root *yaml.Node) error {
} }
// handle examples if set. // handle examples if set.
exps, expsL, expsN, eErr := ExtractMapFlat[*Example](ExamplesLabel, root) exps, expsL, expsN, eErr := ExtractMapFlat[*Example](ExamplesLabel, root, idx)
if eErr != nil { if eErr != nil {
return eErr return eErr
} }
@@ -64,9 +59,9 @@ func (mt *MediaType) Build(root *yaml.Node) error {
} }
// handle encoding // handle encoding
encs, encsL, encsN, encErr := ExtractMapFlat[*Encoding](EncodingLabel, root) encs, encsL, encsN, encErr := ExtractMapFlat[*Encoding](EncodingLabel, root, idx)
if encErr != nil { if encErr != nil {
return err return encErr
} }
if encs != nil { if encs != nil {
mt.Encoding = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Encoding]]{ mt.Encoding = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Encoding]]{

View File

@@ -2,6 +2,7 @@ package v3
import ( import (
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils" "github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@@ -22,32 +23,28 @@ type OAuthFlows struct {
Extensions map[low.KeyReference[string]]low.ValueReference[any] Extensions map[low.KeyReference[string]]low.ValueReference[any]
} }
func (o *OAuthFlows) Build(root *yaml.Node) error { func (o *OAuthFlows) Build(root *yaml.Node, idx *index.SpecIndex) error {
extensionMap, err := ExtractExtensions(root) o.Extensions = ExtractExtensions(root)
if err != nil {
return err
}
o.Extensions = extensionMap
v, vErr := ExtractObject[*OAuthFlow](ImplicitLabel, root) v, vErr := ExtractObject[*OAuthFlow](ImplicitLabel, root, idx)
if vErr != nil { if vErr != nil {
return vErr return vErr
} }
o.Implicit = v o.Implicit = v
v, vErr = ExtractObject[*OAuthFlow](PasswordLabel, root) v, vErr = ExtractObject[*OAuthFlow](PasswordLabel, root, idx)
if vErr != nil { if vErr != nil {
return vErr return vErr
} }
o.Password = v o.Password = v
v, vErr = ExtractObject[*OAuthFlow](ClientCredentialsLabel, root) v, vErr = ExtractObject[*OAuthFlow](ClientCredentialsLabel, root, idx)
if vErr != nil { if vErr != nil {
return vErr return vErr
} }
o.ClientCredentials = v o.ClientCredentials = v
v, vErr = ExtractObject[*OAuthFlow](AuthorizationCodeLabel, root) v, vErr = ExtractObject[*OAuthFlow](AuthorizationCodeLabel, root, idx)
if vErr != nil { if vErr != nil {
return vErr return vErr
} }
@@ -68,12 +65,8 @@ func (o *OAuthFlow) FindScope(scope string) *low.ValueReference[string] {
return FindItemInMap[string](scope, o.Scopes.Value) return FindItemInMap[string](scope, o.Scopes.Value)
} }
func (o *OAuthFlow) Build(root *yaml.Node) error { func (o *OAuthFlow) Build(root *yaml.Node, idx *index.SpecIndex) error {
extensionMap, err := ExtractExtensions(root) o.Extensions = ExtractExtensions(root)
if err != nil {
return err
}
o.Extensions = extensionMap
var currSec *yaml.Node var currSec *yaml.Node

View File

@@ -2,6 +2,7 @@ package v3
import ( import (
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@@ -29,22 +30,18 @@ type Operation struct {
Extensions map[low.KeyReference[string]]low.ValueReference[any] Extensions map[low.KeyReference[string]]low.ValueReference[any]
} }
func (o *Operation) Build(root *yaml.Node) error { func (o *Operation) Build(root *yaml.Node, idx *index.SpecIndex) error {
extensionMap, err := ExtractExtensions(root) o.Extensions = ExtractExtensions(root)
if err != nil {
return err
}
o.Extensions = extensionMap
// extract externalDocs // extract externalDocs
extDocs, dErr := ExtractObject[*ExternalDoc](ExternalDocsLabel, root) extDocs, dErr := ExtractObject[*ExternalDoc](ExternalDocsLabel, root, idx)
if dErr != nil { if dErr != nil {
return dErr return dErr
} }
o.ExternalDocs = extDocs o.ExternalDocs = extDocs
// extract parameters // extract parameters
params, ln, vn, pErr := ExtractArray[*Parameter](ParametersLabel, root) params, ln, vn, pErr := ExtractArray[*Parameter](ParametersLabel, root, idx)
if pErr != nil { if pErr != nil {
return pErr return pErr
} }
@@ -57,21 +54,21 @@ func (o *Operation) Build(root *yaml.Node) error {
} }
// extract request body // extract request body
rBody, rErr := ExtractObject[*RequestBody](RequestBodyLabel, root) rBody, rErr := ExtractObject[*RequestBody](RequestBodyLabel, root, idx)
if rErr != nil { if rErr != nil {
return rErr return rErr
} }
o.RequestBody = rBody o.RequestBody = rBody
// extract responses // extract responses
respBody, respErr := ExtractObject[*Responses](ResponsesLabel, root) respBody, respErr := ExtractObject[*Responses](ResponsesLabel, root, idx)
if respErr != nil { if respErr != nil {
return rErr return rErr
} }
o.Responses = respBody o.Responses = respBody
// extract callbacks // extract callbacks
callbacks, cbL, cbN, cbErr := ExtractMapFlat[*Callback](CallbacksLabel, root) callbacks, cbL, cbN, cbErr := ExtractMapFlat[*Callback](CallbacksLabel, root, idx)
if cbErr != nil { if cbErr != nil {
return cbErr return cbErr
} }
@@ -84,14 +81,14 @@ func (o *Operation) Build(root *yaml.Node) error {
} }
// extract security // extract security
sec, sErr := ExtractObject[*SecurityRequirement](SecurityLabel, root) sec, sErr := ExtractObject[*SecurityRequirement](SecurityLabel, root, idx)
if sErr != nil { if sErr != nil {
return sErr return sErr
} }
o.Security = sec o.Security = sec
// extract servers // extract servers
servers, sl, sn, serErr := ExtractArray[*Server](ServersLabel, root) servers, sl, sn, serErr := ExtractArray[*Server](ServersLabel, root, idx)
if serErr != nil { if serErr != nil {
return serErr return serErr
} }

View File

@@ -2,6 +2,7 @@ package v3
import ( import (
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils" "github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@@ -36,14 +37,8 @@ func (p *Parameter) FindExample(eType string) *low.ValueReference[*Example] {
return FindItemInMap[*Example](eType, p.Examples.Value) return FindItemInMap[*Example](eType, p.Examples.Value)
} }
func (p *Parameter) Build(root *yaml.Node) error { func (p *Parameter) Build(root *yaml.Node, idx *index.SpecIndex) error {
p.Extensions = ExtractExtensions(root)
// extract extensions
extensionMap, err := ExtractExtensions(root)
if err != nil {
return err
}
p.Extensions = extensionMap
// handle example if set. // handle example if set.
_, expLabel, expNode := utils.FindKeyNodeFull(ExampleLabel, root.Content) _, expLabel, expNode := utils.FindKeyNodeFull(ExampleLabel, root.Content)
@@ -52,14 +47,16 @@ func (p *Parameter) Build(root *yaml.Node) error {
} }
// handle schema // handle schema
sch, sErr := ExtractSchema(root) sch, sErr := ExtractSchema(root, idx)
if sErr != nil { if sErr != nil {
return sErr return sErr
} }
p.Schema = *sch if sch != nil {
p.Schema = *sch
}
// handle examples if set. // handle examples if set.
exps, expsL, expsN, eErr := ExtractMapFlat[*Example](ExamplesLabel, root) exps, expsL, expsN, eErr := ExtractMapFlat[*Example](ExamplesLabel, root, idx)
if eErr != nil { if eErr != nil {
return eErr return eErr
} }
@@ -72,7 +69,7 @@ func (p *Parameter) Build(root *yaml.Node) error {
} }
// handle content, if set. // handle content, if set.
con, cL, cN, cErr := ExtractMapFlat[*MediaType](ContentLabel, root) con, cL, cN, cErr := ExtractMapFlat[*MediaType](ContentLabel, root, idx)
if cErr != nil { if cErr != nil {
return cErr return cErr
} }

View File

@@ -2,6 +2,8 @@ package v3
import ( import (
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"strings" "strings"
"sync" "sync"
@@ -33,14 +35,8 @@ func (p *Paths) FindPath(path string) *low.ValueReference[*PathItem] {
return nil return nil
} }
func (p *Paths) Build(root *yaml.Node) error { func (p *Paths) Build(root *yaml.Node, idx *index.SpecIndex) error {
p.Extensions = ExtractExtensions(root)
// extract extensions
extensionMap, err := ExtractExtensions(root)
if err != nil {
return err
}
p.Extensions = extensionMap
skip := false skip := false
var currentNode *yaml.Node var currentNode *yaml.Node
@@ -60,11 +56,11 @@ func (p *Paths) Build(root *yaml.Node) error {
continue continue
} }
var path = PathItem{} var path = PathItem{}
err = BuildModel(pathNode, &path) err := BuildModel(pathNode, &path)
if err != nil { if err != nil {
} }
err = path.Build(pathNode) err = path.Build(pathNode, idx)
if err != nil { if err != nil {
return err return err
} }
@@ -100,12 +96,8 @@ type PathItem struct {
Extensions map[low.KeyReference[string]]low.ValueReference[any] Extensions map[low.KeyReference[string]]low.ValueReference[any]
} }
func (p *PathItem) Build(root *yaml.Node) error { func (p *PathItem) Build(root *yaml.Node, idx *index.SpecIndex) error {
extensionMap, err := ExtractExtensions(root) p.Extensions = ExtractExtensions(root)
if err != nil {
return err
}
p.Extensions = extensionMap
skip := false skip := false
var currentNode *yaml.Node var currentNode *yaml.Node
@@ -114,6 +106,15 @@ func (p *PathItem) Build(root *yaml.Node) error {
var ops []low.NodeReference[*Operation] var ops []low.NodeReference[*Operation]
if ok, _, _ := utils.IsNodeRefValue(root); ok {
r := LocateRefNode(root, idx)
if r != nil {
root = r
} else {
return nil
}
}
for i, pathNode := range root.Content { for i, pathNode := range root.Content {
if strings.HasPrefix(strings.ToLower(pathNode.Value), "x-") { if strings.HasPrefix(strings.ToLower(pathNode.Value), "x-") {
skip = true skip = true
@@ -161,18 +162,20 @@ func (p *PathItem) Build(root *yaml.Node) error {
} }
} }
wg.Wait() if len(ops) > 0 {
//wg.Wait()
}
// all operations have been superficially built, //all operations have been superficially built,
// now we need to build out the operation, we will do this asynchronously for speed. //now we need to build out the operation, we will do this asynchronously for speed.
opBuildChan := make(chan bool) opBuildChan := make(chan bool)
opErrorChan := make(chan error) opErrorChan := make(chan error)
var buildOpFunc = func(op low.NodeReference[*Operation], ch chan<- bool, errCh chan<- error) { var buildOpFunc = func(op low.NodeReference[*Operation], ch chan<- bool, errCh chan<- error) {
// build out the operation. //build out the operation.
er := op.Value.Build(op.ValueNode) er := op.Value.Build(op.ValueNode, idx)
if err != nil { if er != nil {
errCh <- er errCh <- er
} }
ch <- true ch <- true

View File

@@ -2,6 +2,7 @@ package v3
import ( import (
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@@ -16,18 +17,11 @@ func (rb *RequestBody) FindContent(cType string) *low.ValueReference[*MediaType]
return FindItemInMap[*MediaType](cType, rb.Content.Value) return FindItemInMap[*MediaType](cType, rb.Content.Value)
} }
func (rb *RequestBody) Build(root *yaml.Node) error { func (rb *RequestBody) Build(root *yaml.Node, idx *index.SpecIndex) error {
// extract extensions rb.Extensions = ExtractExtensions(root)
extensionMap, err := ExtractExtensions(root)
if err != nil {
return err
}
if extensionMap != nil {
rb.Extensions = extensionMap
}
// handle content, if set. // handle content, if set.
con, cL, cN, cErr := ExtractMapFlat[*MediaType](ContentLabel, root) con, cL, cN, cErr := ExtractMapFlat[*MediaType](ContentLabel, root, idx)
if cErr != nil { if cErr != nil {
return cErr return cErr
} }

View File

@@ -2,6 +2,7 @@ package v3
import ( import (
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils" "github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@@ -15,9 +16,9 @@ type Responses struct {
Default low.NodeReference[*Response] Default low.NodeReference[*Response]
} }
func (r *Responses) Build(root *yaml.Node) error { func (r *Responses) Build(root *yaml.Node, idx *index.SpecIndex) error {
if utils.IsNodeMap(root) { if utils.IsNodeMap(root) {
codes, err := ExtractMapFlatNoLookup[*Response](root) codes, err := ExtractMapFlatNoLookup[*Response](root, idx)
if err != nil { if err != nil {
return err return err
} }
@@ -52,15 +53,11 @@ func (r *Response) FindLink(hType string) *low.ValueReference[*Link] {
return FindItemInMap[*Link](hType, r.Links.Value) return FindItemInMap[*Link](hType, r.Links.Value)
} }
func (r *Response) Build(root *yaml.Node) error { func (r *Response) Build(root *yaml.Node, idx *index.SpecIndex) error {
extensionMap, err := ExtractExtensions(root) r.Extensions = ExtractExtensions(root)
if err != nil {
return err
}
r.Extensions = extensionMap
// extract headers // extract headers
headers, lN, kN, err := ExtractMapFlat[*Header](HeadersLabel, root) headers, lN, kN, err := ExtractMapFlat[*Header](HeadersLabel, root, idx)
if err != nil { if err != nil {
return err return err
} }
@@ -73,7 +70,7 @@ func (r *Response) Build(root *yaml.Node) error {
} }
// handle content, if set. // handle content, if set.
con, clN, cN, cErr := ExtractMapFlat[*MediaType](ContentLabel, root) con, clN, cN, cErr := ExtractMapFlat[*MediaType](ContentLabel, root, idx)
if cErr != nil { if cErr != nil {
return cErr return cErr
} }
@@ -86,7 +83,7 @@ func (r *Response) Build(root *yaml.Node) error {
} }
// handle links if set // handle links if set
links, linkLabel, linkValue, lErr := ExtractMapFlat[*Link](LinksLabel, root) links, linkLabel, linkValue, lErr := ExtractMapFlat[*Link](LinksLabel, root, idx)
if lErr != nil { if lErr != nil {
return lErr return lErr
} }

View File

@@ -2,6 +2,7 @@ package v3
import ( import (
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils" "github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"strconv" "strconv"
@@ -61,20 +62,17 @@ func (s *Schema) FindProperty(name string) *low.ValueReference[*Schema] {
return FindItemInMap[*Schema](name, s.Properties.Value) return FindItemInMap[*Schema](name, s.Properties.Value)
} }
func (s *Schema) Build(root *yaml.Node) error { func (s *Schema) Build(root *yaml.Node, idx *index.SpecIndex) error {
return s.BuildLevel(root, 0) return s.BuildLevel(root, idx, 0)
} }
func (s *Schema) BuildLevel(root *yaml.Node, level int) error { func (s *Schema) BuildLevel(root *yaml.Node, idx *index.SpecIndex, level int) error {
level++ level++
if level > 50 { if level > 10 {
return nil // we're done, son! too fricken deep. return nil // we're done, son! too fricken deep.
} }
err := s.extractExtensions(root) s.extractExtensions(root)
if err != nil {
return err
}
// handle example if set. // handle example if set.
_, expLabel, expNode := utils.FindKeyNodeFull(ExampleLabel, root.Content) _, expLabel, expNode := utils.FindKeyNodeFull(ExampleLabel, root.Content)
@@ -85,7 +83,7 @@ func (s *Schema) BuildLevel(root *yaml.Node, level int) error {
_, addPLabel, addPNode := utils.FindKeyNodeFull(AdditionalPropertiesLabel, root.Content) _, addPLabel, addPNode := utils.FindKeyNodeFull(AdditionalPropertiesLabel, root.Content)
if addPNode != nil { if addPNode != nil {
if utils.IsNodeMap(addPNode) { if utils.IsNodeMap(addPNode) {
schema, serr := ExtractObjectRaw[*Schema](addPNode) schema, serr := ExtractObjectRaw[*Schema](addPNode, idx)
if serr != nil { if serr != nil {
return serr return serr
} }
@@ -102,7 +100,7 @@ func (s *Schema) BuildLevel(root *yaml.Node, level int) error {
_, discLabel, discNode := utils.FindKeyNodeFull(DiscriminatorLabel, root.Content) _, discLabel, discNode := utils.FindKeyNodeFull(DiscriminatorLabel, root.Content)
if discNode != nil { if discNode != nil {
var discriminator Discriminator var discriminator Discriminator
err = BuildModel(discNode, &discriminator) err := BuildModel(discNode, &discriminator)
if err != nil { if err != nil {
return err return err
} }
@@ -113,11 +111,11 @@ func (s *Schema) BuildLevel(root *yaml.Node, level int) error {
_, extDocLabel, extDocNode := utils.FindKeyNodeFull(ExternalDocsLabel, root.Content) _, extDocLabel, extDocNode := utils.FindKeyNodeFull(ExternalDocsLabel, root.Content)
if extDocNode != nil { if extDocNode != nil {
var exDoc ExternalDoc var exDoc ExternalDoc
err = BuildModel(extDocNode, &exDoc) err := BuildModel(extDocNode, &exDoc)
if err != nil { if err != nil {
return err return err
} }
err = exDoc.Build(extDocNode) err = exDoc.Build(extDocNode, idx)
if err != nil { if err != nil {
return err return err
} }
@@ -128,7 +126,7 @@ func (s *Schema) BuildLevel(root *yaml.Node, level int) error {
_, xmlLabel, xmlNode := utils.FindKeyNodeFull(XMLLabel, root.Content) _, xmlLabel, xmlNode := utils.FindKeyNodeFull(XMLLabel, root.Content)
if xmlNode != nil { if xmlNode != nil {
var xml XML var xml XML
err = BuildModel(xmlNode, &xml) err := BuildModel(xmlNode, &xml)
if err != nil { if err != nil {
return err return err
} }
@@ -150,12 +148,21 @@ func (s *Schema) BuildLevel(root *yaml.Node, level int) error {
currentProp = prop currentProp = prop
continue continue
} }
// check our prop isn't reference
if h, _, _ := utils.IsNodeRefValue(prop); h {
ref := LocateRefNode(prop, idx)
if ref != nil {
prop = ref
}
}
var property Schema var property Schema
err = BuildModel(prop, &property) err := BuildModel(prop, &property)
if err != nil { if err != nil {
return err return err
} }
err = property.BuildLevel(prop, level) err = property.BuildLevel(prop, idx, level)
if err != nil { if err != nil {
return err return err
} }
@@ -179,11 +186,11 @@ func (s *Schema) BuildLevel(root *yaml.Node, level int) error {
var allOf, anyOf, oneOf, not, items []low.NodeReference[*Schema] var allOf, anyOf, oneOf, not, items []low.NodeReference[*Schema]
// make this async at some point to speed things up. // make this async at some point to speed things up.
allOfLabel, allOfValue := buildSchema(&allOf, AllOfLabel, root, level, &errors) allOfLabel, allOfValue := buildSchema(&allOf, AllOfLabel, root, level, &errors, idx)
anyOfLabel, anyOfValue := buildSchema(&anyOf, AnyOfLabel, root, level, &errors) anyOfLabel, anyOfValue := buildSchema(&anyOf, AnyOfLabel, root, level, &errors, idx)
oneOfLabel, oneOfValue := buildSchema(&oneOf, OneOfLabel, root, level, &errors) oneOfLabel, oneOfValue := buildSchema(&oneOf, OneOfLabel, root, level, &errors, idx)
notLabel, notValue := buildSchema(&not, NotLabel, root, level, &errors) notLabel, notValue := buildSchema(&not, NotLabel, root, level, &errors, idx)
itemsLabel, itemsValue := buildSchema(&items, ItemsLabel, root, level, &errors) itemsLabel, itemsValue := buildSchema(&items, ItemsLabel, root, level, &errors, idx)
if len(errors) > 0 { if len(errors) > 0 {
// todo fix this // todo fix this
@@ -228,16 +235,13 @@ func (s *Schema) BuildLevel(root *yaml.Node, level int) error {
return nil return nil
} }
func (s *Schema) extractExtensions(root *yaml.Node) error { func (s *Schema) extractExtensions(root *yaml.Node) {
extensionMap, err := ExtractExtensions(root) s.Extensions = ExtractExtensions(root)
if err != nil {
return err
}
s.Extensions = extensionMap
return err
} }
func buildSchema(schemas *[]low.NodeReference[*Schema], attribute string, rootNode *yaml.Node, level int, errors *[]error) (labelNode *yaml.Node, valueNode *yaml.Node) { func buildSchema(schemas *[]low.NodeReference[*Schema], attribute string, rootNode *yaml.Node, level int,
errors *[]error, idx *index.SpecIndex) (labelNode *yaml.Node, valueNode *yaml.Node) {
_, labelNode, valueNode = utils.FindKeyNodeFull(attribute, rootNode.Content) _, labelNode, valueNode = utils.FindKeyNodeFull(attribute, rootNode.Content)
//wg.Add(1) //wg.Add(1)
if valueNode != nil { if valueNode != nil {
@@ -248,7 +252,7 @@ func buildSchema(schemas *[]low.NodeReference[*Schema], attribute string, rootNo
*errors = append(*errors, err) *errors = append(*errors, err)
return nil return nil
} }
err = schema.BuildLevel(vn, level) err = schema.BuildLevel(vn, idx, level)
if err != nil { if err != nil {
*errors = append(*errors, err) *errors = append(*errors, err)
return nil return nil

View File

@@ -111,7 +111,7 @@ additionalProperties: true `
mbErr := BuildModel(&rootNode, &sch) mbErr := BuildModel(&rootNode, &sch)
assert.NoError(t, mbErr) assert.NoError(t, mbErr)
schErr := sch.Build(rootNode.Content[0]) schErr := sch.Build(rootNode.Content[0], nil)
assert.NoError(t, schErr) assert.NoError(t, schErr)
assert.Equal(t, "something object", sch.Description.Value) assert.Equal(t, "something object", sch.Description.Value)
assert.True(t, sch.AdditionalProperties.Value.(bool)) assert.True(t, sch.AdditionalProperties.Value.(bool))

View File

@@ -2,6 +2,7 @@ package v3
import ( import (
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils" "github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@@ -28,14 +29,10 @@ type SecurityRequirement struct {
Value []low.ValueReference[map[low.KeyReference[string]][]low.ValueReference[string]] Value []low.ValueReference[map[low.KeyReference[string]][]low.ValueReference[string]]
} }
func (ss *SecurityScheme) Build(root *yaml.Node) error { func (ss *SecurityScheme) Build(root *yaml.Node, idx *index.SpecIndex) error {
extensionMap, err := ExtractExtensions(root) ss.Extensions = ExtractExtensions(root)
if err != nil {
return err
}
ss.Extensions = extensionMap
oa, oaErr := ExtractObject[*OAuthFlows](OAuthFlowsLabel, root) oa, oaErr := ExtractObject[*OAuthFlows](OAuthFlowsLabel, root, idx)
if oaErr != nil { if oaErr != nil {
return oaErr return oaErr
} }
@@ -57,7 +54,7 @@ func (sr *SecurityRequirement) FindRequirement(name string) []low.ValueReference
return nil return nil
} }
func (sr *SecurityRequirement) Build(root *yaml.Node) error { func (sr *SecurityRequirement) Build(root *yaml.Node, idx *index.SpecIndex) error {
if utils.IsNodeArray(root) { if utils.IsNodeArray(root) {
var requirements []low.ValueReference[map[low.KeyReference[string]][]low.ValueReference[string]] var requirements []low.ValueReference[map[low.KeyReference[string]][]low.ValueReference[string]]
for _, n := range root.Content { for _, n := range root.Content {

View File

@@ -2,6 +2,7 @@ package v3
import ( import (
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils" "github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@@ -17,7 +18,7 @@ type Server struct {
Variables low.NodeReference[map[string]low.NodeReference[*ServerVariable]] Variables low.NodeReference[map[string]low.NodeReference[*ServerVariable]]
} }
func (s *Server) Build(root *yaml.Node) error { func (s *Server) Build(root *yaml.Node, idx *index.SpecIndex) error {
kn, vars := utils.FindKeyNode(VariablesLabel, root.Content) kn, vars := utils.FindKeyNode(VariablesLabel, root.Content)
if vars == nil { if vars == nil {
return nil return nil

View File

@@ -2,6 +2,7 @@ package v3
import ( import (
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@@ -17,16 +18,11 @@ type Tag struct {
Extensions map[low.KeyReference[string]]low.ValueReference[any] Extensions map[low.KeyReference[string]]low.ValueReference[any]
} }
func (t *Tag) Build(root *yaml.Node) error { func (t *Tag) Build(root *yaml.Node, idx *index.SpecIndex) error {
// extract extensions t.Extensions = ExtractExtensions(root)
extensionMap, err := ExtractExtensions(root)
if err != nil {
return err
}
t.Extensions = extensionMap
// extract externalDocs // extract externalDocs
extDocs, dErr := ExtractObject[*ExternalDoc](ExternalDocsLabel, root) extDocs, dErr := ExtractObject[*ExternalDoc](ExternalDocsLabel, root, idx)
if dErr != nil { if dErr != nil {
return dErr return dErr
} }

View File

@@ -15,10 +15,6 @@ type XML struct {
} }
func (x *XML) Build(root *yaml.Node) error { func (x *XML) Build(root *yaml.Node) error {
extensionMap, err := ExtractExtensions(root) x.Extensions = ExtractExtensions(root)
if err != nil {
return err
}
x.Extensions = extensionMap
return nil return nil
} }

View File

@@ -1,13 +1,16 @@
package low package low
import "gopkg.in/yaml.v3" import (
"github.com/pb33f/libopenapi/index"
"gopkg.in/yaml.v3"
)
type HasNode interface { type HasNode interface {
GetNode() *yaml.Node GetNode() *yaml.Node
} }
type Buildable[T any] interface { type Buildable[T any] interface {
Build(node *yaml.Node) error Build(node *yaml.Node, idx *index.SpecIndex) error
*T *T
} }

View File

@@ -16,9 +16,9 @@ import (
) )
const ( const (
localResolve int = 0 LocalResolve int = 0
httpResolve int = 1 HttpResolve int = 1
fileResolve int = 2 FileResolve int = 2
) )
// Reference is a wrapper around *yaml.Node results to make things more manageable when performing // Reference is a wrapper around *yaml.Node results to make things more manageable when performing
@@ -72,7 +72,8 @@ type SpecIndex struct {
responsesRefs map[string]*Reference // top level responses responsesRefs map[string]*Reference // top level responses
headersRefs map[string]*Reference // top level responses headersRefs map[string]*Reference // top level responses
examplesRefs map[string]*Reference // top level examples examplesRefs map[string]*Reference // top level examples
linksRefs map[string]map[string][]*Reference // all links callbacksRefs map[string]map[string][]*Reference // all links
linksRefs map[string]map[string][]*Reference // all callbacks
operationTagsRefs map[string]map[string][]*Reference // tags found in operations operationTagsRefs map[string]map[string][]*Reference // tags found in operations
operationDescriptionRefs map[string]map[string]*Reference // descriptions in operations. operationDescriptionRefs map[string]map[string]*Reference // descriptions in operations.
operationSummaryRefs map[string]map[string]*Reference // summaries in operations operationSummaryRefs map[string]map[string]*Reference // summaries in operations
@@ -99,6 +100,7 @@ type SpecIndex struct {
globalHeadersCount int // component headers globalHeadersCount int // component headers
globalExamplesCount int // component examples globalExamplesCount int // component examples
globalLinksCount int // component links globalLinksCount int // component links
globalCallbacksCount int // component callbacks
globalCallbacks int // component callbacks. globalCallbacks int // component callbacks.
pathCount int // number of paths pathCount int // number of paths
operationCount int // number of operations operationCount int // number of operations
@@ -207,6 +209,7 @@ func NewSpecIndex(rootNode *yaml.Node) *SpecIndex {
index.responsesRefs = make(map[string]*Reference) index.responsesRefs = make(map[string]*Reference)
index.headersRefs = make(map[string]*Reference) index.headersRefs = make(map[string]*Reference)
index.examplesRefs = make(map[string]*Reference) index.examplesRefs = make(map[string]*Reference)
index.callbacksRefs = make(map[string]map[string][]*Reference)
index.linksRefs = make(map[string]map[string][]*Reference) index.linksRefs = make(map[string]map[string][]*Reference)
index.callbackRefs = make(map[string]*Reference) index.callbackRefs = make(map[string]*Reference)
index.externalSpecIndex = make(map[string]*SpecIndex) index.externalSpecIndex = make(map[string]*SpecIndex)
@@ -256,6 +259,7 @@ func NewSpecIndex(rootNode *yaml.Node) *SpecIndex {
index.GetInlineUniqueParamCount, index.GetInlineUniqueParamCount,
index.GetOperationTagsCount, index.GetOperationTagsCount,
index.GetGlobalLinksCount, index.GetGlobalLinksCount,
index.GetGlobalCallbacksCount,
} }
wg.Add(len(countFuncs)) wg.Add(len(countFuncs))
@@ -872,13 +876,59 @@ func (index *SpecIndex) GetTotalTagsCount() int {
return index.totalTagsCount return index.totalTagsCount
} }
// GetGlobalLinksCount for each response of each operation method, multiple links can be defined // GetGlobalCallbacksCount for each response of each operation method, multiple links can be defined
func (index *SpecIndex) GetGlobalCallbacksCount() int {
if index.root == nil {
return -1
}
if index.globalCallbacksCount > 0 {
return index.globalCallbacksCount
}
index.pathRefsLock.Lock()
for path, p := range index.pathRefs {
for _, m := range p {
// look through method for callbacks
callbacks, _ := yamlpath.NewPath("$..callbacks")
res, _ := callbacks.Find(m.Node)
if len(res) > 0 {
for _, callback := range res[0].Content {
if utils.IsNodeMap(callback) {
ref := &Reference{
Definition: m.Name,
Name: m.Name,
Node: callback,
}
if index.callbacksRefs[path] == nil {
index.callbacksRefs[path] = make(map[string][]*Reference)
}
if len(index.callbacksRefs[path][m.Name]) > 0 {
index.callbacksRefs[path][m.Name] = append(index.callbacksRefs[path][m.Name], ref)
}
index.callbacksRefs[path][m.Name] = []*Reference{ref}
index.globalCallbacksCount++
}
}
}
}
}
index.pathRefsLock.Unlock()
return index.globalCallbacksCount
}
// GetGlobalLinksCount for each response of each operation method, multiple callbacks can be defined
func (index *SpecIndex) GetGlobalLinksCount() int { func (index *SpecIndex) GetGlobalLinksCount() int {
if index.root == nil { if index.root == nil {
return -1 return -1
} }
if index.globalLinksCount > 0 { if index.globalCallbacksCount > 0 {
return index.globalLinksCount return index.globalLinksCount
} }
@@ -900,7 +950,6 @@ func (index *SpecIndex) GetGlobalLinksCount() int {
Name: m.Name, Name: m.Name,
Node: link, Node: link,
} }
if index.linksRefs[path] == nil { if index.linksRefs[path] == nil {
index.linksRefs[path] = make(map[string][]*Reference) index.linksRefs[path] = make(map[string][]*Reference)
} }
@@ -1421,17 +1470,17 @@ func (index *SpecIndex) FindComponent(componentId string, parent *yaml.Node) *Re
return index.lookupFileReference(id) return index.lookupFileReference(id)
} }
switch determineReferenceResolveType(componentId) { switch DetermineReferenceResolveType(componentId) {
case localResolve: // ideally, every single ref in every single spec is local. however, this is not the case. case LocalResolve: // ideally, every single ref in every single spec is local. however, this is not the case.
return index.findComponentInRoot(componentId) return index.FindComponentInRoot(componentId)
case httpResolve: case HttpResolve:
uri := strings.Split(componentId, "#") uri := strings.Split(componentId, "#")
if len(uri) == 2 { if len(uri) == 2 {
return index.performExternalLookup(uri, componentId, remoteLookup, parent) return index.performExternalLookup(uri, componentId, remoteLookup, parent)
} }
case fileResolve: case FileResolve:
uri := strings.Split(componentId, "#") uri := strings.Split(componentId, "#")
if len(uri) == 2 { if len(uri) == 2 {
return index.performExternalLookup(uri, componentId, fileLookup, parent) return index.performExternalLookup(uri, componentId, fileLookup, parent)
@@ -1450,23 +1499,23 @@ func (index *SpecIndex) GetAllSummariesCount() int {
return len(index.allSummaries) return len(index.allSummaries)
} }
/* private */ func DetermineReferenceResolveType(ref string) int {
func determineReferenceResolveType(ref string) int {
if ref != "" && ref[0] == '#' { if ref != "" && ref[0] == '#' {
return localResolve return LocalResolve
} }
if ref != "" && len(ref) >= 5 && (ref[:5] == "https" || ref[:5] == "http:") { if ref != "" && len(ref) >= 5 && (ref[:5] == "https" || ref[:5] == "http:") {
return httpResolve return HttpResolve
} }
if strings.Contains(ref, ".json") || if strings.Contains(ref, ".json") ||
strings.Contains(ref, ".yaml") || strings.Contains(ref, ".yaml") ||
strings.Contains(ref, ".yml") { strings.Contains(ref, ".yml") {
return fileResolve return FileResolve
} }
return -1 return -1
} }
/* private */
func (index *SpecIndex) extractDefinitionsAndSchemas(schemasNode *yaml.Node, pathPrefix string) { func (index *SpecIndex) extractDefinitionsAndSchemas(schemasNode *yaml.Node, pathPrefix string) {
var name string var name string
for i, schema := range schemasNode.Content { for i, schema := range schemasNode.Content {
@@ -1650,7 +1699,7 @@ func (index *SpecIndex) performExternalLookup(uri []string, componentId string,
} else { } else {
foundRef := externalSpecIndex.findComponentInRoot(uri[1]) foundRef := externalSpecIndex.FindComponentInRoot(uri[1])
if foundRef != nil { if foundRef != nil {
foundNode = foundRef.Node foundNode = foundRef.Node
} }
@@ -1670,7 +1719,7 @@ func (index *SpecIndex) performExternalLookup(uri []string, componentId string,
return nil return nil
} }
func (index *SpecIndex) findComponentInRoot(componentId string) *Reference { func (index *SpecIndex) FindComponentInRoot(componentId string) *Reference {
name, friendlySearch := utils.ConvertComponentIdIntoFriendlyPathSearch(componentId) name, friendlySearch := utils.ConvertComponentIdIntoFriendlyPathSearch(componentId)

View File

@@ -348,7 +348,7 @@ func TestSpecIndex_TestEmptyBrokenReferences(t *testing.T) {
assert.Equal(t, 2, index.GetGlobalTagsCount()) assert.Equal(t, 2, index.GetGlobalTagsCount())
assert.Equal(t, 3, index.GetTotalTagsCount()) assert.Equal(t, 3, index.GetTotalTagsCount())
assert.Equal(t, 2, index.GetOperationTagsCount()) assert.Equal(t, 2, index.GetOperationTagsCount())
assert.Equal(t, 2, index.GetGlobalLinksCount()) assert.Equal(t, 4, index.GetGlobalLinksCount())
assert.Equal(t, 0, index.GetComponentParameterCount()) assert.Equal(t, 0, index.GetComponentParameterCount())
assert.Equal(t, 2, index.GetOperationsParameterCount()) assert.Equal(t, 2, index.GetOperationsParameterCount())
assert.Equal(t, 1, index.GetInlineDuplicateParamCount()) assert.Equal(t, 1, index.GetInlineDuplicateParamCount())

View File

@@ -5,7 +5,6 @@ import (
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
v3 "github.com/pb33f/libopenapi/datamodel/low/3.0" v3 "github.com/pb33f/libopenapi/datamodel/low/3.0"
"github.com/pb33f/libopenapi/index" "github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/resolver"
"github.com/pb33f/libopenapi/utils" "github.com/pb33f/libopenapi/utils"
"sync" "sync"
) )
@@ -15,26 +14,27 @@ func CreateDocument(info *datamodel.SpecInfo) (*v3.Document, error) {
doc := v3.Document{Version: low.NodeReference[string]{Value: info.Version, ValueNode: info.RootNode}} doc := v3.Document{Version: low.NodeReference[string]{Value: info.Version, ValueNode: info.RootNode}}
// build an index // build an index
rsolvr := resolver.NewResolver(index.NewSpecIndex(info.RootNode)) idx := index.NewSpecIndex(info.RootNode)
//rsolvr := resolver.NewResolver()
// todo handle errors // todo handle errors
rsolvr.Resolve() //rsolvr.Resolve()
var wg sync.WaitGroup var wg sync.WaitGroup
var errors []error var errors []error
var runExtraction = func(info *datamodel.SpecInfo, doc *v3.Document, var runExtraction = func(info *datamodel.SpecInfo, doc *v3.Document, idx *index.SpecIndex,
runFunc func(i *datamodel.SpecInfo, d *v3.Document) error, runFunc func(i *datamodel.SpecInfo, d *v3.Document, idx *index.SpecIndex) error,
ers *[]error, ers *[]error,
wg *sync.WaitGroup) { wg *sync.WaitGroup) {
if er := runFunc(info, doc); er != nil { if er := runFunc(info, doc, idx); er != nil {
*ers = append(*ers, er) *ers = append(*ers, er)
} }
wg.Done() wg.Done()
} }
extractionFuncs := []func(i *datamodel.SpecInfo, d *v3.Document) error{ extractionFuncs := []func(i *datamodel.SpecInfo, d *v3.Document, idx *index.SpecIndex) error{
extractInfo, extractInfo,
extractServers, extractServers,
extractTags, extractTags,
@@ -45,7 +45,7 @@ func CreateDocument(info *datamodel.SpecInfo) (*v3.Document, error) {
} }
wg.Add(len(extractionFuncs)) wg.Add(len(extractionFuncs))
for _, f := range extractionFuncs { for _, f := range extractionFuncs {
go runExtraction(info, &doc, f, &errors, &wg) go runExtraction(info, &doc, idx, f, &errors, &wg)
} }
wg.Wait() wg.Wait()
@@ -56,7 +56,7 @@ func CreateDocument(info *datamodel.SpecInfo) (*v3.Document, error) {
return &doc, nil return &doc, nil
} }
func extractInfo(info *datamodel.SpecInfo, doc *v3.Document) error { func extractInfo(info *datamodel.SpecInfo, doc *v3.Document, idx *index.SpecIndex) error {
_, ln, vn := utils.FindKeyNodeFull(v3.InfoLabel, info.RootNode.Content) _, ln, vn := utils.FindKeyNodeFull(v3.InfoLabel, info.RootNode.Content)
if vn != nil { if vn != nil {
ir := v3.Info{} ir := v3.Info{}
@@ -71,8 +71,8 @@ func extractInfo(info *datamodel.SpecInfo, doc *v3.Document) error {
return nil return nil
} }
func extractSecurity(info *datamodel.SpecInfo, doc *v3.Document) error { func extractSecurity(info *datamodel.SpecInfo, doc *v3.Document, idx *index.SpecIndex) error {
sec, sErr := v3.ExtractObject[*v3.SecurityRequirement](v3.SecurityLabel, info.RootNode) sec, sErr := v3.ExtractObject[*v3.SecurityRequirement](v3.SecurityLabel, info.RootNode, idx)
if sErr != nil { if sErr != nil {
return sErr return sErr
} }
@@ -80,8 +80,8 @@ func extractSecurity(info *datamodel.SpecInfo, doc *v3.Document) error {
return nil return nil
} }
func extractExternalDocs(info *datamodel.SpecInfo, doc *v3.Document) error { func extractExternalDocs(info *datamodel.SpecInfo, doc *v3.Document, idx *index.SpecIndex) error {
extDocs, dErr := v3.ExtractObject[*v3.ExternalDoc](v3.ExternalDocsLabel, info.RootNode) extDocs, dErr := v3.ExtractObject[*v3.ExternalDoc](v3.ExternalDocsLabel, info.RootNode, idx)
if dErr != nil { if dErr != nil {
return dErr return dErr
} }
@@ -89,7 +89,7 @@ func extractExternalDocs(info *datamodel.SpecInfo, doc *v3.Document) error {
return nil return nil
} }
func extractComponents(info *datamodel.SpecInfo, doc *v3.Document) error { func extractComponents(info *datamodel.SpecInfo, doc *v3.Document, idx *index.SpecIndex) error {
_, ln, vn := utils.FindKeyNodeFull(v3.ComponentsLabel, info.RootNode.Content) _, ln, vn := utils.FindKeyNodeFull(v3.ComponentsLabel, info.RootNode.Content)
if vn != nil { if vn != nil {
ir := v3.Components{} ir := v3.Components{}
@@ -97,14 +97,14 @@ func extractComponents(info *datamodel.SpecInfo, doc *v3.Document) error {
if err != nil { if err != nil {
return err return err
} }
err = ir.Build(vn) err = ir.Build(vn, idx)
nr := low.NodeReference[*v3.Components]{Value: &ir, ValueNode: vn, KeyNode: ln} nr := low.NodeReference[*v3.Components]{Value: &ir, ValueNode: vn, KeyNode: ln}
doc.Components = nr doc.Components = nr
} }
return nil return nil
} }
func extractServers(info *datamodel.SpecInfo, doc *v3.Document) error { func extractServers(info *datamodel.SpecInfo, doc *v3.Document, idx *index.SpecIndex) error {
_, ln, vn := utils.FindKeyNodeFull(v3.ServersLabel, info.RootNode.Content) _, ln, vn := utils.FindKeyNodeFull(v3.ServersLabel, info.RootNode.Content)
if vn != nil { if vn != nil {
if utils.IsNodeArray(vn) { if utils.IsNodeArray(vn) {
@@ -116,7 +116,7 @@ func extractServers(info *datamodel.SpecInfo, doc *v3.Document) error {
if err != nil { if err != nil {
return err return err
} }
srvr.Build(srvN) srvr.Build(srvN, idx)
servers = append(servers, low.ValueReference[*v3.Server]{ servers = append(servers, low.ValueReference[*v3.Server]{
Value: &srvr, Value: &srvr,
ValueNode: srvN, ValueNode: srvN,
@@ -133,7 +133,7 @@ func extractServers(info *datamodel.SpecInfo, doc *v3.Document) error {
return nil return nil
} }
func extractTags(info *datamodel.SpecInfo, doc *v3.Document) error { func extractTags(info *datamodel.SpecInfo, doc *v3.Document, idx *index.SpecIndex) error {
_, ln, vn := utils.FindKeyNodeFull(v3.TagsLabel, info.RootNode.Content) _, ln, vn := utils.FindKeyNodeFull(v3.TagsLabel, info.RootNode.Content)
if vn != nil { if vn != nil {
if utils.IsNodeArray(vn) { if utils.IsNodeArray(vn) {
@@ -145,7 +145,7 @@ func extractTags(info *datamodel.SpecInfo, doc *v3.Document) error {
if err != nil { if err != nil {
return err return err
} }
tag.Build(tagN) tag.Build(tagN, idx)
tags = append(tags, low.ValueReference[*v3.Tag]{ tags = append(tags, low.ValueReference[*v3.Tag]{
Value: &tag, Value: &tag,
ValueNode: tagN, ValueNode: tagN,
@@ -162,11 +162,11 @@ func extractTags(info *datamodel.SpecInfo, doc *v3.Document) error {
return nil return nil
} }
func extractPaths(info *datamodel.SpecInfo, doc *v3.Document) error { func extractPaths(info *datamodel.SpecInfo, doc *v3.Document, idx *index.SpecIndex) error {
_, ln, vn := utils.FindKeyNodeFull(v3.PathsLabel, info.RootNode.Content) _, ln, vn := utils.FindKeyNodeFull(v3.PathsLabel, info.RootNode.Content)
if vn != nil { if vn != nil {
ir := v3.Paths{} ir := v3.Paths{}
err := ir.Build(vn) err := ir.Build(vn, idx)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -24,6 +24,17 @@ func BenchmarkCreateDocument(b *testing.B) {
} }
} }
func BenchmarkCreateDocument_Stripe(b *testing.B) {
data, _ := ioutil.ReadFile("../test_specs/stripe.yaml")
info, _ := datamodel.ExtractSpecInfo(data)
for i := 0; i < b.N; i++ {
_, err := CreateDocument(info)
if err != nil {
panic("this should not error")
}
}
}
func TestCreateDocument(t *testing.T) { func TestCreateDocument(t *testing.T) {
assert.Equal(t, "3.0.1", doc.Version.Value) assert.Equal(t, "3.0.1", doc.Version.Value)
assert.Equal(t, "Burger Shop", doc.Info.Value.Title.Value) assert.Equal(t, "Burger Shop", doc.Info.Value.Title.Value)
@@ -254,8 +265,9 @@ func TestCreateDocument_Components_Schemas(t *testing.T) {
assert.NotNil(t, fries.Value) assert.NotNil(t, fries.Value)
assert.Len(t, fries.Value.Properties.Value, 3) assert.Len(t, fries.Value.Properties.Value, 3)
p := fries.Value.FindProperty("favoriteDrink")
assert.Equal(t, "a frosty cold beverage can be coke or sprite", assert.Equal(t, "a frosty cold beverage can be coke or sprite",
fries.Value.FindProperty("favoriteDrink").Value.Description.Value) p.Value.Description.Value)
} }

View File

@@ -372,6 +372,17 @@ func IsNodeBoolValue(node *yaml.Node) bool {
return node.Tag == "!!bool" return node.Tag == "!!bool"
} }
func IsNodeRefValue(node *yaml.Node) (bool, *yaml.Node, string) {
for i, r := range node.Content {
if i%2 == 0 {
if r.Value == "$ref" {
return true, r, node.Content[i+1].Value
}
}
}
return false, nil, ""
}
// FixContext will clean up a JSONpath string to be correctly traversable. // FixContext will clean up a JSONpath string to be correctly traversable.
func FixContext(context string) string { func FixContext(context string) string {