From 7535cf568c482cc027ca7d5262556f85a082704d Mon Sep 17 00:00:00 2001 From: Dave Shanley Date: Sat, 30 Jul 2022 15:27:21 -0400 Subject: [PATCH] Working through the model builder Shaping out the design as I go, what makes sence, what feels right, what do we need, how do we want to use it and how to we want to search it etc. --- datamodel/low/3.0/contact.go | 2 - datamodel/low/3.0/document.go | 47 ++----- datamodel/low/3.0/info.go | 26 +++- datamodel/low/3.0/license.go | 2 - datamodel/low/3.0/server.go | 44 ++++++- datamodel/low/3.0/server_variable.go | 2 - datamodel/low/reference.go | 14 +- {utils => datamodel}/model_builder.go | 143 +++++++++++++++------ {utils => datamodel}/model_builder_test.go | 24 +--- openapi/create_document.go | 65 +++++++++- openapi/create_document_test.go | 2 +- test_specs/burgershop.openapi.yaml | 20 ++- utils/utils.go | 23 ++++ 13 files changed, 290 insertions(+), 124 deletions(-) rename {utils => datamodel}/model_builder.go (67%) rename {utils => datamodel}/model_builder_test.go (89%) diff --git a/datamodel/low/3.0/contact.go b/datamodel/low/3.0/contact.go index 08d90fb..5c31ecb 100644 --- a/datamodel/low/3.0/contact.go +++ b/datamodel/low/3.0/contact.go @@ -2,11 +2,9 @@ package v3 import ( "github.com/pb33f/libopenapi/datamodel/low" - "gopkg.in/yaml.v3" ) type Contact struct { - Node *yaml.Node Name low.NodeReference[string] URL low.NodeReference[string] Email low.NodeReference[string] diff --git a/datamodel/low/3.0/document.go b/datamodel/low/3.0/document.go index 518eb25..aec5c67 100644 --- a/datamodel/low/3.0/document.go +++ b/datamodel/low/3.0/document.go @@ -1,48 +1,17 @@ package v3 import ( - "fmt" "github.com/pb33f/libopenapi/datamodel/low" - "gopkg.in/yaml.v3" - "reflect" ) type Document struct { - Version string - Info Info - Servers []Server - Paths Paths - Components Components - Security []SecurityRequirement - Tags []Tag - ExternalDocs ExternalDoc + Version low.NodeReference[string] + Info low.NodeReference[*Info] + Servers []low.NodeReference[*Server] + Paths *Paths + Components *Components + Security []*SecurityRequirement + Tags []*Tag + ExternalDocs *ExternalDoc Extensions map[string]low.ObjectReference } - -func (d Document) Build(node *yaml.Node) { - - doc := Document{ - Version: "", - Info: Info{}, - Servers: nil, - Paths: Paths{}, - Components: Components{}, - Security: nil, - Tags: nil, - ExternalDocs: ExternalDoc{}, - Extensions: nil, - } - - var j interface{} - j = doc - t := reflect.TypeOf(j) - v := reflect.ValueOf(j) - k := t.Kind() - fmt.Println("Type ", t) - fmt.Println("Value ", v) - fmt.Println("Kind ", k) - for i := 0; i < v.NumField(); i++ { - fmt.Printf("Field:%d type:%T value:%v\n", i, v.Field(i), v.Field(i)) - } - -} diff --git a/datamodel/low/3.0/info.go b/datamodel/low/3.0/info.go index 1bd3f12..310aa33 100644 --- a/datamodel/low/3.0/info.go +++ b/datamodel/low/3.0/info.go @@ -1,16 +1,36 @@ package v3 import ( + "github.com/pb33f/libopenapi/datamodel" "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/utils" "gopkg.in/yaml.v3" + "sync" ) type Info struct { - Node *yaml.Node Title low.NodeReference[string] Description low.NodeReference[string] TermsOfService low.NodeReference[string] - Contact Contact - License License + Contact low.NodeReference[*Contact] + License low.NodeReference[*License] Version low.NodeReference[string] } + +func (i *Info) Build(root *yaml.Node) error { + var wg sync.WaitGroup + wg.Add(2) + var errs []error + + contact := Contact{} + _, kln, cn := utils.FindKeyNodeFull("contact", root.Content) + go datamodel.BuildModelAsync(cn, &contact, &wg, &errs) + + license := License{} + _, kln, ln := utils.FindKeyNodeFull("license", root.Content) + go datamodel.BuildModelAsync(ln, &license, &wg, &errs) + wg.Wait() + i.Contact = low.NodeReference[*Contact]{Value: &contact, ValueNode: cn, KeyNode: kln} + i.License = low.NodeReference[*License]{Value: &license, ValueNode: ln, KeyNode: kln} + return nil +} diff --git a/datamodel/low/3.0/license.go b/datamodel/low/3.0/license.go index 1a2d925..e578fc3 100644 --- a/datamodel/low/3.0/license.go +++ b/datamodel/low/3.0/license.go @@ -2,11 +2,9 @@ package v3 import ( "github.com/pb33f/libopenapi/datamodel/low" - "gopkg.in/yaml.v3" ) type License struct { - Node *yaml.Node Name low.NodeReference[string] URL low.NodeReference[string] } diff --git a/datamodel/low/3.0/server.go b/datamodel/low/3.0/server.go index 34c0e4e..7fa7417 100644 --- a/datamodel/low/3.0/server.go +++ b/datamodel/low/3.0/server.go @@ -1,9 +1,49 @@ package v3 -import "github.com/pb33f/libopenapi/datamodel/low" +import ( + "github.com/pb33f/libopenapi/datamodel" + "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/utils" + "gopkg.in/yaml.v3" +) type Server struct { URL low.NodeReference[string] Description low.NodeReference[string] - Variables map[string]ServerVariable + Variables low.NodeReference[*map[string]low.NodeReference[*ServerVariable]] +} + +func (s *Server) Build(root *yaml.Node) error { + kn, vars := utils.FindKeyNode("variables", root.Content) + if vars == nil { + return nil + } + variablesMap := make(map[string]low.NodeReference[*ServerVariable]) + if utils.IsNodeMap(vars) { + var currentNode string + var keyNode *yaml.Node + for i, varNode := range vars.Content { + if i%2 == 0 { + currentNode = varNode.Value + keyNode = varNode + continue + } + variable := ServerVariable{} + err := datamodel.BuildModel(varNode, &variable) + if err != nil { + return err + } + variablesMap[currentNode] = low.NodeReference[*ServerVariable]{ + ValueNode: varNode, + KeyNode: keyNode, + Value: &variable, + } + } + s.Variables = low.NodeReference[*map[string]low.NodeReference[*ServerVariable]]{ + KeyNode: kn, + ValueNode: vars, + Value: &variablesMap, + } + } + return nil } diff --git a/datamodel/low/3.0/server_variable.go b/datamodel/low/3.0/server_variable.go index 47e7ce0..4d7f5af 100644 --- a/datamodel/low/3.0/server_variable.go +++ b/datamodel/low/3.0/server_variable.go @@ -2,11 +2,9 @@ package v3 import ( "github.com/pb33f/libopenapi/datamodel/low" - "gopkg.in/yaml.v3" ) type ServerVariable struct { - Node *yaml.Node Enum []low.NodeReference[string] Default low.NodeReference[string] Description low.NodeReference[string] diff --git a/datamodel/low/reference.go b/datamodel/low/reference.go index a9cd1a3..6f7795a 100644 --- a/datamodel/low/reference.go +++ b/datamodel/low/reference.go @@ -7,15 +7,17 @@ type HasNode interface { } type Buildable interface { - Build(node *yaml.Node) + Build(node *yaml.Node) error } -type NodeReference[T comparable] struct { - Value T - Node *yaml.Node +type NodeReference[T any] struct { + Value T + ValueNode *yaml.Node + KeyNode *yaml.Node } type ObjectReference struct { - Value map[string]interface{} - Node *yaml.Node + Value map[string]interface{} + ValueNode *yaml.Node + KeyNode *yaml.Node } diff --git a/utils/model_builder.go b/datamodel/model_builder.go similarity index 67% rename from utils/model_builder.go rename to datamodel/model_builder.go index 7f84ed6..4f7ef85 100644 --- a/utils/model_builder.go +++ b/datamodel/model_builder.go @@ -1,11 +1,13 @@ -package utils +package datamodel import ( "fmt" "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/utils" "gopkg.in/yaml.v3" "reflect" "strconv" + "sync" ) func BuildModel(node *yaml.Node, model interface{}) error { @@ -19,12 +21,12 @@ func BuildModel(node *yaml.Node, model interface{}) error { fName := v.Type().Field(i).Name // we need to find a matching field in the YAML, the cases may be off, so take no chances. - cases := []Case{PascalCase, CamelCase, ScreamingSnakeCase, - SnakeCase, KebabCase, RegularCase} + cases := []utils.Case{utils.PascalCase, utils.CamelCase, utils.ScreamingSnakeCase, + utils.SnakeCase, utils.KebabCase, utils.RegularCase} var vn, kn *yaml.Node for _, tryCase := range cases { - kn, vn = FindKeyNode(ConvertCase(fName, tryCase), node.Content) + kn, vn = utils.FindKeyNode(utils.ConvertCase(fName, tryCase), node.Content) if vn != nil { break } @@ -38,7 +40,7 @@ func BuildModel(node *yaml.Node, model interface{}) error { field := v.FieldByName(fName) kind := field.Kind() switch kind { - case reflect.Struct, reflect.Slice, reflect.Map: + case reflect.Struct, reflect.Slice, reflect.Map, reflect.Pointer: err := SetField(field, vn, kn) if err != nil { return err @@ -57,7 +59,7 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err case reflect.TypeOf(map[string]low.ObjectReference{}): if valueNode != nil { - if IsNodeMap(valueNode) { + if utils.IsNodeMap(valueNode) { if field.CanSet() { items := make(map[string]low.ObjectReference) var currentLabel string @@ -72,8 +74,9 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err return err } items[currentLabel] = low.ObjectReference{ - Value: decoded, - Node: sliceItem, + Value: decoded, + ValueNode: sliceItem, + KeyNode: valueNode, } } field.Set(reflect.ValueOf(items)) @@ -84,7 +87,7 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err case reflect.TypeOf(map[string]low.NodeReference[string]{}): if valueNode != nil { - if IsNodeMap(valueNode) { + if utils.IsNodeMap(valueNode) { if field.CanSet() { items := make(map[string]low.NodeReference[string]) var currentLabel string @@ -94,8 +97,9 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err continue } items[currentLabel] = low.NodeReference[string]{ - Value: sliceItem.Value, - Node: sliceItem, + Value: sliceItem.Value, + ValueNode: sliceItem, + KeyNode: valueNode, } } field.Set(reflect.ValueOf(items)) @@ -110,9 +114,9 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err if err != nil { return err } - if IsNodeMap(valueNode) { + if utils.IsNodeMap(valueNode) { if field.CanSet() { - or := low.ObjectReference{Value: decoded, Node: valueNode} + or := low.ObjectReference{Value: decoded, ValueNode: valueNode} field.Set(reflect.ValueOf(or)) } } @@ -120,7 +124,7 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err break case reflect.TypeOf([]low.ObjectReference{}): if valueNode != nil { - if IsNodeArray(valueNode) { + if utils.IsNodeArray(valueNode) { if field.CanSet() { var items []low.ObjectReference for _, sliceItem := range valueNode.Content { @@ -130,8 +134,9 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err return err } items = append(items, low.ObjectReference{ - Value: decoded, - Node: sliceItem, + Value: decoded, + ValueNode: sliceItem, + KeyNode: valueNode, }) } field.Set(reflect.ValueOf(items)) @@ -141,9 +146,13 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err break case reflect.TypeOf(low.NodeReference[string]{}): if valueNode != nil { - if IsNodeStringValue(valueNode) { + if utils.IsNodeStringValue(valueNode) { if field.CanSet() { - nr := low.NodeReference[string]{Value: valueNode.Value, Node: valueNode} + nr := low.NodeReference[string]{ + Value: valueNode.Value, + ValueNode: valueNode, + KeyNode: keyNode, + } field.Set(reflect.ValueOf(nr)) } } @@ -151,10 +160,14 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err break case reflect.TypeOf(low.NodeReference[bool]{}): if valueNode != nil { - if IsNodeBoolValue(valueNode) { + if utils.IsNodeBoolValue(valueNode) { if field.CanSet() { bv, _ := strconv.ParseBool(valueNode.Value) - nr := low.NodeReference[bool]{Value: bv, Node: valueNode} + nr := low.NodeReference[bool]{ + Value: bv, + ValueNode: valueNode, + KeyNode: keyNode, + } field.Set(reflect.ValueOf(nr)) } } @@ -162,10 +175,14 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err break case reflect.TypeOf(low.NodeReference[int]{}): if valueNode != nil { - if IsNodeIntValue(valueNode) { + if utils.IsNodeIntValue(valueNode) { if field.CanSet() { fv, _ := strconv.Atoi(valueNode.Value) - nr := low.NodeReference[int]{Value: fv, Node: valueNode} + nr := low.NodeReference[int]{ + Value: fv, + ValueNode: valueNode, + KeyNode: keyNode, + } field.Set(reflect.ValueOf(nr)) } } @@ -173,10 +190,14 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err break case reflect.TypeOf(low.NodeReference[int64]{}): if valueNode != nil { - if IsNodeIntValue(valueNode) || IsNodeFloatValue(valueNode) { // + if utils.IsNodeIntValue(valueNode) || utils.IsNodeFloatValue(valueNode) { // if field.CanSet() { fv, _ := strconv.ParseInt(valueNode.Value, 10, 64) - nr := low.NodeReference[int64]{Value: fv, Node: valueNode} + nr := low.NodeReference[int64]{ + Value: fv, + ValueNode: valueNode, + KeyNode: keyNode, + } field.Set(reflect.ValueOf(nr)) } } @@ -184,10 +205,14 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err break case reflect.TypeOf(low.NodeReference[float32]{}): if valueNode != nil { - if IsNodeFloatValue(valueNode) { + if utils.IsNodeFloatValue(valueNode) { if field.CanSet() { fv, _ := strconv.ParseFloat(valueNode.Value, 32) - nr := low.NodeReference[float32]{Value: float32(fv), Node: valueNode} + nr := low.NodeReference[float32]{ + Value: float32(fv), + ValueNode: valueNode, + KeyNode: keyNode, + } field.Set(reflect.ValueOf(nr)) } } @@ -195,10 +220,14 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err break case reflect.TypeOf(low.NodeReference[float64]{}): if valueNode != nil { - if IsNodeFloatValue(valueNode) { + if utils.IsNodeFloatValue(valueNode) { if field.CanSet() { fv, _ := strconv.ParseFloat(valueNode.Value, 64) - nr := low.NodeReference[float64]{Value: fv, Node: valueNode} + nr := low.NodeReference[float64]{ + Value: fv, + ValueNode: valueNode, + KeyNode: keyNode, + } field.Set(reflect.ValueOf(nr)) } } @@ -206,11 +235,15 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err break case reflect.TypeOf([]low.NodeReference[string]{}): if valueNode != nil { - if IsNodeArray(valueNode) { + if utils.IsNodeArray(valueNode) { if field.CanSet() { var items []low.NodeReference[string] for _, sliceItem := range valueNode.Content { - items = append(items, low.NodeReference[string]{Value: sliceItem.Value, Node: sliceItem}) + items = append(items, low.NodeReference[string]{ + Value: sliceItem.Value, + ValueNode: sliceItem, + KeyNode: valueNode, + }) } field.Set(reflect.ValueOf(items)) } @@ -219,12 +252,16 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err break case reflect.TypeOf([]low.NodeReference[float32]{}): if valueNode != nil { - if IsNodeArray(valueNode) { + if utils.IsNodeArray(valueNode) { if field.CanSet() { var items []low.NodeReference[float32] for _, sliceItem := range valueNode.Content { fv, _ := strconv.ParseFloat(sliceItem.Value, 32) - items = append(items, low.NodeReference[float32]{Value: float32(fv), Node: sliceItem}) + items = append(items, low.NodeReference[float32]{ + Value: float32(fv), + ValueNode: sliceItem, + KeyNode: valueNode, + }) } field.Set(reflect.ValueOf(items)) } @@ -233,12 +270,12 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err break case reflect.TypeOf([]low.NodeReference[float64]{}): if valueNode != nil { - if IsNodeArray(valueNode) { + if utils.IsNodeArray(valueNode) { if field.CanSet() { var items []low.NodeReference[float64] for _, sliceItem := range valueNode.Content { fv, _ := strconv.ParseFloat(sliceItem.Value, 64) - items = append(items, low.NodeReference[float64]{Value: fv, Node: sliceItem}) + items = append(items, low.NodeReference[float64]{Value: fv, ValueNode: sliceItem}) } field.Set(reflect.ValueOf(items)) } @@ -247,12 +284,16 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err break case reflect.TypeOf([]low.NodeReference[int]{}): if valueNode != nil { - if IsNodeArray(valueNode) { + if utils.IsNodeArray(valueNode) { if field.CanSet() { var items []low.NodeReference[int] for _, sliceItem := range valueNode.Content { iv, _ := strconv.Atoi(sliceItem.Value) - items = append(items, low.NodeReference[int]{Value: iv, Node: sliceItem}) + items = append(items, low.NodeReference[int]{ + Value: iv, + ValueNode: sliceItem, + KeyNode: valueNode, + }) } field.Set(reflect.ValueOf(items)) } @@ -261,12 +302,16 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err break case reflect.TypeOf([]low.NodeReference[int64]{}): if valueNode != nil { - if IsNodeArray(valueNode) { + if utils.IsNodeArray(valueNode) { if field.CanSet() { var items []low.NodeReference[int64] for _, sliceItem := range valueNode.Content { iv, _ := strconv.ParseInt(sliceItem.Value, 10, 64) - items = append(items, low.NodeReference[int64]{Value: iv, Node: sliceItem}) + items = append(items, low.NodeReference[int64]{ + Value: iv, + ValueNode: sliceItem, + KeyNode: valueNode, + }) } field.Set(reflect.ValueOf(items)) } @@ -275,12 +320,16 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err break case reflect.TypeOf([]low.NodeReference[bool]{}): if valueNode != nil { - if IsNodeArray(valueNode) { + if utils.IsNodeArray(valueNode) { if field.CanSet() { var items []low.NodeReference[bool] for _, sliceItem := range valueNode.Content { bv, _ := strconv.ParseBool(sliceItem.Value) - items = append(items, low.NodeReference[bool]{Value: bv, Node: sliceItem}) + items = append(items, low.NodeReference[bool]{ + Value: bv, + ValueNode: sliceItem, + KeyNode: valueNode, + }) } field.Set(reflect.ValueOf(items)) } @@ -288,8 +337,18 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err } break default: - m := field.Type() - return fmt.Errorf("unknown type, cannot parse: %v", m) + // we want to ignore everything else. + break } return nil } + +func BuildModelAsync(n *yaml.Node, model interface{}, lwg *sync.WaitGroup, errors *[]error) { + if n != nil { + err := BuildModel(n, model) + if err != nil { + *errors = append(*errors, err) + } + } + lwg.Done() +} diff --git a/utils/model_builder_test.go b/datamodel/model_builder_test.go similarity index 89% rename from utils/model_builder_test.go rename to datamodel/model_builder_test.go index 8cfccad..e5306f8 100644 --- a/utils/model_builder_test.go +++ b/datamodel/model_builder_test.go @@ -1,4 +1,4 @@ -package utils +package datamodel import ( "github.com/pb33f/libopenapi/datamodel/low" @@ -106,7 +106,7 @@ there: hd := hotdog{} cErr := BuildModel(&rootNode, &hd) assert.Equal(t, 200, hd.Fat.Value) - assert.Equal(t, 3, hd.Fat.Node.Line) + assert.Equal(t, 3, hd.Fat.ValueNode.Line) assert.Equal(t, true, hd.Grilled.Value) assert.Equal(t, "yummy", hd.Name.Value) assert.Equal(t, float32(200.45), hd.Ketchup.Value) @@ -119,7 +119,7 @@ there: assert.Len(t, hd.MaxTempAlt, 5) assert.Equal(t, int64(7392837462032342), hd.MaxTempHigh.Value) assert.Equal(t, 2, hd.Temps[1].Value) - assert.Equal(t, 26, hd.Temps[1].Node.Line) + assert.Equal(t, 26, hd.Temps[1].ValueNode.Line) assert.Len(t, hd.UnknownElements.Value, 2) assert.Len(t, hd.LotsOfUnknowns, 3) assert.Len(t, hd.Where, 2) @@ -129,24 +129,6 @@ there: assert.NoError(t, cErr) } -func TestBuildModel_UnsupportedType(t *testing.T) { - - type notSupported struct { - cake low.NodeReference[uintptr] - } - ns := notSupported{} - yml := `cake: -99999` - - var rootNode yaml.Node - mErr := yaml.Unmarshal([]byte(yml), &rootNode) - assert.NoError(t, mErr) - - cErr := BuildModel(&rootNode, &ns) - assert.Error(t, cErr) - assert.Nil(t, ns.cake) - -} - func TestBuildModel_UseCopyNotRef(t *testing.T) { yml := `cake: -99999` diff --git a/openapi/create_document.go b/openapi/create_document.go index 861d653..ba38635 100644 --- a/openapi/create_document.go +++ b/openapi/create_document.go @@ -2,7 +2,9 @@ package openapi import ( "github.com/pb33f/libopenapi/datamodel" + "github.com/pb33f/libopenapi/datamodel/low" v3 "github.com/pb33f/libopenapi/datamodel/low/3.0" + "github.com/pb33f/libopenapi/utils" ) func CreateDocument(spec []byte) (*v3.Document, error) { @@ -13,7 +15,64 @@ func CreateDocument(spec []byte) (*v3.Document, error) { return nil, err } - doc := &v3.Document{} - doc.Build(info.RootNode.Content[0]) - return doc, nil + doc := v3.Document{Version: low.NodeReference[string]{Value: info.Version, ValueNode: info.RootNode}} + + // build an index + //idx := index.NewSpecIndex(info.RootNode) + datamodel.BuildModel(info.RootNode.Content[0], &doc) + + // extract info + extractErr := extractInfo(info, &doc) + if extractErr != nil { + return nil, extractErr + } + + // extract servers + extractErr = extractServers(info, &doc) + if extractErr != nil { + return nil, extractErr + } + + return &doc, nil +} + +func extractInfo(info *datamodel.SpecInfo, doc *v3.Document) error { + _, ln, vn := utils.FindKeyNodeFull("info", info.RootNode.Content) + if vn != nil { + ir := v3.Info{} + err := datamodel.BuildModel(vn, &ir) + if err != nil { + return err + } + err = ir.Build(vn) + nr := low.NodeReference[*v3.Info]{Value: &ir, ValueNode: vn, KeyNode: ln} + doc.Info = nr + } + return nil +} + +func extractServers(info *datamodel.SpecInfo, doc *v3.Document) error { + _, ln, vn := utils.FindKeyNodeFull("servers", info.RootNode.Content) + if vn != nil { + if utils.IsNodeArray(vn) { + var servers []low.NodeReference[*v3.Server] + for _, srvN := range vn.Content { + if utils.IsNodeMap(srvN) { + srvr := v3.Server{} + err := datamodel.BuildModel(srvN, &srvr) + if err != nil { + return err + } + srvr.Build(srvN) + servers = append(servers, low.NodeReference[*v3.Server]{ + Value: &srvr, + ValueNode: srvN, + KeyNode: ln, + }) + } + } + doc.Servers = servers + } + } + return nil } diff --git a/openapi/create_document_test.go b/openapi/create_document_test.go index 94c1f91..7d914a9 100644 --- a/openapi/create_document_test.go +++ b/openapi/create_document_test.go @@ -13,7 +13,7 @@ func TestCreateDocument_NoData(t *testing.T) { } func TestCreateDocument(t *testing.T) { - data, aErr := ioutil.ReadFile("../test_specs/petstorev3.json") + data, aErr := ioutil.ReadFile("../test_specs/burgershop.openapi.yaml") assert.NoError(t, aErr) doc, err := CreateDocument(data) diff --git a/test_specs/burgershop.openapi.yaml b/test_specs/burgershop.openapi.yaml index c7b17db..883bac2 100644 --- a/test_specs/burgershop.openapi.yaml +++ b/test_specs/burgershop.openapi.yaml @@ -6,8 +6,11 @@ info: termsOfService: https://quobix.com contact: name: quobix + email: test@quobix.com + url: https://quobix.com license: name: Quobix + url: https://quobix.com/made-up version: "1.2" tags: - name: "Burgers" @@ -21,7 +24,22 @@ tags: description: "Find out more information about our products)" url: "https://quobix.com/" servers: - - url: https://quobix.com/api + - url: "{scheme}://api.quobix.com" + description: "this is our main API server, for all fun API things." + variables: + scheme: + enum: [https] + default: https + description: this is a server variable for the scheme + - url: "https://{domain}.{host}.com" + description: "this is our second API server, for all fun API things." + variables: + domain: + default: "api" + description: the default API domain is 'api' + host: + default: "quobix.com" + description: the default host for this API is 'quobix.com' paths: /burgers: post: diff --git a/utils/utils.go b/utils/utils.go index be232a1..3923c3a 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -239,6 +239,29 @@ func FindKeyNode(key string, nodes []*yaml.Node) (keyNode *yaml.Node, valueNode return nil, nil } +func FindKeyNodeFull(key string, nodes []*yaml.Node) (keyNode *yaml.Node, labelNode *yaml.Node, valueNode *yaml.Node) { + for i, v := range nodes { + if i%2 == 0 && key == v.Value { + return v, nodes[i], nodes[i+1] // next node is what we need. + } + for x, j := range v.Content { + if key == j.Value { + if IsNodeMap(v) { + if x+1 == len(v.Content) { + return v, v.Content[x], v.Content[x] + } + return v, v.Content[x], v.Content[x+1] // next node is what we need. + + } + if IsNodeArray(v) { + return v, v.Content[x], v.Content[x] + } + } + } + } + return nil, nil, nil +} + var ObjectLabel = "object" var IntegerLabel = "integer" var NumberLabel = "number"