mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-10 04:20:24 +00:00
(feat): Circular / resolving errors returned with document creation. #18
Tristan made a good point, part of the doc building process performs a resolving check and circular reference check, which is ignored by the returned errors. So resolving errors are now unpacked into standard errors and returned. Not sure why gofmt has shifted everything around however.
This commit is contained in:
@@ -1,203 +1,213 @@
|
||||
package v3
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"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"
|
||||
"github.com/pb33f/libopenapi/utils"
|
||||
"sync"
|
||||
"errors"
|
||||
"fmt"
|
||||
"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"
|
||||
"github.com/pb33f/libopenapi/utils"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func CreateDocument(info *datamodel.SpecInfo) (*Document, []error) {
|
||||
|
||||
_, labelNode, versionNode := utils.FindKeyNodeFull(OpenAPILabel, info.RootNode.Content)
|
||||
var version low.NodeReference[string]
|
||||
if versionNode == nil {
|
||||
return nil, []error{errors.New("no openapi version/tag found, cannot create document")}
|
||||
}
|
||||
version = low.NodeReference[string]{Value: versionNode.Value, KeyNode: labelNode, ValueNode: versionNode}
|
||||
doc := Document{Version: version}
|
||||
_, labelNode, versionNode := utils.FindKeyNodeFull(OpenAPILabel, info.RootNode.Content)
|
||||
var version low.NodeReference[string]
|
||||
if versionNode == nil {
|
||||
return nil, []error{errors.New("no openapi version/tag found, cannot create document")}
|
||||
}
|
||||
version = low.NodeReference[string]{Value: versionNode.Value, KeyNode: labelNode, ValueNode: versionNode}
|
||||
doc := Document{Version: version}
|
||||
|
||||
// build an index
|
||||
idx := index.NewSpecIndex(info.RootNode)
|
||||
doc.Index = idx
|
||||
// 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
|
||||
|
||||
var wg sync.WaitGroup
|
||||
var errors []error
|
||||
// create resolver and check for circular references.
|
||||
resolve := resolver.NewResolver(idx)
|
||||
resolvingErrors := resolve.CheckForCircularReferences()
|
||||
|
||||
doc.Extensions = low.ExtractExtensions(info.RootNode.Content[0])
|
||||
if len(resolvingErrors) > 0 {
|
||||
for r := range resolvingErrors {
|
||||
errors = append(errors,
|
||||
fmt.Errorf("%s: %s [%d:%d]", resolvingErrors[r].Error.Error(),
|
||||
resolvingErrors[r].Path, resolvingErrors[r].Node.Line, resolvingErrors[r].Node.Column))
|
||||
}
|
||||
}
|
||||
|
||||
// if set, extract jsonSchemaDialect (3.1)
|
||||
_, dialectLabel, dialectNode := utils.FindKeyNodeFull(JSONSchemaDialectLabel, info.RootNode.Content)
|
||||
if dialectNode != nil {
|
||||
doc.JsonSchemaDialect = low.NodeReference[string]{
|
||||
Value: dialectNode.Value, KeyNode: dialectLabel, ValueNode: dialectNode}
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
|
||||
var runExtraction = func(info *datamodel.SpecInfo, doc *Document, idx *index.SpecIndex,
|
||||
runFunc func(i *datamodel.SpecInfo, d *Document, idx *index.SpecIndex) error,
|
||||
ers *[]error,
|
||||
wg *sync.WaitGroup) {
|
||||
doc.Extensions = low.ExtractExtensions(info.RootNode.Content[0])
|
||||
|
||||
if er := runFunc(info, doc, idx); er != nil {
|
||||
*ers = append(*ers, er)
|
||||
}
|
||||
wg.Done()
|
||||
}
|
||||
extractionFuncs := []func(i *datamodel.SpecInfo, d *Document, idx *index.SpecIndex) error{
|
||||
extractInfo,
|
||||
extractServers,
|
||||
extractTags,
|
||||
extractComponents,
|
||||
extractSecurity,
|
||||
extractExternalDocs,
|
||||
extractPaths,
|
||||
extractWebhooks,
|
||||
}
|
||||
// if set, extract jsonSchemaDialect (3.1)
|
||||
_, dialectLabel, dialectNode := utils.FindKeyNodeFull(JSONSchemaDialectLabel, info.RootNode.Content)
|
||||
if dialectNode != nil {
|
||||
doc.JsonSchemaDialect = low.NodeReference[string]{
|
||||
Value: dialectNode.Value, KeyNode: dialectLabel, ValueNode: dialectNode}
|
||||
}
|
||||
|
||||
wg.Add(len(extractionFuncs))
|
||||
for _, f := range extractionFuncs {
|
||||
go runExtraction(info, &doc, idx, f, &errors, &wg)
|
||||
}
|
||||
wg.Wait()
|
||||
return &doc, errors
|
||||
var runExtraction = func(info *datamodel.SpecInfo, doc *Document, idx *index.SpecIndex,
|
||||
runFunc func(i *datamodel.SpecInfo, d *Document, idx *index.SpecIndex) error,
|
||||
ers *[]error,
|
||||
wg *sync.WaitGroup) {
|
||||
|
||||
if er := runFunc(info, doc, idx); er != nil {
|
||||
*ers = append(*ers, er)
|
||||
}
|
||||
wg.Done()
|
||||
}
|
||||
extractionFuncs := []func(i *datamodel.SpecInfo, d *Document, idx *index.SpecIndex) error{
|
||||
extractInfo,
|
||||
extractServers,
|
||||
extractTags,
|
||||
extractComponents,
|
||||
extractSecurity,
|
||||
extractExternalDocs,
|
||||
extractPaths,
|
||||
extractWebhooks,
|
||||
}
|
||||
|
||||
wg.Add(len(extractionFuncs))
|
||||
for _, f := range extractionFuncs {
|
||||
go runExtraction(info, &doc, idx, f, &errors, &wg)
|
||||
}
|
||||
wg.Wait()
|
||||
return &doc, errors
|
||||
}
|
||||
|
||||
func extractInfo(info *datamodel.SpecInfo, doc *Document, idx *index.SpecIndex) error {
|
||||
_, ln, vn := utils.FindKeyNodeFullTop(base.InfoLabel, info.RootNode.Content[0].Content)
|
||||
if vn != nil {
|
||||
ir := base.Info{}
|
||||
_ = low.BuildModel(vn, &ir)
|
||||
_ = ir.Build(vn, idx)
|
||||
nr := low.NodeReference[*base.Info]{Value: &ir, ValueNode: vn, KeyNode: ln}
|
||||
doc.Info = nr
|
||||
}
|
||||
return nil
|
||||
_, ln, vn := utils.FindKeyNodeFullTop(base.InfoLabel, info.RootNode.Content[0].Content)
|
||||
if vn != nil {
|
||||
ir := base.Info{}
|
||||
_ = low.BuildModel(vn, &ir)
|
||||
_ = ir.Build(vn, idx)
|
||||
nr := low.NodeReference[*base.Info]{Value: &ir, ValueNode: vn, KeyNode: ln}
|
||||
doc.Info = nr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractSecurity(info *datamodel.SpecInfo, doc *Document, idx *index.SpecIndex) error {
|
||||
sec, ln, vn, err := low.ExtractArray[*base.SecurityRequirement](SecurityLabel, info.RootNode.Content[0], idx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
doc.Security = low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]]{
|
||||
Value: sec,
|
||||
KeyNode: ln,
|
||||
ValueNode: vn,
|
||||
}
|
||||
return nil
|
||||
sec, ln, vn, err := low.ExtractArray[*base.SecurityRequirement](SecurityLabel, info.RootNode.Content[0], idx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
doc.Security = low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]]{
|
||||
Value: sec,
|
||||
KeyNode: ln,
|
||||
ValueNode: vn,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractExternalDocs(info *datamodel.SpecInfo, doc *Document, idx *index.SpecIndex) error {
|
||||
extDocs, dErr := low.ExtractObject[*base.ExternalDoc](base.ExternalDocsLabel, info.RootNode.Content[0], idx)
|
||||
if dErr != nil {
|
||||
return dErr
|
||||
}
|
||||
doc.ExternalDocs = extDocs
|
||||
return nil
|
||||
extDocs, dErr := low.ExtractObject[*base.ExternalDoc](base.ExternalDocsLabel, info.RootNode.Content[0], idx)
|
||||
if dErr != nil {
|
||||
return dErr
|
||||
}
|
||||
doc.ExternalDocs = extDocs
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractComponents(info *datamodel.SpecInfo, doc *Document, idx *index.SpecIndex) error {
|
||||
_, ln, vn := utils.FindKeyNodeFullTop(ComponentsLabel, info.RootNode.Content[0].Content)
|
||||
if vn != nil {
|
||||
ir := Components{}
|
||||
_ = low.BuildModel(vn, &ir)
|
||||
err := ir.Build(vn, idx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nr := low.NodeReference[*Components]{Value: &ir, ValueNode: vn, KeyNode: ln}
|
||||
doc.Components = nr
|
||||
}
|
||||
return nil
|
||||
_, ln, vn := utils.FindKeyNodeFullTop(ComponentsLabel, info.RootNode.Content[0].Content)
|
||||
if vn != nil {
|
||||
ir := Components{}
|
||||
_ = low.BuildModel(vn, &ir)
|
||||
err := ir.Build(vn, idx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nr := low.NodeReference[*Components]{Value: &ir, ValueNode: vn, KeyNode: ln}
|
||||
doc.Components = nr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractServers(info *datamodel.SpecInfo, doc *Document, idx *index.SpecIndex) error {
|
||||
_, ln, vn := utils.FindKeyNodeFull(ServersLabel, info.RootNode.Content[0].Content)
|
||||
if vn != nil {
|
||||
if utils.IsNodeArray(vn) {
|
||||
var servers []low.ValueReference[*Server]
|
||||
for _, srvN := range vn.Content {
|
||||
if utils.IsNodeMap(srvN) {
|
||||
srvr := Server{}
|
||||
_ = low.BuildModel(srvN, &srvr)
|
||||
_ = srvr.Build(srvN, idx)
|
||||
servers = append(servers, low.ValueReference[*Server]{
|
||||
Value: &srvr,
|
||||
ValueNode: srvN,
|
||||
})
|
||||
}
|
||||
}
|
||||
doc.Servers = low.NodeReference[[]low.ValueReference[*Server]]{
|
||||
Value: servers,
|
||||
KeyNode: ln,
|
||||
ValueNode: vn,
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
_, ln, vn := utils.FindKeyNodeFull(ServersLabel, info.RootNode.Content[0].Content)
|
||||
if vn != nil {
|
||||
if utils.IsNodeArray(vn) {
|
||||
var servers []low.ValueReference[*Server]
|
||||
for _, srvN := range vn.Content {
|
||||
if utils.IsNodeMap(srvN) {
|
||||
srvr := Server{}
|
||||
_ = low.BuildModel(srvN, &srvr)
|
||||
_ = srvr.Build(srvN, idx)
|
||||
servers = append(servers, low.ValueReference[*Server]{
|
||||
Value: &srvr,
|
||||
ValueNode: srvN,
|
||||
})
|
||||
}
|
||||
}
|
||||
doc.Servers = low.NodeReference[[]low.ValueReference[*Server]]{
|
||||
Value: servers,
|
||||
KeyNode: ln,
|
||||
ValueNode: vn,
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractTags(info *datamodel.SpecInfo, doc *Document, idx *index.SpecIndex) error {
|
||||
_, ln, vn := utils.FindKeyNodeFull(base.TagsLabel, info.RootNode.Content[0].Content)
|
||||
if vn != nil {
|
||||
if utils.IsNodeArray(vn) {
|
||||
var tags []low.ValueReference[*base.Tag]
|
||||
for _, tagN := range vn.Content {
|
||||
if utils.IsNodeMap(tagN) {
|
||||
tag := base.Tag{}
|
||||
_ = low.BuildModel(tagN, &tag)
|
||||
if err := tag.Build(tagN, idx); err != nil {
|
||||
return err
|
||||
}
|
||||
tags = append(tags, low.ValueReference[*base.Tag]{
|
||||
Value: &tag,
|
||||
ValueNode: tagN,
|
||||
})
|
||||
}
|
||||
}
|
||||
doc.Tags = low.NodeReference[[]low.ValueReference[*base.Tag]]{
|
||||
Value: tags,
|
||||
KeyNode: ln,
|
||||
ValueNode: vn,
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
_, ln, vn := utils.FindKeyNodeFull(base.TagsLabel, info.RootNode.Content[0].Content)
|
||||
if vn != nil {
|
||||
if utils.IsNodeArray(vn) {
|
||||
var tags []low.ValueReference[*base.Tag]
|
||||
for _, tagN := range vn.Content {
|
||||
if utils.IsNodeMap(tagN) {
|
||||
tag := base.Tag{}
|
||||
_ = low.BuildModel(tagN, &tag)
|
||||
if err := tag.Build(tagN, idx); err != nil {
|
||||
return err
|
||||
}
|
||||
tags = append(tags, low.ValueReference[*base.Tag]{
|
||||
Value: &tag,
|
||||
ValueNode: tagN,
|
||||
})
|
||||
}
|
||||
}
|
||||
doc.Tags = low.NodeReference[[]low.ValueReference[*base.Tag]]{
|
||||
Value: tags,
|
||||
KeyNode: ln,
|
||||
ValueNode: vn,
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractPaths(info *datamodel.SpecInfo, doc *Document, idx *index.SpecIndex) error {
|
||||
_, ln, vn := utils.FindKeyNodeFull(PathsLabel, info.RootNode.Content[0].Content)
|
||||
if vn != nil {
|
||||
ir := Paths{}
|
||||
err := ir.Build(vn, idx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nr := low.NodeReference[*Paths]{Value: &ir, ValueNode: vn, KeyNode: ln}
|
||||
doc.Paths = nr
|
||||
}
|
||||
return nil
|
||||
_, ln, vn := utils.FindKeyNodeFull(PathsLabel, info.RootNode.Content[0].Content)
|
||||
if vn != nil {
|
||||
ir := Paths{}
|
||||
err := ir.Build(vn, idx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nr := low.NodeReference[*Paths]{Value: &ir, ValueNode: vn, KeyNode: ln}
|
||||
doc.Paths = nr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractWebhooks(info *datamodel.SpecInfo, doc *Document, idx *index.SpecIndex) error {
|
||||
hooks, hooksL, hooksN, eErr := low.ExtractMap[*PathItem](WebhooksLabel, info.RootNode, idx)
|
||||
if eErr != nil {
|
||||
return eErr
|
||||
}
|
||||
if hooks != nil {
|
||||
doc.Webhooks = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*PathItem]]{
|
||||
Value: hooks,
|
||||
KeyNode: hooksL,
|
||||
ValueNode: hooksN,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
hooks, hooksL, hooksN, eErr := low.ExtractMap[*PathItem](WebhooksLabel, info.RootNode, idx)
|
||||
if eErr != nil {
|
||||
return eErr
|
||||
}
|
||||
if hooks != nil {
|
||||
doc.Webhooks = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*PathItem]]{
|
||||
Value: hooks,
|
||||
KeyNode: hooksL,
|
||||
ValueNode: hooksN,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user