mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-06 20:47:49 +00:00
working through rolodex design and using it externally via vacuum
this is some complex and messy work. Signed-off-by: quobix <dave@quobix.com>
This commit is contained in:
34
document.go
34
document.go
@@ -36,6 +36,9 @@ type Document interface {
|
||||
// GetVersion will return the exact version of the OpenAPI specification set for the document.
|
||||
GetVersion() string
|
||||
|
||||
// GetRolodex will return the Rolodex instance that was used to load the document.
|
||||
GetRolodex() *index.Rolodex
|
||||
|
||||
// GetSpecInfo will return the *datamodel.SpecInfo instance that contains all specification information.
|
||||
GetSpecInfo() *datamodel.SpecInfo
|
||||
|
||||
@@ -102,6 +105,7 @@ type Document interface {
|
||||
}
|
||||
|
||||
type document struct {
|
||||
rolodex *index.Rolodex
|
||||
version string
|
||||
info *datamodel.SpecInfo
|
||||
config *datamodel.DocumentConfiguration
|
||||
@@ -161,6 +165,10 @@ func NewDocumentWithConfiguration(specByteArray []byte, configuration *datamodel
|
||||
return d, err
|
||||
}
|
||||
|
||||
func (d *document) GetRolodex() *index.Rolodex {
|
||||
return d.rolodex
|
||||
}
|
||||
|
||||
func (d *document) GetVersion() string {
|
||||
return d.version
|
||||
}
|
||||
@@ -281,15 +289,15 @@ func (d *document) BuildV3Model() (*DocumentModel[v3high.Document], []error) {
|
||||
if d.highOpenAPI3Model != nil {
|
||||
return d.highOpenAPI3Model, nil
|
||||
}
|
||||
var errors []error
|
||||
var errs []error
|
||||
if d.info == nil {
|
||||
errors = append(errors, fmt.Errorf("unable to build document, no specification has been loaded"))
|
||||
return nil, errors
|
||||
errs = append(errs, fmt.Errorf("unable to build document, no specification has been loaded"))
|
||||
return nil, errs
|
||||
}
|
||||
if d.info.SpecFormat != datamodel.OAS3 {
|
||||
errors = append(errors, fmt.Errorf("unable to build openapi document, "+
|
||||
errs = append(errs, fmt.Errorf("unable to build openapi document, "+
|
||||
"supplied spec is a different version (%v). Try 'BuildV2Model()'", d.info.SpecFormat))
|
||||
return nil, errors
|
||||
return nil, errs
|
||||
}
|
||||
|
||||
var lowDoc *v3low.Document
|
||||
@@ -300,24 +308,26 @@ func (d *document) BuildV3Model() (*DocumentModel[v3high.Document], []error) {
|
||||
}
|
||||
}
|
||||
|
||||
lowDoc, errors = v3low.CreateDocumentFromConfig(d.info, d.config)
|
||||
var docErr error
|
||||
lowDoc, docErr = v3low.CreateDocumentFromConfig(d.info, d.config)
|
||||
d.rolodex = lowDoc.Rolodex
|
||||
// Do not short-circuit on circular reference errors, so the client
|
||||
// has the option of ignoring them.
|
||||
for _, err := range errors {
|
||||
if refErr, ok := err.(*index.ResolvingError); ok {
|
||||
for _, err := range utils.UnwrapErrors(docErr) {
|
||||
var refErr *index.ResolvingError
|
||||
if errors.As(err, &refErr) {
|
||||
if refErr.CircularReference == nil {
|
||||
return nil, errors
|
||||
return nil, errs
|
||||
}
|
||||
} else {
|
||||
return nil, errors
|
||||
}
|
||||
}
|
||||
highDoc := v3high.NewDocument(lowDoc)
|
||||
|
||||
d.highOpenAPI3Model = &DocumentModel[v3high.Document]{
|
||||
Model: *highDoc,
|
||||
Index: lowDoc.Index,
|
||||
}
|
||||
return d.highOpenAPI3Model, errors
|
||||
return d.highOpenAPI3Model, errs
|
||||
}
|
||||
|
||||
// CompareDocuments will accept a left and right Document implementing struct, build a model for the correct
|
||||
|
||||
@@ -822,6 +822,7 @@ components:
|
||||
|
||||
assert.Len(t, errs, 0)
|
||||
assert.Len(t, m.Index.GetCircularReferences(), 0)
|
||||
assert.Len(t, m.Index.GetResolver().GetIgnoredCircularPolyReferences(), 1)
|
||||
|
||||
}
|
||||
|
||||
@@ -856,5 +857,6 @@ components:
|
||||
|
||||
assert.Len(t, errs, 0)
|
||||
assert.Len(t, m.Index.GetCircularReferences(), 0)
|
||||
assert.Len(t, m.Index.GetResolver().GetIgnoredCircularArrayReferences(), 1)
|
||||
|
||||
}
|
||||
|
||||
@@ -53,10 +53,23 @@ func NewResolver(index *SpecIndex) *Resolver {
|
||||
if index == nil {
|
||||
return nil
|
||||
}
|
||||
return &Resolver{
|
||||
r := &Resolver{
|
||||
|
||||
specIndex: index,
|
||||
resolvedRoot: index.GetRootNode(),
|
||||
}
|
||||
index.resolver = r
|
||||
return r
|
||||
}
|
||||
|
||||
// GetIgnoredCircularPolyReferences returns all ignored circular references that are polymorphic
|
||||
func (resolver *Resolver) GetIgnoredCircularPolyReferences() []*CircularReferenceResult {
|
||||
return resolver.ignoredPolyReferences
|
||||
}
|
||||
|
||||
// GetIgnoredCircularArrayReferences returns all ignored circular references that are arrays
|
||||
func (resolver *Resolver) GetIgnoredCircularArrayReferences() []*CircularReferenceResult {
|
||||
return resolver.ignoredArrayReferences
|
||||
}
|
||||
|
||||
// GetResolvingErrors returns all errors found during resolving
|
||||
|
||||
@@ -318,8 +318,8 @@ func TestResolver_CheckForCircularReferences_DigitalOcean(t *testing.T) {
|
||||
baseURL, _ := url.Parse("https://raw.githubusercontent.com/digitalocean/openapi/main/specification")
|
||||
|
||||
idx := NewSpecIndexWithConfig(&rootNode, &SpecIndexConfig{
|
||||
AllowRemoteLookup: true,
|
||||
AllowFileLookup: true,
|
||||
//AllowRemoteLookup: true,
|
||||
//AllowFileLookup: true,
|
||||
BaseURL: baseURL,
|
||||
})
|
||||
|
||||
|
||||
@@ -54,6 +54,9 @@ type Rolodex struct {
|
||||
localFS map[string]fs.FS
|
||||
remoteFS map[string]fs.FS
|
||||
indexed bool
|
||||
built bool
|
||||
resolved bool
|
||||
circChecked bool
|
||||
indexConfig *SpecIndexConfig
|
||||
indexingDuration time.Duration
|
||||
indexes []*SpecIndex
|
||||
@@ -324,11 +327,12 @@ func (r *Rolodex) IndexTheRolodex() error {
|
||||
}
|
||||
|
||||
// now that we have indexed all the files, we can build the index.
|
||||
r.indexes = indexBuildQueue
|
||||
if !r.indexConfig.AvoidBuildIndex {
|
||||
for _, idx := range indexBuildQueue {
|
||||
idx.BuildIndex()
|
||||
|
||||
}
|
||||
r.indexes = indexBuildQueue
|
||||
}
|
||||
|
||||
// indexed and built every supporting file, we can build the root index (our entry point)
|
||||
index := NewSpecIndexWithConfig(r.indexConfig.SpecInfo.RootNode, r.indexConfig)
|
||||
@@ -339,11 +343,17 @@ func (r *Rolodex) IndexTheRolodex() error {
|
||||
if r.indexConfig.IgnorePolymorphicCircularReferences {
|
||||
resolver.IgnorePolymorphicCircularReferences()
|
||||
}
|
||||
index.resolver = resolver
|
||||
|
||||
if !r.indexConfig.AvoidBuildIndex {
|
||||
index.BuildIndex()
|
||||
}
|
||||
|
||||
if !r.indexConfig.AvoidCircularReferenceCheck {
|
||||
resolvingErrors := resolver.CheckForCircularReferences()
|
||||
for e := range resolvingErrors {
|
||||
caughtErrors = append(caughtErrors, resolvingErrors[e])
|
||||
}
|
||||
}
|
||||
|
||||
r.rootIndex = index
|
||||
r.indexingDuration = time.Now().Sub(started)
|
||||
@@ -353,6 +363,29 @@ func (r *Rolodex) IndexTheRolodex() error {
|
||||
|
||||
}
|
||||
|
||||
func (r *Rolodex) CheckForCircularReferences() {
|
||||
if r.rootIndex != nil && r.rootIndex.resolver != nil {
|
||||
resolvingErrors := r.rootIndex.resolver.CheckForCircularReferences()
|
||||
for e := range resolvingErrors {
|
||||
r.caughtErrors = append(r.caughtErrors, resolvingErrors[e])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Rolodex) BuildIndexes() {
|
||||
if r.built {
|
||||
return
|
||||
}
|
||||
for _, idx := range r.indexes {
|
||||
idx.BuildIndex()
|
||||
}
|
||||
if r.rootIndex != nil {
|
||||
r.rootIndex.BuildIndex()
|
||||
}
|
||||
r.built = true
|
||||
return
|
||||
}
|
||||
|
||||
func (r *Rolodex) Open(location string) (RolodexFile, error) {
|
||||
|
||||
var errorStack []error
|
||||
@@ -360,6 +393,10 @@ func (r *Rolodex) Open(location string) (RolodexFile, error) {
|
||||
var localFile *LocalFile
|
||||
//var remoteFile *RemoteFile
|
||||
|
||||
if r == nil || r.localFS == nil && r.remoteFS == nil {
|
||||
panic("WHAT NO....")
|
||||
}
|
||||
|
||||
for k, v := range r.localFS {
|
||||
|
||||
// check if this is a URL or an abs/rel reference.
|
||||
|
||||
@@ -124,10 +124,13 @@ func NewLocalFS(baseDir string, dirFS fs.FS) (*LocalFS, error) {
|
||||
if absBaseErr != nil {
|
||||
return nil, absBaseErr
|
||||
}
|
||||
walkErr := fs.WalkDir(dirFS, baseDir, func(p string, d fs.DirEntry, err error) error {
|
||||
walkErr := fs.WalkDir(dirFS, ".", func(p string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// we don't care about directories.
|
||||
if d.IsDir() {
|
||||
// we don't care about directories, or errors, just read everything we can.
|
||||
if d == nil || d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user