diff --git a/datamodel/document_config.go b/datamodel/document_config.go index e29c78f..4efe85c 100644 --- a/datamodel/document_config.go +++ b/datamodel/document_config.go @@ -24,6 +24,10 @@ type DocumentConfiguration struct { // AllowRemoteReferences will allow the index to lookup remote references. This is disabled by default. AllowRemoteReferences bool + + // AvoidIndexBuild will avoid building the index. This is disabled by default, only use if you are sure you don't need it. + // This is useful for developers building out models that should be indexed later on. + AvoidIndexBuild bool } func NewOpenDocumentConfiguration() *DocumentConfiguration { diff --git a/datamodel/low/v3/create_document.go b/datamodel/low/v3/create_document.go index 9b6724c..f8465fe 100644 --- a/datamodel/low/v3/create_document.go +++ b/datamodel/low/v3/create_document.go @@ -52,6 +52,7 @@ func createDocument(info *datamodel.SpecInfo, config *datamodel.DocumentConfigur BasePath: cwd, AllowFileLookup: config.AllowFileReferences, AllowRemoteLookup: config.AllowRemoteReferences, + AvoidBuildIndex: config.AvoidIndexBuild, }) doc.Index = idx diff --git a/index/index_model.go b/index/index_model.go index ddb811b..a1e6a83 100644 --- a/index/index_model.go +++ b/index/index_model.go @@ -76,6 +76,13 @@ type SpecIndexConfig struct { // a breakglass to be used to prevent loops, checking the tree before recursing down. ParentIndex *SpecIndex + // If set to true, the index will not be built out, which means only the foundational elements will be + // parsed and added to the index. This is useful to avoid building out an index if the specification is + // broken up into references and you want it fully resolved. + // + // Use the `BuildIndex()` method on the index to build it out once resolved/ready. + AvoidBuildIndex bool + // private fields seenRemoteSources *syncmap.Map remoteLock *sync.Mutex diff --git a/index/spec_index.go b/index/spec_index.go index 6a2fd00..22e3451 100644 --- a/index/spec_index.go +++ b/index/spec_index.go @@ -39,7 +39,7 @@ func NewSpecIndexWithConfig(rootNode *yaml.Node, config *SpecIndexConfig) *SpecI return index } boostrapIndexCollections(rootNode, index) - return createNewIndex(rootNode, index) + return createNewIndex(rootNode, index, config.AvoidBuildIndex) } // NewSpecIndex will create a new index of an OpenAPI or Swagger spec. It's not resolved or converted into anything @@ -55,10 +55,10 @@ func NewSpecIndex(rootNode *yaml.Node) *SpecIndex { index := new(SpecIndex) index.config = CreateOpenAPIIndexConfig() boostrapIndexCollections(rootNode, index) - return createNewIndex(rootNode, index) + return createNewIndex(rootNode, index, false) } -func createNewIndex(rootNode *yaml.Node, index *SpecIndex) *SpecIndex { +func createNewIndex(rootNode *yaml.Node, index *SpecIndex, avoidBuildOut bool) *SpecIndex { // there is no node! return an empty index. if rootNode == nil { return index @@ -82,6 +82,23 @@ func createNewIndex(rootNode *yaml.Node, index *SpecIndex) *SpecIndex { index.ExtractExternalDocuments(index.root) index.GetPathCount() + // build out the index. + if !avoidBuildOut { + index.BuildIndex() + } + + // do a copy! + index.config.seenRemoteSources.Range(func(k, v any) bool { + index.seenRemoteSources[k.(string)] = v.(*yaml.Node) + return true + }) + return index +} + +// BuildIndex will run all of the count operations required to build up maps of everything. It's what makes the index +// useful for looking up things, the count operations are all run in parallel and then the final calculations are run +// the index is ready. +func (index *SpecIndex) BuildIndex() { countFuncs := []func() int{ index.GetOperationCount, index.GetComponentSchemaCount, @@ -111,13 +128,6 @@ func createNewIndex(rootNode *yaml.Node, index *SpecIndex) *SpecIndex { index.GetInlineDuplicateParamCount() index.GetAllDescriptionsCount() index.GetTotalTagsCount() - - // do a copy! - index.config.seenRemoteSources.Range(func(k, v any) bool { - index.seenRemoteSources[k.(string)] = v.(*yaml.Node) - return true - }) - return index } // GetRootNode returns document root node.