Building out 2.0 low model

This commit is contained in:
Dave Shanley
2022-09-02 10:38:14 -04:00
parent 68743113ed
commit c1c45a8362
16 changed files with 917 additions and 68 deletions

View File

@@ -38,7 +38,9 @@ type Components struct {
func NewComponents(comp *low.Components) *Components {
c := new(Components)
c.low = comp
if len(comp.Extensions) > 0 {
c.Extensions = high.ExtractExtensions(comp.Extensions)
}
cbMap := make(map[string]*Callback)
linkMap := make(map[string]*Link)
responseMap := make(map[string]*Response)

View File

@@ -45,9 +45,15 @@ func NewDocument(document *low.Document) *Document {
if !document.ExternalDocs.IsEmpty() {
d.ExternalDocs = NewExternalDoc(document.ExternalDocs.Value)
}
if len(document.Extensions) > 0 {
d.Extensions = high.ExtractExtensions(document.Extensions)
}
if !document.Components.IsEmpty() {
d.Components = NewComponents(document.Components.Value)
}
if !document.Paths.IsEmpty() {
d.Paths = NewPaths(document.Paths.Value)
}
d.Index = document.Index
return d
}

View File

@@ -6,20 +6,199 @@ package v2
import (
"github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/datamodel/low/base"
"github.com/pb33f/libopenapi/index"
"gopkg.in/yaml.v3"
)
const (
DefinitionsLabel = "definitions"
)
type ParameterDefinitions struct {
Parameters low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Parameter]]
Definitions map[low.KeyReference[string]]low.ValueReference[*Parameter]
}
type ResponsesDefinitions struct {
Definitions map[low.KeyReference[string]]low.ValueReference[*Response]
}
type SecurityDefinitions struct {
Definitions map[low.KeyReference[string]]low.ValueReference[*SecurityScheme]
}
type Definitions struct {
Schemas low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*base.SchemaProxy]]
Schemas map[low.KeyReference[string]]low.ValueReference[*base.SchemaProxy]
}
func (d *Definitions) FindSchema(schema string) *low.ValueReference[*base.SchemaProxy] {
return low.FindItemInMap[*base.SchemaProxy](schema, d.Schemas.Value)
return low.FindItemInMap[*base.SchemaProxy](schema, d.Schemas)
}
func (pd *ParameterDefinitions) FindSchema(schema string) *low.ValueReference[*Parameter] {
return low.FindItemInMap[*Parameter](schema, pd.Parameters.Value)
func (pd *ParameterDefinitions) FindParameter(schema string) *low.ValueReference[*Parameter] {
return low.FindItemInMap[*Parameter](schema, pd.Definitions)
}
func (r *ResponsesDefinitions) FindResponse(schema string) *low.ValueReference[*Response] {
return low.FindItemInMap[*Response](schema, r.Definitions)
}
func (s *SecurityDefinitions) FindSecurityScheme(schema string) *low.ValueReference[*SecurityScheme] {
return low.FindItemInMap[*SecurityScheme](schema, s.Definitions)
}
func (d *Definitions) Build(root *yaml.Node, idx *index.SpecIndex) error {
errorChan := make(chan error)
resultChan := make(chan definitionResult)
var defLabel *yaml.Node
totalDefinitions := 0
for i := range root.Content {
if i%2 == 0 {
defLabel = root.Content[i]
continue
}
totalDefinitions++
var buildFunc = func(label *yaml.Node, value *yaml.Node, idx *index.SpecIndex, r chan definitionResult, e chan error) {
obj, err := low.ExtractObjectRaw[*base.SchemaProxy](value, idx)
if err != nil {
e <- err
}
r <- definitionResult{k: label, v: low.ValueReference[any]{Value: obj, ValueNode: value}}
}
go buildFunc(defLabel, root.Content[i], idx, resultChan, errorChan)
}
completedDefs := 0
results := make(map[low.KeyReference[string]]low.ValueReference[*base.SchemaProxy])
for completedDefs < totalDefinitions {
select {
case err := <-errorChan:
return err
case sch := <-resultChan:
results[low.KeyReference[string]{
Value: sch.k.Value,
KeyNode: sch.k,
}] = sch.v.(low.ValueReference[*base.SchemaProxy])
}
}
d.Schemas = results
return nil
}
func (pd *ParameterDefinitions) Build(root *yaml.Node, idx *index.SpecIndex) error {
errorChan := make(chan error)
resultChan := make(chan definitionResult)
var defLabel *yaml.Node
totalDefinitions := 0
for i := range root.Content {
if i%2 == 0 {
defLabel = root.Content[i]
continue
}
totalDefinitions++
var buildFunc = func(label *yaml.Node, value *yaml.Node, idx *index.SpecIndex, r chan definitionResult, e chan error) {
obj, err := low.ExtractObjectRaw[*Parameter](value, idx)
if err != nil {
e <- err
}
r <- definitionResult{k: label, v: low.ValueReference[any]{Value: obj, ValueNode: value}}
}
go buildFunc(defLabel, root.Content[i], idx, resultChan, errorChan)
}
completedDefs := 0
results := make(map[low.KeyReference[string]]low.ValueReference[*Parameter])
for completedDefs < totalDefinitions {
select {
case err := <-errorChan:
return err
case sch := <-resultChan:
results[low.KeyReference[string]{
Value: sch.k.Value,
KeyNode: sch.k,
}] = sch.v.(low.ValueReference[*Parameter])
}
}
pd.Definitions = results
return nil
}
type definitionResult struct {
k *yaml.Node
v any
}
func (r *ResponsesDefinitions) Build(root *yaml.Node, idx *index.SpecIndex) error {
errorChan := make(chan error)
resultChan := make(chan definitionResult)
var defLabel *yaml.Node
totalDefinitions := 0
for i := range root.Content {
if i%2 == 0 {
defLabel = root.Content[i]
continue
}
totalDefinitions++
var buildFunc = func(label *yaml.Node, value *yaml.Node, idx *index.SpecIndex, r chan definitionResult, e chan error) {
obj, err := low.ExtractObjectRaw[*Response](value, idx)
if err != nil {
e <- err
}
r <- definitionResult{k: label, v: low.ValueReference[any]{Value: obj, ValueNode: value}}
}
go buildFunc(defLabel, root.Content[i], idx, resultChan, errorChan)
}
completedDefs := 0
results := make(map[low.KeyReference[string]]low.ValueReference[*Response])
for completedDefs < totalDefinitions {
select {
case err := <-errorChan:
return err
case sch := <-resultChan:
results[low.KeyReference[string]{
Value: sch.k.Value,
KeyNode: sch.k,
}] = sch.v.(low.ValueReference[*Response])
}
}
r.Definitions = results
return nil
}
func (s *SecurityDefinitions) Build(root *yaml.Node, idx *index.SpecIndex) error {
errorChan := make(chan error)
resultChan := make(chan definitionResult)
var defLabel *yaml.Node
totalDefinitions := 0
for i := range root.Content {
if i%2 == 0 {
defLabel = root.Content[i]
continue
}
totalDefinitions++
var buildFunc = func(label *yaml.Node, value *yaml.Node, idx *index.SpecIndex, r chan definitionResult, e chan error) {
obj, err := low.ExtractObjectRaw[*SecurityScheme](value, idx)
if err != nil {
e <- err
}
r <- definitionResult{k: label, v: low.ValueReference[any]{Value: obj, ValueNode: value}}
}
go buildFunc(defLabel, root.Content[i], idx, resultChan, errorChan)
}
completedDefs := 0
results := make(map[low.KeyReference[string]]low.ValueReference[*SecurityScheme])
for completedDefs < totalDefinitions {
select {
case err := <-errorChan:
return err
case sch := <-resultChan:
results[low.KeyReference[string]{
Value: sch.k.Value,
KeyNode: sch.k,
}] = sch.v.(low.ValueReference[*SecurityScheme])
}
}
s.Definitions = results
return nil
}

View File

@@ -0,0 +1,64 @@
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
// SPDX-License-Identifier: MIT
package v2
import (
"github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3"
)
type Examples struct {
Values map[low.KeyReference[string]]low.ValueReference[any]
}
func (e *Examples) Build(root *yaml.Node, _ *index.SpecIndex) error {
var keyNode, currNode *yaml.Node
var err error
for i := range root.Content {
if i%2 == 0 {
keyNode = root.Content[i]
continue
}
currNode = root.Content[i]
if utils.IsNodeMap(currNode) {
var n map[string]interface{}
err = currNode.Decode(&n)
if err != nil {
var k []interface{}
err = currNode.Decode(&k)
if err != nil {
// lets just default to interface
var j interface{}
_ = currNode.Decode(&j)
e.Values[low.KeyReference[string]{
Value: keyNode.Value,
KeyNode: keyNode,
}] = low.ValueReference[any]{
Value: j,
ValueNode: currNode,
}
continue
}
e.Values[low.KeyReference[string]{
Value: keyNode.Value,
KeyNode: keyNode,
}] = low.ValueReference[any]{
Value: k,
ValueNode: currNode,
}
continue
}
e.Values[low.KeyReference[string]{
Value: keyNode.Value,
KeyNode: keyNode,
}] = low.ValueReference[any]{
Value: n,
ValueNode: currNode,
}
}
}
return nil
}

View File

@@ -9,6 +9,10 @@ import (
"gopkg.in/yaml.v3"
)
const (
HeadersLabel = "headers"
)
type Header struct {
Type low.NodeReference[string]
Format low.NodeReference[string]
@@ -42,4 +46,3 @@ func (h *Header) Build(root *yaml.Node, idx *index.SpecIndex) error {
return nil
}

View File

@@ -0,0 +1,72 @@
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
// SPDX-License-Identifier: MIT
package v2
import (
"github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/datamodel/low/base"
"github.com/pb33f/libopenapi/index"
"gopkg.in/yaml.v3"
)
type Operation struct {
Tags low.NodeReference[[]low.ValueReference[string]]
Summary low.NodeReference[string]
Description low.NodeReference[string]
ExternalDocs low.NodeReference[*base.ExternalDoc]
OperationId low.NodeReference[string]
Consumes low.NodeReference[[]low.ValueReference[string]]
Produces low.NodeReference[[]low.ValueReference[string]]
Parameters low.NodeReference[[]low.ValueReference[*Parameter]]
Responses low.NodeReference[*Responses]
Schemes low.NodeReference[[]low.ValueReference[string]]
Deprecated low.NodeReference[bool]
Security low.NodeReference[[]low.ValueReference[*SecurityRequirement]]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
}
func (o *Operation) Build(root *yaml.Node, idx *index.SpecIndex) error {
o.Extensions = low.ExtractExtensions(root)
// extract externalDocs
extDocs, dErr := low.ExtractObject[*base.ExternalDoc](base.ExternalDocsLabel, root, idx)
if dErr != nil {
return dErr
}
o.ExternalDocs = extDocs
// extract parameters
params, ln, vn, pErr := low.ExtractArray[*Parameter](ParametersLabel, root, idx)
if pErr != nil {
return pErr
}
if params != nil {
o.Parameters = low.NodeReference[[]low.ValueReference[*Parameter]]{
Value: params,
KeyNode: ln,
ValueNode: vn,
}
}
// extract responses
respBody, respErr := low.ExtractObject[*Responses](ResponsesLabel, root, idx)
if respErr != nil {
return respErr
}
o.Responses = respBody
// extract parameters
sec, sln, svn, sErr := low.ExtractArray[*SecurityRequirement](SecurityLabel, root, idx)
if sErr != nil {
return sErr
}
if sec != nil {
o.Security = low.NodeReference[[]low.ValueReference[*SecurityRequirement]]{
Value: sec,
KeyNode: sln,
ValueNode: svn,
}
}
return nil
}

View File

@@ -5,10 +5,15 @@ package v2
import (
"github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/datamodel/low/base"
"github.com/pb33f/libopenapi/index"
"gopkg.in/yaml.v3"
)
const (
ParametersLabel = "parameters"
)
type Parameter struct {
Name low.NodeReference[string]
In low.NodeReference[string]
@@ -17,6 +22,7 @@ type Parameter struct {
Description low.NodeReference[string]
Required low.NodeReference[bool]
AllowEmptyValue low.NodeReference[bool]
Schema low.NodeReference[*base.SchemaProxy]
Items low.NodeReference[*Items]
CollectionFormat low.NodeReference[string]
Default low.NodeReference[any]

View File

@@ -0,0 +1,179 @@
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
// SPDX-License-Identifier: MIT
package v2
import (
"fmt"
"github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3"
"strings"
"sync"
)
type PathItem struct {
Ref low.NodeReference[string]
Get low.NodeReference[*Operation]
Put low.NodeReference[*Operation]
Post low.NodeReference[*Operation]
Delete low.NodeReference[*Operation]
Options low.NodeReference[*Operation]
Head low.NodeReference[*Operation]
Patch low.NodeReference[*Operation]
Parameters low.NodeReference[[]low.ValueReference[*Parameter]]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
}
func (p *PathItem) FindExtension(ext string) *low.ValueReference[any] {
return low.FindItemInMap[any](ext, p.Extensions)
}
func (p *PathItem) Build(root *yaml.Node, idx *index.SpecIndex) error {
p.Extensions = low.ExtractExtensions(root)
skip := false
var currentNode *yaml.Node
var wg sync.WaitGroup
var errors []error
var ops []low.NodeReference[*Operation]
// extract parameters
params, ln, vn, pErr := low.ExtractArray[*Parameter](ParametersLabel, root, idx)
if pErr != nil {
return pErr
}
if params != nil {
p.Parameters = low.NodeReference[[]low.ValueReference[*Parameter]]{
Value: params,
KeyNode: ln,
ValueNode: vn,
}
}
for i, pathNode := range root.Content {
if strings.HasPrefix(strings.ToLower(pathNode.Value), "x-") {
skip = true
continue
}
if strings.HasPrefix(strings.ToLower(pathNode.Value), "parameters") {
skip = true
continue
}
if skip {
skip = false
continue
}
if i%2 == 0 {
currentNode = pathNode
continue
}
// the only thing we now care about is handling operations, filter out anything that's not a verb.
switch currentNode.Value {
case GetLabel:
break
case PostLabel:
break
case PutLabel:
break
case PatchLabel:
break
case DeleteLabel:
break
case HeadLabel:
break
case OptionsLabel:
break
default:
continue // ignore everything else.
}
var op Operation
wg.Add(1)
if ok, _, _ := utils.IsNodeRefValue(pathNode); ok {
r, err := low.LocateRefNode(pathNode, idx)
if r != nil {
pathNode = r
if err != nil {
if !idx.AllowCircularReferenceResolving() {
return fmt.Errorf("build schema failed: %s", err.Error())
}
}
} else {
return fmt.Errorf("path item build failed: cannot find reference: %s at line %d, col %d",
pathNode.Content[1].Value, pathNode.Content[1].Line, pathNode.Content[1].Column)
}
}
go low.BuildModelAsync(pathNode, &op, &wg, &errors)
opRef := low.NodeReference[*Operation]{
Value: &op,
KeyNode: currentNode,
ValueNode: pathNode,
}
ops = append(ops, opRef)
switch currentNode.Value {
case GetLabel:
p.Get = opRef
case PostLabel:
p.Post = opRef
case PutLabel:
p.Put = opRef
case PatchLabel:
p.Patch = opRef
case DeleteLabel:
p.Delete = opRef
case HeadLabel:
p.Head = opRef
case OptionsLabel:
p.Options = opRef
}
}
//all operations have been superficially built,
//now we need to build out the operation, we will do this asynchronously for speed.
opBuildChan := make(chan bool)
opErrorChan := make(chan error)
var buildOpFunc = func(op low.NodeReference[*Operation], ch chan<- bool, errCh chan<- error) {
er := op.Value.Build(op.ValueNode, idx)
if er != nil {
errCh <- er
}
ch <- true
}
if len(ops) <= 0 {
return nil // nothing to do.
}
for _, op := range ops {
go buildOpFunc(op, opBuildChan, opErrorChan)
}
n := 0
total := len(ops)
for n < total {
select {
case buildError := <-opErrorChan:
return buildError
case <-opBuildChan:
n++
}
}
// make sure we don't exit before the path is finished building.
if len(ops) > 0 {
wg.Wait()
}
return nil
}

125
datamodel/low/2.0/paths.go Normal file
View File

@@ -0,0 +1,125 @@
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
// SPDX-License-Identifier: MIT
package v2
import (
"fmt"
"github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3"
"strings"
)
const (
PathsLabel = "paths"
GetLabel = "get"
PostLabel = "post"
PatchLabel = "patch"
PutLabel = "put"
DeleteLabel = "delete"
OptionsLabel = "options"
HeadLabel = "head"
TraceLabel = "trace"
)
type Paths struct {
PathItems map[low.KeyReference[string]]low.ValueReference[*PathItem]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
}
func (p *Paths) FindPath(path string) *low.ValueReference[*PathItem] {
for k, j := range p.PathItems {
if k.Value == path {
return &j
}
}
return nil
}
func (p *Paths) FindExtension(ext string) *low.ValueReference[any] {
return low.FindItemInMap[any](ext, p.Extensions)
}
func (p *Paths) Build(root *yaml.Node, idx *index.SpecIndex) error {
p.Extensions = low.ExtractExtensions(root)
skip := false
var currentNode *yaml.Node
pathsMap := make(map[low.KeyReference[string]]low.ValueReference[*PathItem])
// build each new path, in a new thread.
type pathBuildResult struct {
k low.KeyReference[string]
v low.ValueReference[*PathItem]
}
bChan := make(chan pathBuildResult)
eChan := make(chan error)
var buildPathItem = func(cNode, pNode *yaml.Node, b chan<- pathBuildResult, e chan<- error) {
if ok, _, _ := utils.IsNodeRefValue(pNode); ok {
r, err := low.LocateRefNode(pNode, idx)
if r != nil {
pNode = r
if err != nil {
if !idx.AllowCircularReferenceResolving() {
e <- fmt.Errorf("path item build failed: %s", err.Error())
return
}
}
} else {
e <- fmt.Errorf("path item build failed: cannot find reference: %s at line %d, col %d",
pNode.Content[1].Value, pNode.Content[1].Line, pNode.Content[1].Column)
return
}
}
path := new(PathItem)
_ = low.BuildModel(pNode, path)
err := path.Build(pNode, idx)
if err != nil {
e <- err
return
}
b <- pathBuildResult{
k: low.KeyReference[string]{
Value: cNode.Value,
KeyNode: cNode,
},
v: low.ValueReference[*PathItem]{
Value: path,
ValueNode: pNode,
},
}
}
pathCount := 0
for i, pathNode := range root.Content {
if strings.HasPrefix(strings.ToLower(pathNode.Value), "x-") {
skip = true
continue
}
if skip {
skip = false
continue
}
if i%2 == 0 {
currentNode = pathNode
continue
}
pathCount++
go buildPathItem(currentNode, pathNode, bChan, eChan)
}
completedItems := 0
for completedItems < pathCount {
select {
case err := <-eChan:
return err
case res := <-bChan:
completedItems++
pathsMap[res.k] = res.v
}
}
p.PathItems = pathsMap
return nil
}

View File

@@ -6,11 +6,50 @@ package v2
import (
"github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/datamodel/low/base"
"github.com/pb33f/libopenapi/index"
"gopkg.in/yaml.v3"
)
const (
ResponsesLabel = "responses"
)
type Response struct {
Description low.NodeReference[string]
Schema low.NodeReference[*base.SchemaProxy]
Headers low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Header]]
Examples low.NodeReference[map[low.KeyReference[string]]low.ValueReference[any]]
Examples low.NodeReference[*Examples]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
}
func (r *Response) FindExtension(ext string) *low.ValueReference[any] {
return low.FindItemInMap[any](ext, r.Extensions)
}
func (r *Response) FindHeader(hType string) *low.ValueReference[*Header] {
return low.FindItemInMap[*Header](hType, r.Headers.Value)
}
func (r *Response) Build(root *yaml.Node, idx *index.SpecIndex) error {
r.Extensions = low.ExtractExtensions(root)
s, err := base.ExtractSchema(root, idx)
if err != nil {
return err
}
r.Schema = *s
//extract headers
headers, lN, kN, err := low.ExtractMapFlat[*Header](HeadersLabel, root, idx)
if err != nil {
return err
}
if headers != nil {
r.Headers = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Header]]{
Value: headers,
KeyNode: lN,
ValueNode: kN,
}
}
return nil
}

View File

@@ -0,0 +1,47 @@
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
// SPDX-License-Identifier: MIT
package v2
import (
"fmt"
"github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3"
)
type Responses struct {
Codes map[low.KeyReference[string]]low.ValueReference[*Response]
Default low.NodeReference[*Response]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
}
func (r *Responses) Build(root *yaml.Node, idx *index.SpecIndex) error {
r.Extensions = low.ExtractExtensions(root)
if utils.IsNodeMap(root) {
codes, err := low.ExtractMapFlatNoLookup[*Response](root, idx)
if err != nil {
return err
}
if codes != nil {
r.Codes = codes
}
def, derr := low.ExtractObject[*Response](DefaultLabel, root, idx)
if derr != nil {
return derr
}
if def.Value != nil {
r.Default = def
}
} else {
return fmt.Errorf("responses build failed: vn node is not a map! line %d, col %d", root.Line, root.Column)
}
return nil
}
func (r *Responses) FindResponseByCode(code string) *low.ValueReference[*Response] {
return low.FindItemInMap[*Response](code, r.Codes)
}

View File

@@ -3,8 +3,21 @@
package v2
import "github.com/pb33f/libopenapi/datamodel/low"
import (
"github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"gopkg.in/yaml.v3"
)
const (
SecurityLabel = "security"
)
type SecurityRequirement struct {
Values low.NodeReference[[]low.ValueReference[string]]
}
func (s *SecurityRequirement) Build(_ *yaml.Node, _ *index.SpecIndex) error {
// not implemented.
return nil
}

View File

@@ -3,7 +3,11 @@
package v2
import "github.com/pb33f/libopenapi/datamodel/low"
import (
"github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index"
"gopkg.in/yaml.v3"
)
type SecurityScheme struct {
Type low.NodeReference[string]
@@ -16,3 +20,10 @@ type SecurityScheme struct {
Scopes low.NodeReference[*Scopes]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
}
func (ss *SecurityScheme) Build(root *yaml.Node, idx *index.SpecIndex) error {
ss.Extensions = low.ExtractExtensions(root)
// TODO: scopes
return nil
}

View File

@@ -4,27 +4,132 @@
package v2
import (
"github.com/pb33f/libopenapi/datamodel"
"github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/datamodel/low/base"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/resolver"
"gopkg.in/yaml.v3"
)
type documentFunction func(root *yaml.Node, doc *Swagger, idx *index.SpecIndex, c chan<- bool, e chan<- error)
type Swagger struct {
Swagger low.NodeReference[string]
Swagger low.ValueReference[string]
Info low.NodeReference[*base.Info]
Host low.NodeReference[string]
BasePath low.NodeReference[string]
Schemes low.NodeReference[[]low.ValueReference[string]]
Consumes low.NodeReference[[]low.ValueReference[string]]
Produces low.NodeReference[[]low.ValueReference[string]]
// TODO: paths
Definitions low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*base.SchemaProxy]]
Parameters low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Parameter]]
Responses low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Response]]
SecurityDefinitions low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*SecurityScheme]]
Security low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*SecurityRequirement]]
Tags low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*base.Tag]]
Paths low.NodeReference[*Paths]
Definitions low.NodeReference[*Definitions]
SecurityDefinitions low.NodeReference[*SecurityDefinitions]
Parameters low.NodeReference[*ParameterDefinitions]
ResponsesDefinitions low.NodeReference[*ResponsesDefinitions]
Responses low.NodeReference[*Responses]
Security low.NodeReference[[]low.ValueReference[*SecurityRequirement]]
Tags low.NodeReference[[]low.ValueReference[*base.Tag]]
ExternalDocs low.NodeReference[*base.ExternalDoc]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
Index *index.SpecIndex
}
func CreateDocument(info *datamodel.SpecInfo) (*Swagger, []error) {
doc := Swagger{Swagger: low.ValueReference[string]{Value: info.Version, ValueNode: info.RootNode}}
doc.Extensions = low.ExtractExtensions(info.RootNode.Content[0])
// build an index
idx := index.NewSpecIndex(info.RootNode)
doc.Index = idx
// create resolver and check for circular references.
resolve := resolver.NewResolver(idx)
_ = resolve.CheckForCircularReferences()
var errors []error
extractionFuncs := []documentFunction{
extractInfo,
extractPaths,
extractDefinitions,
extractParamDefinitions,
extractResponsesDefinitions,
extractSecurityDefinitions,
}
doneChan := make(chan bool)
errChan := make(chan error)
for i := range extractionFuncs {
go extractionFuncs[i](info.RootNode, &doc, idx, doneChan, errChan)
}
completedExtractions := 0
for completedExtractions < len(extractionFuncs) {
select {
case <-doneChan:
completedExtractions++
case e := <-errChan:
errors = append(errors, e)
}
}
return &doc, errors
}
func extractInfo(root *yaml.Node, doc *Swagger, idx *index.SpecIndex, c chan<- bool, e chan<- error) {
info, err := low.ExtractObject[*base.Info](base.InfoLabel, root, idx)
if err != nil {
e <- err
return
}
doc.Info = info
c <- true
}
func extractPaths(root *yaml.Node, doc *Swagger, idx *index.SpecIndex, c chan<- bool, e chan<- error) {
paths, err := low.ExtractObject[*Paths](PathsLabel, root, idx)
if err != nil {
e <- err
return
}
doc.Paths = paths
c <- true
}
func extractDefinitions(root *yaml.Node, doc *Swagger, idx *index.SpecIndex, c chan<- bool, e chan<- error) {
def, err := low.ExtractObject[*Definitions](DefinitionsLabel, root, idx)
if err != nil {
e <- err
return
}
doc.Definitions = def
c <- true
}
func extractParamDefinitions(root *yaml.Node, doc *Swagger, idx *index.SpecIndex, c chan<- bool, e chan<- error) {
param, err := low.ExtractObject[*ParameterDefinitions](ParametersLabel, root, idx)
if err != nil {
e <- err
return
}
doc.Parameters = param
c <- true
}
func extractResponsesDefinitions(root *yaml.Node, doc *Swagger, idx *index.SpecIndex, c chan<- bool, e chan<- error) {
resp, err := low.ExtractObject[*ResponsesDefinitions](ResponsesLabel, root, idx)
if err != nil {
e <- err
return
}
doc.ResponsesDefinitions = resp
c <- true
}
func extractSecurityDefinitions(root *yaml.Node, doc *Swagger, idx *index.SpecIndex, c chan<- bool, e chan<- error) {
sec, err := low.ExtractObject[*SecurityDefinitions](SecurityLabel, root, idx)
if err != nil {
e <- err
return
}
doc.SecurityDefinitions = sec
c <- true
}

View File

@@ -12,7 +12,6 @@ import (
func CreateDocument(info *datamodel.SpecInfo) (*Document, []error) {
// clean state
doc := Document{Version: low.ValueReference[string]{Value: info.Version, ValueNode: info.RootNode}}
// build an index

View File

@@ -31,7 +31,6 @@ func (ex *Example) FindExtension(ext string) *low.ValueReference[any] {
func (ex *Example) Build(root *yaml.Node, idx *index.SpecIndex) error {
ex.Extensions = low.ExtractExtensions(root)
_, ln, vn := utils.FindKeyNodeFull(ValueLabel, root.Content)
if vn != nil {