mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-08 04:20:17 +00:00
Components are in, writing new content for them and tests!
And, thats basically it (almost)
This commit is contained in:
@@ -1,19 +1,174 @@
|
|||||||
package v3
|
package v3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gopkg.in/yaml.v3"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"net/http"
|
"github.com/pb33f/libopenapi/utils"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ComponentsLabel = "components"
|
||||||
|
SchemasLabel = "schemas"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Components struct {
|
type Components struct {
|
||||||
Node *yaml.Node
|
Schemas low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Schema]]
|
||||||
Schemas map[string]Schema
|
Responses low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Response]]
|
||||||
Responses map[string]Response
|
Parameters low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Parameter]]
|
||||||
Parameters map[string]Parameter
|
Examples low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Example]]
|
||||||
Examples map[string]Example
|
RequestBodies low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*RequestBody]]
|
||||||
RequestBodies map[string]RequestBody
|
Headers low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Header]]
|
||||||
Headers map[string]http.Header
|
SecuritySchemes low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*SecurityScheme]]
|
||||||
SecuritySchemes map[string]SecurityScheme
|
Links low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Link]]
|
||||||
Links map[string]Link
|
Callbacks low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Callback]]
|
||||||
Callbacks map[string]Callback
|
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (co *Components) FindSchema(schema string) *low.ValueReference[*Schema] {
|
||||||
|
return FindItemInMap[*Schema](schema, co.Schemas.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (co *Components) FindResponse(response string) *low.ValueReference[*Response] {
|
||||||
|
return FindItemInMap[*Response](response, co.Responses.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (co *Components) Build(root *yaml.Node) error {
|
||||||
|
extensionMap, err := ExtractExtensions(root)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
co.Extensions = extensionMap
|
||||||
|
|
||||||
|
// build out components asynchronously for speed. There could be some significant weight here.
|
||||||
|
skipChan := make(chan bool)
|
||||||
|
errorChan := make(chan error)
|
||||||
|
paramChan := make(chan low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Parameter]])
|
||||||
|
schemaChan := make(chan low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Schema]])
|
||||||
|
responsesChan := make(chan low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Response]])
|
||||||
|
examplesChan := make(chan low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Example]])
|
||||||
|
requestBodiesChan := make(chan low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*RequestBody]])
|
||||||
|
headersChan := make(chan low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Header]])
|
||||||
|
securitySchemesChan := make(chan low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*SecurityScheme]])
|
||||||
|
linkChan := make(chan low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Link]])
|
||||||
|
callbackChan := make(chan low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Callback]])
|
||||||
|
|
||||||
|
go extractComponentValues[*Schema](SchemasLabel, root, skipChan, errorChan, schemaChan)
|
||||||
|
go extractComponentValues[*Parameter](ParametersLabel, root, skipChan, errorChan, paramChan)
|
||||||
|
go extractComponentValues[*Response](ResponsesLabel, root, skipChan, errorChan, responsesChan)
|
||||||
|
go extractComponentValues[*Example](ExamplesLabel, root, skipChan, errorChan, examplesChan)
|
||||||
|
go extractComponentValues[*RequestBody](RequestBodiesLabel, root, skipChan, errorChan, requestBodiesChan)
|
||||||
|
go extractComponentValues[*Header](HeadersLabel, root, skipChan, errorChan, headersChan)
|
||||||
|
go extractComponentValues[*SecurityScheme](SecuritySchemesLabel, root, skipChan, errorChan, securitySchemesChan)
|
||||||
|
go extractComponentValues[*Link](LinksLabel, root, skipChan, errorChan, linkChan)
|
||||||
|
go extractComponentValues[*Callback](CallbacksLabel, root, skipChan, errorChan, callbackChan)
|
||||||
|
|
||||||
|
n := 0
|
||||||
|
total := 9
|
||||||
|
allDone:
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case buildError := <-errorChan:
|
||||||
|
return buildError
|
||||||
|
case <-skipChan:
|
||||||
|
n++
|
||||||
|
if n == total {
|
||||||
|
break allDone
|
||||||
|
}
|
||||||
|
case params := <-paramChan:
|
||||||
|
co.Parameters = params
|
||||||
|
n++
|
||||||
|
if n == total {
|
||||||
|
break allDone
|
||||||
|
}
|
||||||
|
case schemas := <-schemaChan:
|
||||||
|
co.Schemas = schemas
|
||||||
|
n++
|
||||||
|
if n == total {
|
||||||
|
break allDone
|
||||||
|
}
|
||||||
|
case responses := <-responsesChan:
|
||||||
|
co.Responses = responses
|
||||||
|
n++
|
||||||
|
if n == total {
|
||||||
|
break allDone
|
||||||
|
}
|
||||||
|
case examples := <-examplesChan:
|
||||||
|
co.Examples = examples
|
||||||
|
n++
|
||||||
|
if n == total {
|
||||||
|
break allDone
|
||||||
|
}
|
||||||
|
case reqBody := <-requestBodiesChan:
|
||||||
|
co.RequestBodies = reqBody
|
||||||
|
n++
|
||||||
|
if n == total {
|
||||||
|
break allDone
|
||||||
|
}
|
||||||
|
case headers := <-headersChan:
|
||||||
|
co.Headers = headers
|
||||||
|
n++
|
||||||
|
if n == total {
|
||||||
|
break allDone
|
||||||
|
}
|
||||||
|
case sScheme := <-securitySchemesChan:
|
||||||
|
co.SecuritySchemes = sScheme
|
||||||
|
n++
|
||||||
|
if n == total {
|
||||||
|
break allDone
|
||||||
|
}
|
||||||
|
case links := <-linkChan:
|
||||||
|
co.Links = links
|
||||||
|
n++
|
||||||
|
if n == total {
|
||||||
|
break allDone
|
||||||
|
}
|
||||||
|
case callbacks := <-callbackChan:
|
||||||
|
co.Callbacks = callbacks
|
||||||
|
n++
|
||||||
|
if n == total {
|
||||||
|
break allDone
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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]]) {
|
||||||
|
_, nodeLabel, nodeValue := utils.FindKeyNodeFull(label, root.Content)
|
||||||
|
if nodeValue == nil {
|
||||||
|
skip <- true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var currentLabel *yaml.Node
|
||||||
|
componentValues := make(map[low.KeyReference[string]]low.ValueReference[T])
|
||||||
|
for i, v := range nodeValue.Content {
|
||||||
|
if i%2 == 0 {
|
||||||
|
currentLabel = v
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var n T = new(N)
|
||||||
|
err := BuildModel(v, n)
|
||||||
|
if err != nil {
|
||||||
|
errorChan <- err
|
||||||
|
}
|
||||||
|
err = n.Build(v)
|
||||||
|
if err != nil {
|
||||||
|
errorChan <- err
|
||||||
|
}
|
||||||
|
componentValues[low.KeyReference[string]{
|
||||||
|
KeyNode: currentLabel,
|
||||||
|
Value: currentLabel.Value,
|
||||||
|
}] = low.ValueReference[T]{
|
||||||
|
Value: n,
|
||||||
|
ValueNode: v,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
results := low.NodeReference[map[low.KeyReference[string]]low.ValueReference[T]]{
|
||||||
|
KeyNode: nodeLabel,
|
||||||
|
ValueNode: nodeValue,
|
||||||
|
Value: componentValues,
|
||||||
|
}
|
||||||
|
resultChan <- results
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ func ExtractSchema(root *yaml.Node) (*low.NodeReference[*Schema], error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = schema.Build(schNode, 0)
|
err = schema.Build(schNode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ParametersLabel = "parameters"
|
ParametersLabel = "parameters"
|
||||||
RequestBodyLabel = "requestBody"
|
RequestBodyLabel = "requestBody"
|
||||||
ResponsesLabel = "responses"
|
RequestBodiesLabel = "requestBodies"
|
||||||
CallbacksLabel = "callbacks"
|
ResponsesLabel = "responses"
|
||||||
|
CallbacksLabel = "callbacks"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Operation struct {
|
type Operation struct {
|
||||||
|
|||||||
@@ -189,9 +189,11 @@ allDone:
|
|||||||
case buildError := <-opErrorChan:
|
case buildError := <-opErrorChan:
|
||||||
return buildError
|
return buildError
|
||||||
case <-opBuildChan:
|
case <-opBuildChan:
|
||||||
if n == len(ops)-1 {
|
n++
|
||||||
|
if n == len(ops) {
|
||||||
break allDone
|
break allDone
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,11 @@ 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, level int) error {
|
func (s *Schema) Build(root *yaml.Node) error {
|
||||||
|
return s.BuildLevel(root, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Schema) BuildLevel(root *yaml.Node, level int) error {
|
||||||
level++
|
level++
|
||||||
if level > 50 {
|
if level > 50 {
|
||||||
return nil // we're done, son! too fricken deep.
|
return nil // we're done, son! too fricken deep.
|
||||||
@@ -152,7 +156,7 @@ func (s *Schema) Build(root *yaml.Node, level int) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = property.Build(prop, level)
|
err = property.BuildLevel(prop, level)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -245,7 +249,7 @@ func buildSchema(schemas *[]low.NodeReference[*Schema], attribute string, rootNo
|
|||||||
*errors = append(*errors, err)
|
*errors = append(*errors, err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
err = schema.Build(vn, level)
|
err = schema.BuildLevel(vn, level)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
*errors = append(*errors, err)
|
*errors = append(*errors, err)
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -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], 0)
|
schErr := sch.Build(rootNode.Content[0])
|
||||||
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))
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SecurityLabel = "security"
|
SecurityLabel = "security"
|
||||||
|
SecuritySchemesLabel = "securitySchemes"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SecurityScheme struct {
|
type SecurityScheme struct {
|
||||||
@@ -47,39 +48,7 @@ func (sr *SecurityRequirement) FindRequirement(name string) []low.ValueReference
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sr *SecurityRequirement) Build(root *yaml.Node) error {
|
func (sr *SecurityRequirement) Build(root *yaml.Node) error {
|
||||||
|
|
||||||
//if utils.IsNodeArray(root) {
|
|
||||||
// var currSec *yaml.Node
|
|
||||||
// var requirements []low.ValueReference[map[low.KeyReference[string]][]low.ValueReference[string]]
|
|
||||||
// for i, n := range root.Content {
|
|
||||||
// if i%2 == 0 {
|
|
||||||
// currSec = n
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
// if utils.IsNodeArray(n) {
|
|
||||||
// res := make(map[low.KeyReference[string]][]low.ValueReference[string])
|
|
||||||
// var dat []low.ValueReference[string]
|
|
||||||
// for _, r := range n.Content {
|
|
||||||
// dat = append(dat, low.ValueReference[string]{
|
|
||||||
// Value: r.Value,
|
|
||||||
// ValueNode: r,
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// res[low.KeyReference[string]{
|
|
||||||
// Value: currSec.Value,
|
|
||||||
// KeyNode: currSec,
|
|
||||||
// }] = dat
|
|
||||||
// requirements = append(requirements, low.ValueReference[map[low.KeyReference[string]][]low.ValueReference[string]]{
|
|
||||||
// Value: res,
|
|
||||||
// ValueNode: n,
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// sr.Value = requirements
|
|
||||||
//}
|
|
||||||
|
|
||||||
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 {
|
||||||
var currSec *yaml.Node
|
var currSec *yaml.Node
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ func CreateDocument(info *datamodel.SpecInfo) (*v3.Document, error) {
|
|||||||
extractServers,
|
extractServers,
|
||||||
extractTags,
|
extractTags,
|
||||||
extractPaths,
|
extractPaths,
|
||||||
|
extractComponents,
|
||||||
}
|
}
|
||||||
wg.Add(len(extractionFuncs))
|
wg.Add(len(extractionFuncs))
|
||||||
for _, f := range extractionFuncs {
|
for _, f := range extractionFuncs {
|
||||||
@@ -68,6 +69,21 @@ func extractInfo(info *datamodel.SpecInfo, doc *v3.Document) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func extractComponents(info *datamodel.SpecInfo, doc *v3.Document) error {
|
||||||
|
_, ln, vn := utils.FindKeyNodeFull(v3.ComponentsLabel, info.RootNode.Content)
|
||||||
|
if vn != nil {
|
||||||
|
ir := v3.Components{}
|
||||||
|
err := v3.BuildModel(vn, &ir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = ir.Build(vn)
|
||||||
|
nr := low.NodeReference[*v3.Components]{Value: &ir, ValueNode: vn, KeyNode: ln}
|
||||||
|
doc.Components = nr
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func extractServers(info *datamodel.SpecInfo, doc *v3.Document) error {
|
func extractServers(info *datamodel.SpecInfo, doc *v3.Document) 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 {
|
||||||
|
|||||||
@@ -235,3 +235,26 @@ func TestCreateDocument_Paths(t *testing.T) {
|
|||||||
assert.Equal(t, "https://pb33f.io", servers[0].Value.URL.Value)
|
assert.Equal(t, "https://pb33f.io", servers[0].Value.URL.Value)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCreateDocument_Components_Schemas(t *testing.T) {
|
||||||
|
|
||||||
|
components := doc.Components.Value
|
||||||
|
assert.NotNil(t, components)
|
||||||
|
assert.Len(t, components.Schemas.Value, 5)
|
||||||
|
|
||||||
|
burger := components.FindSchema("Burger")
|
||||||
|
assert.NotNil(t, burger.Value)
|
||||||
|
assert.Equal(t, "The tastiest food on the planet you would love to eat everyday", burger.Value.Description.Value)
|
||||||
|
|
||||||
|
er := components.FindSchema("Error")
|
||||||
|
assert.NotNil(t, er.Value)
|
||||||
|
assert.Equal(t, "Error defining what went wrong when providing a specification. The message should help indicate the issue clearly.", er.Value.Description.Value)
|
||||||
|
|
||||||
|
fries := components.FindSchema("Fries")
|
||||||
|
assert.NotNil(t, fries.Value)
|
||||||
|
|
||||||
|
assert.Len(t, fries.Value.Properties.Value, 3)
|
||||||
|
assert.Equal(t, "a frosty cold beverage can be coke or sprite",
|
||||||
|
fries.Value.FindProperty("favoriteDrink").Value.Description.Value)
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user