mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-09 04:20:17 +00:00
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.
This commit is contained in:
@@ -2,11 +2,9 @@ package v3
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Contact struct {
|
type Contact struct {
|
||||||
Node *yaml.Node
|
|
||||||
Name low.NodeReference[string]
|
Name low.NodeReference[string]
|
||||||
URL low.NodeReference[string]
|
URL low.NodeReference[string]
|
||||||
Email low.NodeReference[string]
|
Email low.NodeReference[string]
|
||||||
|
|||||||
@@ -1,48 +1,17 @@
|
|||||||
package v3
|
package v3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
"reflect"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Document struct {
|
type Document struct {
|
||||||
Version string
|
Version low.NodeReference[string]
|
||||||
Info Info
|
Info low.NodeReference[*Info]
|
||||||
Servers []Server
|
Servers []low.NodeReference[*Server]
|
||||||
Paths Paths
|
Paths *Paths
|
||||||
Components Components
|
Components *Components
|
||||||
Security []SecurityRequirement
|
Security []*SecurityRequirement
|
||||||
Tags []Tag
|
Tags []*Tag
|
||||||
ExternalDocs ExternalDoc
|
ExternalDocs *ExternalDoc
|
||||||
Extensions map[string]low.ObjectReference
|
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))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,16 +1,36 @@
|
|||||||
package v3
|
package v3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/pb33f/libopenapi/datamodel"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Info struct {
|
type Info struct {
|
||||||
Node *yaml.Node
|
|
||||||
Title low.NodeReference[string]
|
Title low.NodeReference[string]
|
||||||
Description low.NodeReference[string]
|
Description low.NodeReference[string]
|
||||||
TermsOfService low.NodeReference[string]
|
TermsOfService low.NodeReference[string]
|
||||||
Contact Contact
|
Contact low.NodeReference[*Contact]
|
||||||
License License
|
License low.NodeReference[*License]
|
||||||
Version low.NodeReference[string]
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,11 +2,9 @@ package v3
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type License struct {
|
type License struct {
|
||||||
Node *yaml.Node
|
|
||||||
Name low.NodeReference[string]
|
Name low.NodeReference[string]
|
||||||
URL low.NodeReference[string]
|
URL low.NodeReference[string]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,49 @@
|
|||||||
package v3
|
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 {
|
type Server struct {
|
||||||
URL low.NodeReference[string]
|
URL low.NodeReference[string]
|
||||||
Description 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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,9 @@ package v3
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServerVariable struct {
|
type ServerVariable struct {
|
||||||
Node *yaml.Node
|
|
||||||
Enum []low.NodeReference[string]
|
Enum []low.NodeReference[string]
|
||||||
Default low.NodeReference[string]
|
Default low.NodeReference[string]
|
||||||
Description low.NodeReference[string]
|
Description low.NodeReference[string]
|
||||||
|
|||||||
@@ -7,15 +7,17 @@ type HasNode interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Buildable interface {
|
type Buildable interface {
|
||||||
Build(node *yaml.Node)
|
Build(node *yaml.Node) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type NodeReference[T comparable] struct {
|
type NodeReference[T any] struct {
|
||||||
Value T
|
Value T
|
||||||
Node *yaml.Node
|
ValueNode *yaml.Node
|
||||||
|
KeyNode *yaml.Node
|
||||||
}
|
}
|
||||||
|
|
||||||
type ObjectReference struct {
|
type ObjectReference struct {
|
||||||
Value map[string]interface{}
|
Value map[string]interface{}
|
||||||
Node *yaml.Node
|
ValueNode *yaml.Node
|
||||||
|
KeyNode *yaml.Node
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
package utils
|
package datamodel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
func BuildModel(node *yaml.Node, model interface{}) error {
|
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
|
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.
|
// we need to find a matching field in the YAML, the cases may be off, so take no chances.
|
||||||
cases := []Case{PascalCase, CamelCase, ScreamingSnakeCase,
|
cases := []utils.Case{utils.PascalCase, utils.CamelCase, utils.ScreamingSnakeCase,
|
||||||
SnakeCase, KebabCase, RegularCase}
|
utils.SnakeCase, utils.KebabCase, utils.RegularCase}
|
||||||
|
|
||||||
var vn, kn *yaml.Node
|
var vn, kn *yaml.Node
|
||||||
for _, tryCase := range cases {
|
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 {
|
if vn != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -38,7 +40,7 @@ func BuildModel(node *yaml.Node, model interface{}) error {
|
|||||||
field := v.FieldByName(fName)
|
field := v.FieldByName(fName)
|
||||||
kind := field.Kind()
|
kind := field.Kind()
|
||||||
switch kind {
|
switch kind {
|
||||||
case reflect.Struct, reflect.Slice, reflect.Map:
|
case reflect.Struct, reflect.Slice, reflect.Map, reflect.Pointer:
|
||||||
err := SetField(field, vn, kn)
|
err := SetField(field, vn, kn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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{}):
|
case reflect.TypeOf(map[string]low.ObjectReference{}):
|
||||||
if valueNode != nil {
|
if valueNode != nil {
|
||||||
if IsNodeMap(valueNode) {
|
if utils.IsNodeMap(valueNode) {
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
items := make(map[string]low.ObjectReference)
|
items := make(map[string]low.ObjectReference)
|
||||||
var currentLabel string
|
var currentLabel string
|
||||||
@@ -73,7 +75,8 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err
|
|||||||
}
|
}
|
||||||
items[currentLabel] = low.ObjectReference{
|
items[currentLabel] = low.ObjectReference{
|
||||||
Value: decoded,
|
Value: decoded,
|
||||||
Node: sliceItem,
|
ValueNode: sliceItem,
|
||||||
|
KeyNode: valueNode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
field.Set(reflect.ValueOf(items))
|
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]{}):
|
case reflect.TypeOf(map[string]low.NodeReference[string]{}):
|
||||||
if valueNode != nil {
|
if valueNode != nil {
|
||||||
if IsNodeMap(valueNode) {
|
if utils.IsNodeMap(valueNode) {
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
items := make(map[string]low.NodeReference[string])
|
items := make(map[string]low.NodeReference[string])
|
||||||
var currentLabel string
|
var currentLabel string
|
||||||
@@ -95,7 +98,8 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err
|
|||||||
}
|
}
|
||||||
items[currentLabel] = low.NodeReference[string]{
|
items[currentLabel] = low.NodeReference[string]{
|
||||||
Value: sliceItem.Value,
|
Value: sliceItem.Value,
|
||||||
Node: sliceItem,
|
ValueNode: sliceItem,
|
||||||
|
KeyNode: valueNode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
field.Set(reflect.ValueOf(items))
|
field.Set(reflect.ValueOf(items))
|
||||||
@@ -110,9 +114,9 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if IsNodeMap(valueNode) {
|
if utils.IsNodeMap(valueNode) {
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
or := low.ObjectReference{Value: decoded, Node: valueNode}
|
or := low.ObjectReference{Value: decoded, ValueNode: valueNode}
|
||||||
field.Set(reflect.ValueOf(or))
|
field.Set(reflect.ValueOf(or))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,7 +124,7 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err
|
|||||||
break
|
break
|
||||||
case reflect.TypeOf([]low.ObjectReference{}):
|
case reflect.TypeOf([]low.ObjectReference{}):
|
||||||
if valueNode != nil {
|
if valueNode != nil {
|
||||||
if IsNodeArray(valueNode) {
|
if utils.IsNodeArray(valueNode) {
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
var items []low.ObjectReference
|
var items []low.ObjectReference
|
||||||
for _, sliceItem := range valueNode.Content {
|
for _, sliceItem := range valueNode.Content {
|
||||||
@@ -131,7 +135,8 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err
|
|||||||
}
|
}
|
||||||
items = append(items, low.ObjectReference{
|
items = append(items, low.ObjectReference{
|
||||||
Value: decoded,
|
Value: decoded,
|
||||||
Node: sliceItem,
|
ValueNode: sliceItem,
|
||||||
|
KeyNode: valueNode,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
field.Set(reflect.ValueOf(items))
|
field.Set(reflect.ValueOf(items))
|
||||||
@@ -141,9 +146,13 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err
|
|||||||
break
|
break
|
||||||
case reflect.TypeOf(low.NodeReference[string]{}):
|
case reflect.TypeOf(low.NodeReference[string]{}):
|
||||||
if valueNode != nil {
|
if valueNode != nil {
|
||||||
if IsNodeStringValue(valueNode) {
|
if utils.IsNodeStringValue(valueNode) {
|
||||||
if field.CanSet() {
|
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))
|
field.Set(reflect.ValueOf(nr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,10 +160,14 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err
|
|||||||
break
|
break
|
||||||
case reflect.TypeOf(low.NodeReference[bool]{}):
|
case reflect.TypeOf(low.NodeReference[bool]{}):
|
||||||
if valueNode != nil {
|
if valueNode != nil {
|
||||||
if IsNodeBoolValue(valueNode) {
|
if utils.IsNodeBoolValue(valueNode) {
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
bv, _ := strconv.ParseBool(valueNode.Value)
|
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))
|
field.Set(reflect.ValueOf(nr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -162,10 +175,14 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err
|
|||||||
break
|
break
|
||||||
case reflect.TypeOf(low.NodeReference[int]{}):
|
case reflect.TypeOf(low.NodeReference[int]{}):
|
||||||
if valueNode != nil {
|
if valueNode != nil {
|
||||||
if IsNodeIntValue(valueNode) {
|
if utils.IsNodeIntValue(valueNode) {
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
fv, _ := strconv.Atoi(valueNode.Value)
|
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))
|
field.Set(reflect.ValueOf(nr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,10 +190,14 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err
|
|||||||
break
|
break
|
||||||
case reflect.TypeOf(low.NodeReference[int64]{}):
|
case reflect.TypeOf(low.NodeReference[int64]{}):
|
||||||
if valueNode != nil {
|
if valueNode != nil {
|
||||||
if IsNodeIntValue(valueNode) || IsNodeFloatValue(valueNode) { //
|
if utils.IsNodeIntValue(valueNode) || utils.IsNodeFloatValue(valueNode) { //
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
fv, _ := strconv.ParseInt(valueNode.Value, 10, 64)
|
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))
|
field.Set(reflect.ValueOf(nr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -184,10 +205,14 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err
|
|||||||
break
|
break
|
||||||
case reflect.TypeOf(low.NodeReference[float32]{}):
|
case reflect.TypeOf(low.NodeReference[float32]{}):
|
||||||
if valueNode != nil {
|
if valueNode != nil {
|
||||||
if IsNodeFloatValue(valueNode) {
|
if utils.IsNodeFloatValue(valueNode) {
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
fv, _ := strconv.ParseFloat(valueNode.Value, 32)
|
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))
|
field.Set(reflect.ValueOf(nr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -195,10 +220,14 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err
|
|||||||
break
|
break
|
||||||
case reflect.TypeOf(low.NodeReference[float64]{}):
|
case reflect.TypeOf(low.NodeReference[float64]{}):
|
||||||
if valueNode != nil {
|
if valueNode != nil {
|
||||||
if IsNodeFloatValue(valueNode) {
|
if utils.IsNodeFloatValue(valueNode) {
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
fv, _ := strconv.ParseFloat(valueNode.Value, 64)
|
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))
|
field.Set(reflect.ValueOf(nr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -206,11 +235,15 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err
|
|||||||
break
|
break
|
||||||
case reflect.TypeOf([]low.NodeReference[string]{}):
|
case reflect.TypeOf([]low.NodeReference[string]{}):
|
||||||
if valueNode != nil {
|
if valueNode != nil {
|
||||||
if IsNodeArray(valueNode) {
|
if utils.IsNodeArray(valueNode) {
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
var items []low.NodeReference[string]
|
var items []low.NodeReference[string]
|
||||||
for _, sliceItem := range valueNode.Content {
|
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))
|
field.Set(reflect.ValueOf(items))
|
||||||
}
|
}
|
||||||
@@ -219,12 +252,16 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err
|
|||||||
break
|
break
|
||||||
case reflect.TypeOf([]low.NodeReference[float32]{}):
|
case reflect.TypeOf([]low.NodeReference[float32]{}):
|
||||||
if valueNode != nil {
|
if valueNode != nil {
|
||||||
if IsNodeArray(valueNode) {
|
if utils.IsNodeArray(valueNode) {
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
var items []low.NodeReference[float32]
|
var items []low.NodeReference[float32]
|
||||||
for _, sliceItem := range valueNode.Content {
|
for _, sliceItem := range valueNode.Content {
|
||||||
fv, _ := strconv.ParseFloat(sliceItem.Value, 32)
|
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))
|
field.Set(reflect.ValueOf(items))
|
||||||
}
|
}
|
||||||
@@ -233,12 +270,12 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err
|
|||||||
break
|
break
|
||||||
case reflect.TypeOf([]low.NodeReference[float64]{}):
|
case reflect.TypeOf([]low.NodeReference[float64]{}):
|
||||||
if valueNode != nil {
|
if valueNode != nil {
|
||||||
if IsNodeArray(valueNode) {
|
if utils.IsNodeArray(valueNode) {
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
var items []low.NodeReference[float64]
|
var items []low.NodeReference[float64]
|
||||||
for _, sliceItem := range valueNode.Content {
|
for _, sliceItem := range valueNode.Content {
|
||||||
fv, _ := strconv.ParseFloat(sliceItem.Value, 64)
|
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))
|
field.Set(reflect.ValueOf(items))
|
||||||
}
|
}
|
||||||
@@ -247,12 +284,16 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err
|
|||||||
break
|
break
|
||||||
case reflect.TypeOf([]low.NodeReference[int]{}):
|
case reflect.TypeOf([]low.NodeReference[int]{}):
|
||||||
if valueNode != nil {
|
if valueNode != nil {
|
||||||
if IsNodeArray(valueNode) {
|
if utils.IsNodeArray(valueNode) {
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
var items []low.NodeReference[int]
|
var items []low.NodeReference[int]
|
||||||
for _, sliceItem := range valueNode.Content {
|
for _, sliceItem := range valueNode.Content {
|
||||||
iv, _ := strconv.Atoi(sliceItem.Value)
|
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))
|
field.Set(reflect.ValueOf(items))
|
||||||
}
|
}
|
||||||
@@ -261,12 +302,16 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err
|
|||||||
break
|
break
|
||||||
case reflect.TypeOf([]low.NodeReference[int64]{}):
|
case reflect.TypeOf([]low.NodeReference[int64]{}):
|
||||||
if valueNode != nil {
|
if valueNode != nil {
|
||||||
if IsNodeArray(valueNode) {
|
if utils.IsNodeArray(valueNode) {
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
var items []low.NodeReference[int64]
|
var items []low.NodeReference[int64]
|
||||||
for _, sliceItem := range valueNode.Content {
|
for _, sliceItem := range valueNode.Content {
|
||||||
iv, _ := strconv.ParseInt(sliceItem.Value, 10, 64)
|
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))
|
field.Set(reflect.ValueOf(items))
|
||||||
}
|
}
|
||||||
@@ -275,12 +320,16 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err
|
|||||||
break
|
break
|
||||||
case reflect.TypeOf([]low.NodeReference[bool]{}):
|
case reflect.TypeOf([]low.NodeReference[bool]{}):
|
||||||
if valueNode != nil {
|
if valueNode != nil {
|
||||||
if IsNodeArray(valueNode) {
|
if utils.IsNodeArray(valueNode) {
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
var items []low.NodeReference[bool]
|
var items []low.NodeReference[bool]
|
||||||
for _, sliceItem := range valueNode.Content {
|
for _, sliceItem := range valueNode.Content {
|
||||||
bv, _ := strconv.ParseBool(sliceItem.Value)
|
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))
|
field.Set(reflect.ValueOf(items))
|
||||||
}
|
}
|
||||||
@@ -288,8 +337,18 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
m := field.Type()
|
// we want to ignore everything else.
|
||||||
return fmt.Errorf("unknown type, cannot parse: %v", m)
|
break
|
||||||
}
|
}
|
||||||
return nil
|
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()
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package utils
|
package datamodel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
@@ -106,7 +106,7 @@ there:
|
|||||||
hd := hotdog{}
|
hd := hotdog{}
|
||||||
cErr := BuildModel(&rootNode, &hd)
|
cErr := BuildModel(&rootNode, &hd)
|
||||||
assert.Equal(t, 200, hd.Fat.Value)
|
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, true, hd.Grilled.Value)
|
||||||
assert.Equal(t, "yummy", hd.Name.Value)
|
assert.Equal(t, "yummy", hd.Name.Value)
|
||||||
assert.Equal(t, float32(200.45), hd.Ketchup.Value)
|
assert.Equal(t, float32(200.45), hd.Ketchup.Value)
|
||||||
@@ -119,7 +119,7 @@ there:
|
|||||||
assert.Len(t, hd.MaxTempAlt, 5)
|
assert.Len(t, hd.MaxTempAlt, 5)
|
||||||
assert.Equal(t, int64(7392837462032342), hd.MaxTempHigh.Value)
|
assert.Equal(t, int64(7392837462032342), hd.MaxTempHigh.Value)
|
||||||
assert.Equal(t, 2, hd.Temps[1].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.UnknownElements.Value, 2)
|
||||||
assert.Len(t, hd.LotsOfUnknowns, 3)
|
assert.Len(t, hd.LotsOfUnknowns, 3)
|
||||||
assert.Len(t, hd.Where, 2)
|
assert.Len(t, hd.Where, 2)
|
||||||
@@ -129,24 +129,6 @@ there:
|
|||||||
assert.NoError(t, cErr)
|
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) {
|
func TestBuildModel_UseCopyNotRef(t *testing.T) {
|
||||||
|
|
||||||
yml := `cake: -99999`
|
yml := `cake: -99999`
|
||||||
@@ -2,7 +2,9 @@ package openapi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel"
|
"github.com/pb33f/libopenapi/datamodel"
|
||||||
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
v3 "github.com/pb33f/libopenapi/datamodel/low/3.0"
|
v3 "github.com/pb33f/libopenapi/datamodel/low/3.0"
|
||||||
|
"github.com/pb33f/libopenapi/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CreateDocument(spec []byte) (*v3.Document, error) {
|
func CreateDocument(spec []byte) (*v3.Document, error) {
|
||||||
@@ -13,7 +15,64 @@ func CreateDocument(spec []byte) (*v3.Document, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
doc := &v3.Document{}
|
doc := v3.Document{Version: low.NodeReference[string]{Value: info.Version, ValueNode: info.RootNode}}
|
||||||
doc.Build(info.RootNode.Content[0])
|
|
||||||
return doc, nil
|
// 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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ func TestCreateDocument_NoData(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateDocument(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)
|
assert.NoError(t, aErr)
|
||||||
|
|
||||||
doc, err := CreateDocument(data)
|
doc, err := CreateDocument(data)
|
||||||
|
|||||||
@@ -6,8 +6,11 @@ info:
|
|||||||
termsOfService: https://quobix.com
|
termsOfService: https://quobix.com
|
||||||
contact:
|
contact:
|
||||||
name: quobix
|
name: quobix
|
||||||
|
email: test@quobix.com
|
||||||
|
url: https://quobix.com
|
||||||
license:
|
license:
|
||||||
name: Quobix
|
name: Quobix
|
||||||
|
url: https://quobix.com/made-up
|
||||||
version: "1.2"
|
version: "1.2"
|
||||||
tags:
|
tags:
|
||||||
- name: "Burgers"
|
- name: "Burgers"
|
||||||
@@ -21,7 +24,22 @@ tags:
|
|||||||
description: "Find out more information about our products)"
|
description: "Find out more information about our products)"
|
||||||
url: "https://quobix.com/"
|
url: "https://quobix.com/"
|
||||||
servers:
|
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:
|
paths:
|
||||||
/burgers:
|
/burgers:
|
||||||
post:
|
post:
|
||||||
|
|||||||
@@ -239,6 +239,29 @@ func FindKeyNode(key string, nodes []*yaml.Node) (keyNode *yaml.Node, valueNode
|
|||||||
return nil, nil
|
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 ObjectLabel = "object"
|
||||||
var IntegerLabel = "integer"
|
var IntegerLabel = "integer"
|
||||||
var NumberLabel = "number"
|
var NumberLabel = "number"
|
||||||
|
|||||||
Reference in New Issue
Block a user