mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-09 20:47:44 +00:00
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.
214 lines
7.0 KiB
Go
214 lines
7.0 KiB
Go
package v3
|
|
|
|
import (
|
|
"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}
|
|
|
|
// build an index
|
|
idx := index.NewSpecIndex(info.RootNode)
|
|
doc.Index = idx
|
|
|
|
var errors []error
|
|
|
|
// create resolver and check for circular references.
|
|
resolve := resolver.NewResolver(idx)
|
|
resolvingErrors := resolve.CheckForCircularReferences()
|
|
|
|
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))
|
|
}
|
|
}
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
doc.Extensions = low.ExtractExtensions(info.RootNode.Content[0])
|
|
|
|
// 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 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
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
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
|
|
}
|