mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-09 20:47:44 +00:00
Working in generics now to reduce code.
generics are a little funky still. sigh.
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
package v3
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"gopkg.in/yaml.v3"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type Callback struct {
|
||||
Node *yaml.Node
|
||||
Expression map[string]Path
|
||||
Extensions map[string]low.ObjectReference
|
||||
Node *yaml.Node
|
||||
Expression map[string]PathItem
|
||||
Extensions map[string]low.ObjectReference
|
||||
}
|
||||
|
||||
@@ -1,15 +1,31 @@
|
||||
package v3
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"gopkg.in/yaml.v3"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
const (
|
||||
EncodingLabel = "encoding"
|
||||
)
|
||||
|
||||
type Encoding struct {
|
||||
Node *yaml.Node
|
||||
ContentType low.NodeReference[string]
|
||||
Headers map[string]Parameter
|
||||
Style low.NodeReference[string]
|
||||
Explode low.NodeReference[bool]
|
||||
AllowReserved low.NodeReference[bool]
|
||||
ContentType low.NodeReference[string]
|
||||
Headers map[low.KeyReference[string]]map[low.KeyReference[string]]low.ValueReference[*Header]
|
||||
Style low.NodeReference[string]
|
||||
Explode low.NodeReference[bool]
|
||||
AllowReserved low.NodeReference[bool]
|
||||
}
|
||||
|
||||
func (en Encoding) Build(root *yaml.Node) error {
|
||||
|
||||
headers, err := ExtractMap[*Header](HeadersLabel, root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if headers != nil {
|
||||
en.Headers = headers
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,15 +1,29 @@
|
||||
package v3
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"gopkg.in/yaml.v3"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
const (
|
||||
ExamplesLabel = "examples"
|
||||
ExampleLabel = "example"
|
||||
)
|
||||
|
||||
type Example struct {
|
||||
Node *yaml.Node
|
||||
Summary low.NodeReference[string]
|
||||
Description low.NodeReference[string]
|
||||
Value low.ObjectReference
|
||||
ExternalValue low.NodeReference[string]
|
||||
Extensions map[string]low.ObjectReference
|
||||
Summary low.NodeReference[string]
|
||||
Description low.NodeReference[string]
|
||||
Value low.NodeReference[any]
|
||||
ExternalValue low.NodeReference[string]
|
||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
||||
}
|
||||
|
||||
func (ex Example) Build(root *yaml.Node) error {
|
||||
// extract extensions
|
||||
extensionMap, err := ExtractExtensions(root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ex.Extensions = extensionMap
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2,10 +2,21 @@ package v3
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type ExternalDoc struct {
|
||||
Description low.NodeReference[string]
|
||||
URL low.NodeReference[string]
|
||||
Extensions map[string]low.ObjectReference
|
||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
||||
}
|
||||
|
||||
func (ex *ExternalDoc) Build(root *yaml.Node) error {
|
||||
// extract extensions
|
||||
extensionMap, err := ExtractExtensions(root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ex.Extensions = extensionMap
|
||||
return nil
|
||||
}
|
||||
|
||||
123
datamodel/low/3.0/extraction_functions.go
Normal file
123
datamodel/low/3.0/extraction_functions.go
Normal file
@@ -0,0 +1,123 @@
|
||||
package v3
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/utils"
|
||||
"gopkg.in/yaml.v3"
|
||||
"strconv"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func ExtractSchema(root *yaml.Node) (*low.NodeReference[*Schema], error) {
|
||||
_, schLabel, schNode := utils.FindKeyNodeFull(SchemaLabel, root.Content)
|
||||
if schNode != nil {
|
||||
var schema Schema
|
||||
err := BuildModel(schNode, &schema)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = schema.Build(schNode, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &low.NodeReference[*Schema]{Value: &schema, KeyNode: schLabel, ValueNode: schNode}, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var mapLock sync.Mutex
|
||||
|
||||
func ExtractMap[PT low.Buildable[N], N any](label string, root *yaml.Node) (map[low.KeyReference[string]]map[low.KeyReference[string]]low.ValueReference[PT], error) {
|
||||
_, labelNode, valueNode := utils.FindKeyNodeFull(label, root.Content)
|
||||
if valueNode != nil {
|
||||
var currentLabelNode *yaml.Node
|
||||
valueMap := make(map[low.KeyReference[string]]low.ValueReference[PT])
|
||||
for i, en := range valueNode.Content {
|
||||
if i%2 == 0 {
|
||||
currentLabelNode = en
|
||||
continue
|
||||
}
|
||||
var n PT = new(N)
|
||||
err := BuildModel(valueNode, n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
berr := n.Build(valueNode)
|
||||
if berr != nil {
|
||||
return nil, berr
|
||||
}
|
||||
valueMap[low.KeyReference[string]{
|
||||
Value: currentLabelNode.Value,
|
||||
KeyNode: currentLabelNode,
|
||||
}] = low.ValueReference[PT]{
|
||||
Value: n,
|
||||
ValueNode: en,
|
||||
}
|
||||
}
|
||||
|
||||
resMap := make(map[low.KeyReference[string]]map[low.KeyReference[string]]low.ValueReference[PT])
|
||||
resMap[low.KeyReference[string]{
|
||||
Value: labelNode.Value,
|
||||
KeyNode: labelNode,
|
||||
}] = valueMap
|
||||
return resMap, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func ExtractExtensions(root *yaml.Node) (map[low.KeyReference[string]]low.ValueReference[any], error) {
|
||||
extensions := utils.FindExtensionNodes(root.Content)
|
||||
extensionMap := make(map[low.KeyReference[string]]low.ValueReference[any])
|
||||
for _, ext := range extensions {
|
||||
if utils.IsNodeMap(ext.Value) {
|
||||
var v interface{}
|
||||
err := ext.Value.Decode(&v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
extensionMap[low.KeyReference[string]{
|
||||
Value: ext.Key.Value,
|
||||
KeyNode: ext.Key,
|
||||
}] = low.ValueReference[any]{Value: v, ValueNode: ext.Value}
|
||||
}
|
||||
if utils.IsNodeStringValue(ext.Value) {
|
||||
extensionMap[low.KeyReference[string]{
|
||||
Value: ext.Key.Value,
|
||||
KeyNode: ext.Key,
|
||||
}] = low.ValueReference[any]{Value: ext.Value.Value, ValueNode: ext.Value}
|
||||
}
|
||||
if utils.IsNodeFloatValue(ext.Value) {
|
||||
fv, _ := strconv.ParseFloat(ext.Value.Value, 64)
|
||||
extensionMap[low.KeyReference[string]{
|
||||
Value: ext.Key.Value,
|
||||
KeyNode: ext.Key,
|
||||
}] = low.ValueReference[any]{Value: fv, ValueNode: ext.Value}
|
||||
}
|
||||
if utils.IsNodeIntValue(ext.Value) {
|
||||
iv, _ := strconv.ParseInt(ext.Value.Value, 10, 64)
|
||||
extensionMap[low.KeyReference[string]{
|
||||
Value: ext.Key.Value,
|
||||
KeyNode: ext.Key,
|
||||
}] = low.ValueReference[any]{Value: iv, ValueNode: ext.Value}
|
||||
}
|
||||
if utils.IsNodeBoolValue(ext.Value) {
|
||||
bv, _ := strconv.ParseBool(ext.Value.Value)
|
||||
extensionMap[low.KeyReference[string]{
|
||||
Value: ext.Key.Value,
|
||||
KeyNode: ext.Key,
|
||||
}] = low.ValueReference[any]{Value: bv, ValueNode: ext.Value}
|
||||
}
|
||||
if utils.IsNodeArray(ext.Value) {
|
||||
var v []interface{}
|
||||
err := ext.Value.Decode(&v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
extensionMap[low.KeyReference[string]{
|
||||
Value: ext.Key.Value,
|
||||
KeyNode: ext.Key,
|
||||
}] = low.ValueReference[any]{Value: v, ValueNode: ext.Value}
|
||||
}
|
||||
}
|
||||
return extensionMap, nil
|
||||
}
|
||||
61
datamodel/low/3.0/header.go
Normal file
61
datamodel/low/3.0/header.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package v3
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
const (
|
||||
HeadersLabel = "headers"
|
||||
)
|
||||
|
||||
type Header struct {
|
||||
Description low.NodeReference[string]
|
||||
Required low.NodeReference[bool]
|
||||
Deprecated low.NodeReference[bool]
|
||||
AllowEmptyValue low.NodeReference[bool]
|
||||
Style low.NodeReference[string]
|
||||
Explode low.NodeReference[bool]
|
||||
AllowReserved low.NodeReference[bool]
|
||||
Schema low.NodeReference[*Schema]
|
||||
Example low.NodeReference[any]
|
||||
Examples map[low.KeyReference[string]]map[low.KeyReference[string]]low.ValueReference[*Example]
|
||||
Content map[low.KeyReference[string]]map[low.KeyReference[string]]low.ValueReference[*MediaType]
|
||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
||||
}
|
||||
|
||||
func (h *Header) Build(root *yaml.Node) error {
|
||||
// extract extensions
|
||||
extensionMap, err := ExtractExtensions(root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h.Extensions = extensionMap
|
||||
|
||||
// handle examples if set.
|
||||
exps, eErr := ExtractMap[*Example](ExamplesLabel, root)
|
||||
if eErr != nil {
|
||||
return eErr
|
||||
}
|
||||
if exps != nil {
|
||||
h.Examples = exps
|
||||
}
|
||||
|
||||
// handle schema
|
||||
sch, sErr := ExtractSchema(root)
|
||||
if sErr != nil {
|
||||
return nil
|
||||
}
|
||||
if sch != nil {
|
||||
h.Schema = *sch
|
||||
}
|
||||
|
||||
// handle content, if set.
|
||||
con, cErr := ExtractMap[*MediaType](ContentLabel, root)
|
||||
if cErr != nil {
|
||||
return cErr
|
||||
}
|
||||
h.Content = con
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,14 +1,59 @@
|
||||
package v3
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"gopkg.in/yaml.v3"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/utils"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type MediaType struct {
|
||||
Node *yaml.Node
|
||||
Schema Schema
|
||||
Example low.ObjectReference
|
||||
Examples map[string]Example
|
||||
Encoding map[string]Encoding
|
||||
Schema low.NodeReference[*Schema]
|
||||
Example low.NodeReference[any]
|
||||
Examples map[low.KeyReference[string]]map[low.KeyReference[string]]low.ValueReference[*Example]
|
||||
Encoding map[low.KeyReference[string]]map[low.KeyReference[string]]low.ValueReference[*Encoding]
|
||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
||||
}
|
||||
|
||||
func (mt *MediaType) Build(root *yaml.Node) error {
|
||||
|
||||
// extract extensions
|
||||
extensionMap, err := ExtractExtensions(root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mt.Extensions = extensionMap
|
||||
|
||||
// handle example if set.
|
||||
_, expLabel, expNode := utils.FindKeyNodeFull(ExampleLabel, root.Content)
|
||||
if expNode != nil {
|
||||
mt.Example = low.NodeReference[any]{Value: expNode.Value, KeyNode: expLabel, ValueNode: expNode}
|
||||
}
|
||||
|
||||
// handle schema
|
||||
sch, sErr := ExtractSchema(root)
|
||||
if sErr != nil {
|
||||
return nil
|
||||
}
|
||||
if sch != nil {
|
||||
mt.Schema = *sch
|
||||
}
|
||||
|
||||
// handle examples if set.
|
||||
exps, eErr := ExtractMap[*Example](ExamplesLabel, root)
|
||||
if eErr != nil {
|
||||
return eErr
|
||||
}
|
||||
if exps != nil {
|
||||
mt.Examples = exps
|
||||
}
|
||||
|
||||
// handle encoding
|
||||
encs, encErr := ExtractMap[*Encoding](EncodingLabel, root)
|
||||
if encErr != nil {
|
||||
return err
|
||||
}
|
||||
if encs != nil {
|
||||
mt.Encoding = encs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -377,60 +377,3 @@ func BuildModelAsync(n *yaml.Node, model interface{}, lwg *sync.WaitGroup, error
|
||||
}
|
||||
lwg.Done()
|
||||
}
|
||||
|
||||
func ExtractExtensions(root *yaml.Node) (map[low.NodeReference[string]]low.NodeReference[any], error) {
|
||||
extensions := utils.FindExtensionNodes(root.Content)
|
||||
extensionMap := make(map[low.NodeReference[string]]low.NodeReference[any])
|
||||
for _, ext := range extensions {
|
||||
if utils.IsNodeMap(ext.Value) {
|
||||
var v interface{}
|
||||
err := ext.Value.Decode(&v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
extensionMap[low.NodeReference[string]{
|
||||
Value: ext.Key.Value,
|
||||
KeyNode: ext.Key,
|
||||
}] = low.NodeReference[any]{Value: v, KeyNode: ext.Key}
|
||||
}
|
||||
if utils.IsNodeStringValue(ext.Value) {
|
||||
extensionMap[low.NodeReference[string]{
|
||||
Value: ext.Key.Value,
|
||||
KeyNode: ext.Key,
|
||||
}] = low.NodeReference[any]{Value: ext.Value.Value, ValueNode: ext.Value}
|
||||
}
|
||||
if utils.IsNodeFloatValue(ext.Value) {
|
||||
fv, _ := strconv.ParseFloat(ext.Value.Value, 64)
|
||||
extensionMap[low.NodeReference[string]{
|
||||
Value: ext.Key.Value,
|
||||
KeyNode: ext.Key,
|
||||
}] = low.NodeReference[any]{Value: fv, ValueNode: ext.Value}
|
||||
}
|
||||
if utils.IsNodeIntValue(ext.Value) {
|
||||
iv, _ := strconv.ParseInt(ext.Value.Value, 10, 64)
|
||||
extensionMap[low.NodeReference[string]{
|
||||
Value: ext.Key.Value,
|
||||
KeyNode: ext.Key,
|
||||
}] = low.NodeReference[any]{Value: iv, ValueNode: ext.Value}
|
||||
}
|
||||
if utils.IsNodeBoolValue(ext.Value) {
|
||||
bv, _ := strconv.ParseBool(ext.Value.Value)
|
||||
extensionMap[low.NodeReference[string]{
|
||||
Value: ext.Key.Value,
|
||||
KeyNode: ext.Key,
|
||||
}] = low.NodeReference[any]{Value: bv, ValueNode: ext.Value}
|
||||
}
|
||||
if utils.IsNodeArray(ext.Value) {
|
||||
var v []interface{}
|
||||
err := ext.Value.Decode(&v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
extensionMap[low.NodeReference[string]{
|
||||
Value: ext.Key.Value,
|
||||
KeyNode: ext.Key,
|
||||
}] = low.NodeReference[any]{Value: v, ValueNode: ext.Value}
|
||||
}
|
||||
}
|
||||
return extensionMap, nil
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package v3
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/index"
|
||||
"github.com/pb33f/libopenapi/utils"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
@@ -15,19 +14,19 @@ type Operation struct {
|
||||
Tags []low.NodeReference[string]
|
||||
Summary low.NodeReference[string]
|
||||
Description low.NodeReference[string]
|
||||
ExternalDocs *low.NodeReference[*ExternalDoc]
|
||||
ExternalDocs low.NodeReference[*ExternalDoc]
|
||||
OperationId low.NodeReference[string]
|
||||
Parameters []low.NodeReference[*Parameter]
|
||||
RequestBody *low.NodeReference[*RequestBody]
|
||||
Responses *low.NodeReference[*Responses]
|
||||
Callbacks map[low.NodeReference[string]]low.NodeReference[*Callback]
|
||||
Deprecated *low.NodeReference[bool]
|
||||
RequestBody low.NodeReference[*RequestBody]
|
||||
Responses low.NodeReference[*Responses]
|
||||
Callbacks map[low.KeyReference[string]]low.ValueReference[*Callback]
|
||||
Deprecated low.NodeReference[bool]
|
||||
Security []low.NodeReference[*SecurityRequirement]
|
||||
Servers []low.NodeReference[*Server]
|
||||
Extensions map[low.NodeReference[string]]low.NodeReference[any]
|
||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
||||
}
|
||||
|
||||
func (o *Operation) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
||||
func (o *Operation) Build(root *yaml.Node) error {
|
||||
|
||||
extensionMap, err := ExtractExtensions(root)
|
||||
if err != nil {
|
||||
@@ -43,7 +42,7 @@ func (o *Operation) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.ExternalDocs = &low.NodeReference[*ExternalDoc]{
|
||||
o.ExternalDocs = low.NodeReference[*ExternalDoc]{
|
||||
Value: &externalDoc,
|
||||
KeyNode: ln,
|
||||
ValueNode: exDocs,
|
||||
@@ -61,7 +60,7 @@ func (o *Operation) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = param.Build(pN, idx)
|
||||
err = param.Build(pN)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@ package v3
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/index"
|
||||
"github.com/pb33f/libopenapi/utils"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
const (
|
||||
SchemaLabel = "schema"
|
||||
SchemaLabel = "schema"
|
||||
ContentLabel = "content"
|
||||
)
|
||||
|
||||
type Parameter struct {
|
||||
@@ -23,11 +23,23 @@ type Parameter struct {
|
||||
AllowReserved low.NodeReference[bool]
|
||||
Schema low.NodeReference[*Schema]
|
||||
Example low.NodeReference[any]
|
||||
Examples map[low.NodeReference[string]]low.NodeReference[*Example]
|
||||
Extensions map[low.NodeReference[string]]low.NodeReference[any]
|
||||
Examples map[low.KeyReference[string]]map[low.KeyReference[string]]low.ValueReference[*Example]
|
||||
Content map[low.KeyReference[string]]map[low.KeyReference[string]]low.ValueReference[*MediaType]
|
||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
||||
}
|
||||
|
||||
func (p *Parameter) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
||||
func (p *Parameter) GetContent(cType string) *low.ValueReference[*MediaType] {
|
||||
for _, c := range p.Content {
|
||||
for n, o := range c {
|
||||
if n.Value == cType {
|
||||
return &o
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Parameter) Build(root *yaml.Node) error {
|
||||
|
||||
// extract extensions
|
||||
extensionMap, err := ExtractExtensions(root)
|
||||
@@ -36,27 +48,24 @@ func (p *Parameter) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
||||
}
|
||||
p.Extensions = extensionMap
|
||||
|
||||
// handle schema
|
||||
_, schLabel, schNode := utils.FindKeyNodeFull(SchemaLabel, root.Content)
|
||||
if schNode != nil {
|
||||
// deal with schema flat props
|
||||
var schema Schema
|
||||
err = BuildModel(schNode, &schema)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// now comes the part where things may get hairy, schemas are recursive.
|
||||
// which means we could be here forever if our resolver has some unknown bug in it.
|
||||
// in order to prevent this from happening, we will add a counter that tracks the depth
|
||||
// and will hard stop once we reach 50 levels. That's too deep for any data structure IMHO.
|
||||
err = schema.Build(schNode, idx, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.Schema = low.NodeReference[*Schema]{Value: &schema, KeyNode: schLabel, ValueNode: schNode}
|
||||
// handle example if set.
|
||||
_, expLabel, expNode := utils.FindKeyNodeFull(ExampleLabel, root.Content)
|
||||
if expNode != nil {
|
||||
p.Example = low.NodeReference[any]{Value: expNode.Value, KeyNode: expLabel, ValueNode: expNode}
|
||||
}
|
||||
|
||||
// handle schema
|
||||
sch, sErr := ExtractSchema(root)
|
||||
if sErr != nil {
|
||||
return sErr
|
||||
}
|
||||
p.Schema = *sch
|
||||
|
||||
// handle content, if set.
|
||||
con, cErr := ExtractMap[*MediaType](ContentLabel, root)
|
||||
if cErr != nil {
|
||||
return cErr
|
||||
}
|
||||
p.Content = con
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package v3
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/index"
|
||||
"gopkg.in/yaml.v3"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -21,19 +20,20 @@ const (
|
||||
)
|
||||
|
||||
type Paths struct {
|
||||
Paths map[low.NodeReference[string]]low.NodeReference[*Path]
|
||||
Extensions map[low.NodeReference[string]]low.NodeReference[any]
|
||||
PathItems map[low.KeyReference[string]]low.ValueReference[*PathItem]
|
||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
||||
}
|
||||
|
||||
func (p *Paths) GetPathMap() map[string]*Path {
|
||||
pMap := make(map[string]*Path)
|
||||
for i, pv := range p.Paths {
|
||||
pMap[i.Value] = pv.Value
|
||||
func (p *Paths) GetPath(path string) *low.ValueReference[*PathItem] {
|
||||
for k, p := range p.PathItems {
|
||||
if k.Value == path {
|
||||
return &p
|
||||
}
|
||||
}
|
||||
return pMap
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Paths) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
||||
func (p *Paths) Build(root *yaml.Node) error {
|
||||
|
||||
// extract extensions
|
||||
extensionMap, err := ExtractExtensions(root)
|
||||
@@ -44,7 +44,7 @@ func (p *Paths) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
||||
skip := false
|
||||
var currentNode *yaml.Node
|
||||
|
||||
pathsMap := make(map[low.NodeReference[string]]low.NodeReference[*Path])
|
||||
pathsMap := make(map[low.KeyReference[string]]low.ValueReference[*PathItem])
|
||||
|
||||
for i, pathNode := range root.Content {
|
||||
if strings.HasPrefix(strings.ToLower(pathNode.Value), "x-") {
|
||||
@@ -59,32 +59,32 @@ func (p *Paths) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
||||
currentNode = pathNode
|
||||
continue
|
||||
}
|
||||
var path = Path{}
|
||||
var path = PathItem{}
|
||||
err = BuildModel(pathNode, &path)
|
||||
if err != nil {
|
||||
|
||||
}
|
||||
err = path.Build(pathNode, idx)
|
||||
err = path.Build(pathNode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add bulk here
|
||||
pathsMap[low.NodeReference[string]{
|
||||
pathsMap[low.KeyReference[string]{
|
||||
Value: currentNode.Value,
|
||||
KeyNode: currentNode,
|
||||
}] = low.NodeReference[*Path]{
|
||||
}] = low.ValueReference[*PathItem]{
|
||||
Value: &path,
|
||||
ValueNode: pathNode,
|
||||
}
|
||||
}
|
||||
|
||||
p.Paths = pathsMap
|
||||
p.PathItems = pathsMap
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
type Path struct {
|
||||
type PathItem struct {
|
||||
Description low.NodeReference[string]
|
||||
Summary low.NodeReference[string]
|
||||
Get *low.NodeReference[*Operation]
|
||||
@@ -97,10 +97,10 @@ type Path struct {
|
||||
Trace *low.NodeReference[*Operation]
|
||||
Servers []*low.NodeReference[*Server]
|
||||
Parameters []*low.NodeReference[*Parameter]
|
||||
Extensions map[low.NodeReference[string]]low.NodeReference[any]
|
||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
||||
}
|
||||
|
||||
func (p *Path) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
||||
func (p *PathItem) Build(root *yaml.Node) error {
|
||||
extensionMap, err := ExtractExtensions(root)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -171,7 +171,7 @@ func (p *Path) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
||||
var buildOpFunc = func(op low.NodeReference[*Operation], ch chan<- bool, errCh chan<- error) {
|
||||
|
||||
// build out the operation.
|
||||
er := op.Value.Build(op.ValueNode, idx)
|
||||
er := op.Value.Build(op.ValueNode)
|
||||
if err != nil {
|
||||
errCh <- er
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package v3
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/index"
|
||||
"github.com/pb33f/libopenapi/utils"
|
||||
"gopkg.in/yaml.v3"
|
||||
"strconv"
|
||||
@@ -12,7 +11,7 @@ import (
|
||||
const (
|
||||
PropertiesLabel = "properties"
|
||||
AdditionalPropertiesLabel = "additionalProperties"
|
||||
ExampleLabel = "example"
|
||||
XMLLabel = "xml"
|
||||
ItemsLabel = "items"
|
||||
AllOfLabel = "allOf"
|
||||
AnyOfLabel = "anyOf"
|
||||
@@ -44,7 +43,7 @@ type Schema struct {
|
||||
AnyOf []low.NodeReference[*Schema]
|
||||
Not []low.NodeReference[*Schema]
|
||||
Items []low.NodeReference[*Schema]
|
||||
Properties map[low.NodeReference[string]]*low.NodeReference[*Schema]
|
||||
Properties map[low.KeyReference[string]]*low.ValueReference[*Schema]
|
||||
AdditionalProperties low.NodeReference[any]
|
||||
Description low.NodeReference[string]
|
||||
Default low.NodeReference[any]
|
||||
@@ -52,14 +51,14 @@ type Schema struct {
|
||||
Discriminator low.NodeReference[*Discriminator]
|
||||
ReadOnly low.NodeReference[bool]
|
||||
WriteOnly low.NodeReference[bool]
|
||||
XML *low.NodeReference[*XML]
|
||||
ExternalDocs *low.NodeReference[*ExternalDoc]
|
||||
XML low.NodeReference[*XML]
|
||||
ExternalDocs low.NodeReference[*ExternalDoc]
|
||||
Example low.NodeReference[any]
|
||||
Deprecated low.NodeReference[bool]
|
||||
Extensions map[low.NodeReference[string]]low.NodeReference[any]
|
||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
||||
}
|
||||
|
||||
func (s *Schema) FindProperty(name string) *low.NodeReference[*Schema] {
|
||||
func (s *Schema) FindProperty(name string) *low.ValueReference[*Schema] {
|
||||
for k, v := range s.Properties {
|
||||
if k.Value == name {
|
||||
return v
|
||||
@@ -68,17 +67,16 @@ func (s *Schema) FindProperty(name string) *low.NodeReference[*Schema] {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Schema) Build(root *yaml.Node, idx *index.SpecIndex, level int) error {
|
||||
func (s *Schema) Build(root *yaml.Node, level int) error {
|
||||
level++
|
||||
if level > 50 {
|
||||
return nil // we're done, son! too fricken deep.
|
||||
}
|
||||
|
||||
extensionMap, err := ExtractExtensions(root)
|
||||
err := s.extractExtensions(root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.Extensions = extensionMap
|
||||
|
||||
// handle example if set.
|
||||
_, expLabel, expNode := utils.FindKeyNodeFull(ExampleLabel, root.Content)
|
||||
@@ -90,7 +88,10 @@ func (s *Schema) Build(root *yaml.Node, idx *index.SpecIndex, level int) error {
|
||||
if addPNode != nil {
|
||||
if utils.IsNodeMap(addPNode) {
|
||||
var props map[string]interface{}
|
||||
addPNode.Decode(&props)
|
||||
err = addPNode.Decode(&props)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.AdditionalProperties = low.NodeReference[any]{Value: props, KeyNode: addPLabel, ValueNode: addPNode}
|
||||
}
|
||||
|
||||
@@ -111,11 +112,43 @@ func (s *Schema) Build(root *yaml.Node, idx *index.SpecIndex, level int) error {
|
||||
s.Discriminator = low.NodeReference[*Discriminator]{Value: &discriminator, KeyNode: discLabel, ValueNode: discNode}
|
||||
}
|
||||
|
||||
// handle externalDocs if set.
|
||||
_, extDocLabel, extDocNode := utils.FindKeyNodeFull(ExternalDocsLabel, root.Content)
|
||||
if extDocNode != nil {
|
||||
var exDoc ExternalDoc
|
||||
err = BuildModel(extDocNode, &exDoc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = exDoc.Build(extDocNode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.ExternalDocs = low.NodeReference[*ExternalDoc]{Value: &exDoc, KeyNode: extDocLabel, ValueNode: extDocNode}
|
||||
}
|
||||
|
||||
// handle xml if set.
|
||||
_, xmlLabel, xmlNode := utils.FindKeyNodeFull(XMLLabel, root.Content)
|
||||
if xmlNode != nil {
|
||||
var xml XML
|
||||
err = BuildModel(xmlNode, &xml)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// extract extensions if set.
|
||||
err = xml.Build(xmlNode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.XML = low.NodeReference[*XML]{Value: &xml, KeyNode: xmlLabel, ValueNode: xmlNode}
|
||||
}
|
||||
|
||||
// handle properties
|
||||
_, propLabel, propsNode := utils.FindKeyNodeFull(PropertiesLabel, root.Content)
|
||||
if propsNode != nil {
|
||||
propertyMap := make(map[low.NodeReference[string]]*low.NodeReference[*Schema])
|
||||
propertyMap := make(map[low.KeyReference[string]]*low.ValueReference[*Schema])
|
||||
var currentProp *yaml.Node
|
||||
var wg sync.WaitGroup
|
||||
for i, prop := range propsNode.Content {
|
||||
if i%2 == 0 {
|
||||
currentProp = prop
|
||||
@@ -127,17 +160,15 @@ func (s *Schema) Build(root *yaml.Node, idx *index.SpecIndex, level int) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = property.Build(prop, idx, level)
|
||||
err = property.Build(prop, level)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
propertyMap[low.NodeReference[string]{
|
||||
Value: currentProp.Value,
|
||||
KeyNode: propLabel,
|
||||
ValueNode: propsNode,
|
||||
}] = &low.NodeReference[*Schema]{
|
||||
propertyMap[low.KeyReference[string]{
|
||||
Value: currentProp.Value,
|
||||
KeyNode: propLabel,
|
||||
}] = &low.ValueReference[*Schema]{
|
||||
Value: &property,
|
||||
KeyNode: currentProp,
|
||||
ValueNode: prop,
|
||||
}
|
||||
}
|
||||
@@ -145,16 +176,15 @@ func (s *Schema) Build(root *yaml.Node, idx *index.SpecIndex, level int) error {
|
||||
|
||||
// extract all sub-schemas
|
||||
var errors []error
|
||||
var wg sync.WaitGroup
|
||||
|
||||
var allOf, anyOf, oneOf, not, items []low.NodeReference[*Schema]
|
||||
|
||||
// make this async at some point to speed things up.
|
||||
buildSchema(&allOf, AllOfLabel, idx, root, level, &errors, &wg)
|
||||
buildSchema(&anyOf, AnyOfLabel, idx, root, level, &errors, &wg)
|
||||
buildSchema(&oneOf, OneOfLabel, idx, root, level, &errors, &wg)
|
||||
buildSchema(¬, NotLabel, idx, root, level, &errors, &wg)
|
||||
buildSchema(&items, ItemsLabel, idx, root, level, &errors, &wg)
|
||||
buildSchema(&allOf, AllOfLabel, root, level, &errors, &wg)
|
||||
buildSchema(&anyOf, AnyOfLabel, root, level, &errors, &wg)
|
||||
buildSchema(&oneOf, OneOfLabel, root, level, &errors, &wg)
|
||||
buildSchema(¬, NotLabel, root, level, &errors, &wg)
|
||||
buildSchema(&items, ItemsLabel, root, level, &errors, &wg)
|
||||
//wg.Wait()
|
||||
|
||||
if len(errors) > 0 {
|
||||
@@ -182,7 +212,16 @@ func (s *Schema) Build(root *yaml.Node, idx *index.SpecIndex, level int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildSchema(schemas *[]low.NodeReference[*Schema], attribute string, idx *index.SpecIndex, rootNode *yaml.Node, level int, errors *[]error, wg *sync.WaitGroup) {
|
||||
func (s *Schema) extractExtensions(root *yaml.Node) error {
|
||||
extensionMap, err := ExtractExtensions(root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.Extensions = extensionMap
|
||||
return err
|
||||
}
|
||||
|
||||
func buildSchema(schemas *[]low.NodeReference[*Schema], attribute string, rootNode *yaml.Node, level int, errors *[]error, wg *sync.WaitGroup) {
|
||||
_, labelNode, valueNode := utils.FindKeyNodeFull(attribute, rootNode.Content)
|
||||
//wg.Add(1)
|
||||
if valueNode != nil {
|
||||
@@ -194,7 +233,7 @@ func buildSchema(schemas *[]low.NodeReference[*Schema], attribute string, idx *i
|
||||
*errors = append(*errors, err)
|
||||
return nil
|
||||
}
|
||||
err = schema.Build(vn, idx, level)
|
||||
err = schema.Build(vn, level)
|
||||
if err != nil {
|
||||
*errors = append(*errors, err)
|
||||
return nil
|
||||
|
||||
@@ -83,15 +83,25 @@ properties:
|
||||
somethingB:
|
||||
type: object
|
||||
description: an object
|
||||
externalDocs:
|
||||
description: the best docs
|
||||
url: https://pb33f.io
|
||||
properties:
|
||||
somethingBProp:
|
||||
type: string
|
||||
description: something b subprop
|
||||
example: picnics are nice.
|
||||
xml:
|
||||
name: an xml thing
|
||||
namespace: an xml namespace
|
||||
prefix: a prefix
|
||||
attribute: true
|
||||
wrapped: false
|
||||
x-pizza: love
|
||||
additionalProperties:
|
||||
why: yes
|
||||
thatIs: true
|
||||
additionalProperties: true`
|
||||
additionalProperties: true `
|
||||
|
||||
var rootNode yaml.Node
|
||||
mErr := yaml.Unmarshal([]byte(testSpec), &rootNode)
|
||||
@@ -101,13 +111,26 @@ additionalProperties: true`
|
||||
mbErr := BuildModel(&rootNode, &sch)
|
||||
assert.NoError(t, mbErr)
|
||||
|
||||
schErr := sch.Build(rootNode.Content[0], nil, 0)
|
||||
schErr := sch.Build(rootNode.Content[0], 0)
|
||||
assert.NoError(t, schErr)
|
||||
assert.Equal(t, "something object", sch.Description.Value)
|
||||
assert.True(t, sch.AdditionalProperties.Value.(bool))
|
||||
|
||||
assert.Len(t, sch.Properties, 2)
|
||||
v := sch.FindProperty("somethingB")
|
||||
|
||||
assert.Equal(t, "https://pb33f.io", v.Value.ExternalDocs.Value.URL.Value)
|
||||
assert.Equal(t, "the best docs", v.Value.ExternalDocs.Value.Description.Value)
|
||||
|
||||
j := v.Value.FindProperty("somethingBProp")
|
||||
assert.NotNil(t, j.Value)
|
||||
assert.NotNil(t, j.Value.XML.Value)
|
||||
assert.Equal(t, "an xml thing", j.Value.XML.Value.Name.Value)
|
||||
assert.Equal(t, "an xml namespace", j.Value.XML.Value.Namespace.Value)
|
||||
assert.Equal(t, "a prefix", j.Value.XML.Value.Prefix.Value)
|
||||
assert.Equal(t, true, j.Value.XML.Value.Attribute.Value)
|
||||
assert.Len(t, j.Value.XML.Value.Extensions, 1)
|
||||
|
||||
assert.NotNil(t, v.Value.AdditionalProperties.Value)
|
||||
|
||||
var addProps map[string]interface{}
|
||||
|
||||
@@ -15,7 +15,7 @@ type Tag struct {
|
||||
Name low.NodeReference[string]
|
||||
Description low.NodeReference[string]
|
||||
ExternalDocs low.NodeReference[*ExternalDoc]
|
||||
Extensions map[low.NodeReference[string]]low.NodeReference[any]
|
||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
||||
}
|
||||
|
||||
func (t *Tag) Build(root *yaml.Node) error {
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
package v3
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"gopkg.in/yaml.v3"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type XML struct {
|
||||
Node *yaml.Node
|
||||
Name low.NodeReference[string]
|
||||
Namespace low.NodeReference[string]
|
||||
Prefix low.NodeReference[string]
|
||||
Attribute low.NodeReference[string]
|
||||
Wrapped low.NodeReference[bool]
|
||||
Extensions map[string]low.ObjectReference
|
||||
Name low.NodeReference[string]
|
||||
Namespace low.NodeReference[string]
|
||||
Prefix low.NodeReference[string]
|
||||
Attribute low.NodeReference[bool]
|
||||
Wrapped low.NodeReference[bool]
|
||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
||||
}
|
||||
|
||||
func (x *XML) Build(root *yaml.Node) error {
|
||||
extensionMap, err := ExtractExtensions(root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
x.Extensions = extensionMap
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -6,8 +6,9 @@ type HasNode interface {
|
||||
GetNode() *yaml.Node
|
||||
}
|
||||
|
||||
type Buildable interface {
|
||||
type Buildable[T any] interface {
|
||||
Build(node *yaml.Node) error
|
||||
*T
|
||||
}
|
||||
|
||||
type NodeReference[T any] struct {
|
||||
@@ -16,6 +17,16 @@ type NodeReference[T any] struct {
|
||||
KeyNode *yaml.Node
|
||||
}
|
||||
|
||||
type KeyReference[T any] struct {
|
||||
Value T
|
||||
KeyNode *yaml.Node
|
||||
}
|
||||
|
||||
type ValueReference[T any] struct {
|
||||
Value T
|
||||
ValueNode *yaml.Node
|
||||
}
|
||||
|
||||
type ObjectReference struct {
|
||||
Value interface{}
|
||||
ValueNode *yaml.Node
|
||||
@@ -25,3 +36,11 @@ type ObjectReference struct {
|
||||
func (n NodeReference[T]) IsEmpty() bool {
|
||||
return n.KeyNode == nil && n.ValueNode == nil
|
||||
}
|
||||
|
||||
func (n NodeReference[T]) IsMapKeyNode() bool {
|
||||
return n.KeyNode != nil && n.ValueNode == nil
|
||||
}
|
||||
|
||||
func (n NodeReference[T]) IsMapValueNode() bool {
|
||||
return n.KeyNode == nil && n.ValueNode != nil
|
||||
}
|
||||
|
||||
@@ -15,8 +15,7 @@ func CreateDocument(info *datamodel.SpecInfo) (*v3.Document, error) {
|
||||
doc := v3.Document{Version: low.NodeReference[string]{Value: info.Version, ValueNode: info.RootNode}}
|
||||
|
||||
// build an index
|
||||
idx := index.NewSpecIndex(info.RootNode)
|
||||
rsolvr := resolver.NewResolver(idx)
|
||||
rsolvr := resolver.NewResolver(index.NewSpecIndex(info.RootNode))
|
||||
|
||||
// todo handle errors
|
||||
rsolvr.Resolve()
|
||||
@@ -24,18 +23,18 @@ func CreateDocument(info *datamodel.SpecInfo) (*v3.Document, error) {
|
||||
var wg sync.WaitGroup
|
||||
var errors []error
|
||||
var runExtraction = func(info *datamodel.SpecInfo, doc *v3.Document,
|
||||
runFunc func(i *datamodel.SpecInfo, d *v3.Document, idx *index.SpecIndex) error,
|
||||
runFunc func(i *datamodel.SpecInfo, d *v3.Document) error,
|
||||
ers *[]error,
|
||||
wg *sync.WaitGroup) {
|
||||
|
||||
if er := runFunc(info, doc, idx); er != nil {
|
||||
if er := runFunc(info, doc); er != nil {
|
||||
*ers = append(*ers, er)
|
||||
}
|
||||
|
||||
wg.Done()
|
||||
}
|
||||
|
||||
extractionFuncs := []func(i *datamodel.SpecInfo, d *v3.Document, idx *index.SpecIndex) error{
|
||||
extractionFuncs := []func(i *datamodel.SpecInfo, d *v3.Document) error{
|
||||
extractInfo,
|
||||
extractServers,
|
||||
extractTags,
|
||||
@@ -54,7 +53,7 @@ func CreateDocument(info *datamodel.SpecInfo) (*v3.Document, error) {
|
||||
return &doc, nil
|
||||
}
|
||||
|
||||
func extractInfo(info *datamodel.SpecInfo, doc *v3.Document, idx *index.SpecIndex) error {
|
||||
func extractInfo(info *datamodel.SpecInfo, doc *v3.Document) error {
|
||||
_, ln, vn := utils.FindKeyNodeFull(v3.InfoLabel, info.RootNode.Content)
|
||||
if vn != nil {
|
||||
ir := v3.Info{}
|
||||
@@ -69,7 +68,7 @@ func extractInfo(info *datamodel.SpecInfo, doc *v3.Document, idx *index.SpecInde
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractServers(info *datamodel.SpecInfo, doc *v3.Document, idx *index.SpecIndex) error {
|
||||
func extractServers(info *datamodel.SpecInfo, doc *v3.Document) error {
|
||||
_, ln, vn := utils.FindKeyNodeFull(v3.ServersLabel, info.RootNode.Content)
|
||||
if vn != nil {
|
||||
if utils.IsNodeArray(vn) {
|
||||
@@ -95,7 +94,7 @@ func extractServers(info *datamodel.SpecInfo, doc *v3.Document, idx *index.SpecI
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractTags(info *datamodel.SpecInfo, doc *v3.Document, idx *index.SpecIndex) error {
|
||||
func extractTags(info *datamodel.SpecInfo, doc *v3.Document) error {
|
||||
_, ln, vn := utils.FindKeyNodeFull(v3.TagsLabel, info.RootNode.Content)
|
||||
if vn != nil {
|
||||
if utils.IsNodeArray(vn) {
|
||||
@@ -121,11 +120,11 @@ func extractTags(info *datamodel.SpecInfo, doc *v3.Document, idx *index.SpecInde
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractPaths(info *datamodel.SpecInfo, doc *v3.Document, idx *index.SpecIndex) error {
|
||||
func extractPaths(info *datamodel.SpecInfo, doc *v3.Document) error {
|
||||
_, ln, vn := utils.FindKeyNodeFull(v3.PathsLabel, info.RootNode.Content)
|
||||
if vn != nil {
|
||||
ir := v3.Paths{}
|
||||
err := ir.Build(vn, idx)
|
||||
err := ir.Build(vn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,109 +1,126 @@
|
||||
package openapi
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/3.0"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
"github.com/pb33f/libopenapi/datamodel"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/3.0"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var doc *v3.Document
|
||||
|
||||
func init() {
|
||||
data, _ := ioutil.ReadFile("../test_specs/burgershop.openapi.yaml")
|
||||
info, _ := datamodel.ExtractSpecInfo(data)
|
||||
doc, _ = CreateDocument(info)
|
||||
data, _ := ioutil.ReadFile("../test_specs/burgershop.openapi.yaml")
|
||||
info, _ := datamodel.ExtractSpecInfo(data)
|
||||
doc, _ = CreateDocument(info)
|
||||
}
|
||||
|
||||
func BenchmarkCreateDocument(b *testing.B) {
|
||||
data, _ := ioutil.ReadFile("../test_specs/burgershop.openapi.yaml")
|
||||
info, _ := datamodel.ExtractSpecInfo(data)
|
||||
for i := 0; i < b.N; i++ {
|
||||
doc, _ = CreateDocument(info)
|
||||
}
|
||||
data, _ := ioutil.ReadFile("../test_specs/burgershop.openapi.yaml")
|
||||
info, _ := datamodel.ExtractSpecInfo(data)
|
||||
for i := 0; i < b.N; i++ {
|
||||
doc, _ = CreateDocument(info)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateDocument(t *testing.T) {
|
||||
assert.Equal(t, "3.0.1", doc.Version.Value)
|
||||
assert.Equal(t, "Burger Shop", doc.Info.Value.Title.Value)
|
||||
assert.NotEmpty(t, doc.Info.Value.Title.Value)
|
||||
assert.Equal(t, "3.0.1", doc.Version.Value)
|
||||
assert.Equal(t, "Burger Shop", doc.Info.Value.Title.Value)
|
||||
assert.NotEmpty(t, doc.Info.Value.Title.Value)
|
||||
}
|
||||
|
||||
func TestCreateDocument_Info(t *testing.T) {
|
||||
assert.Equal(t, "https://pb33f.io", doc.Info.Value.TermsOfService.Value)
|
||||
assert.Equal(t, "pb33f", doc.Info.Value.Contact.Value.Name.Value)
|
||||
assert.Equal(t, "buckaroo@pb33f.io", doc.Info.Value.Contact.Value.Email.Value)
|
||||
assert.Equal(t, "https://pb33f.io", doc.Info.Value.Contact.Value.URL.Value)
|
||||
assert.Equal(t, "pb33f", doc.Info.Value.License.Value.Name.Value)
|
||||
assert.Equal(t, "https://pb33f.io/made-up", doc.Info.Value.License.Value.URL.Value)
|
||||
assert.Equal(t, "https://pb33f.io", doc.Info.Value.TermsOfService.Value)
|
||||
assert.Equal(t, "pb33f", doc.Info.Value.Contact.Value.Name.Value)
|
||||
assert.Equal(t, "buckaroo@pb33f.io", doc.Info.Value.Contact.Value.Email.Value)
|
||||
assert.Equal(t, "https://pb33f.io", doc.Info.Value.Contact.Value.URL.Value)
|
||||
assert.Equal(t, "pb33f", doc.Info.Value.License.Value.Name.Value)
|
||||
assert.Equal(t, "https://pb33f.io/made-up", doc.Info.Value.License.Value.URL.Value)
|
||||
}
|
||||
|
||||
func TestCreateDocument_Servers(t *testing.T) {
|
||||
assert.Len(t, doc.Servers, 2)
|
||||
server1 := doc.Servers[0]
|
||||
server2 := doc.Servers[1]
|
||||
assert.Len(t, doc.Servers, 2)
|
||||
server1 := doc.Servers[0]
|
||||
server2 := doc.Servers[1]
|
||||
|
||||
// server 1
|
||||
assert.Equal(t, "{scheme}://api.pb33f.io", server1.Value.URL.Value)
|
||||
assert.NotEmpty(t, server1.Value.Description.Value)
|
||||
assert.Len(t, server1.Value.Variables.Value, 1)
|
||||
assert.Len(t, server1.Value.Variables.Value["scheme"].Value.Enum, 2)
|
||||
assert.Equal(t, server1.Value.Variables.Value["scheme"].Value.Default.Value, "https")
|
||||
assert.NotEmpty(t, server1.Value.Variables.Value["scheme"].Value.Description.Value)
|
||||
// server 1
|
||||
assert.Equal(t, "{scheme}://api.pb33f.io", server1.Value.URL.Value)
|
||||
assert.NotEmpty(t, server1.Value.Description.Value)
|
||||
assert.Len(t, server1.Value.Variables.Value, 1)
|
||||
assert.Len(t, server1.Value.Variables.Value["scheme"].Value.Enum, 2)
|
||||
assert.Equal(t, server1.Value.Variables.Value["scheme"].Value.Default.Value, "https")
|
||||
assert.NotEmpty(t, server1.Value.Variables.Value["scheme"].Value.Description.Value)
|
||||
|
||||
// server 2
|
||||
assert.Equal(t, "https://{domain}.{host}.com", server2.Value.URL.Value)
|
||||
assert.NotEmpty(t, server2.Value.Description.Value)
|
||||
assert.Len(t, server2.Value.Variables.Value, 2)
|
||||
assert.Equal(t, server2.Value.Variables.Value["domain"].Value.Default.Value, "api")
|
||||
assert.NotEmpty(t, server2.Value.Variables.Value["domain"].Value.Description.Value)
|
||||
assert.NotEmpty(t, server2.Value.Variables.Value["host"].Value.Description.Value)
|
||||
assert.Equal(t, server2.Value.Variables.Value["host"].Value.Default.Value, "pb33f.io")
|
||||
assert.Equal(t, "1.2", doc.Info.Value.Version.Value)
|
||||
// server 2
|
||||
assert.Equal(t, "https://{domain}.{host}.com", server2.Value.URL.Value)
|
||||
assert.NotEmpty(t, server2.Value.Description.Value)
|
||||
assert.Len(t, server2.Value.Variables.Value, 2)
|
||||
assert.Equal(t, server2.Value.Variables.Value["domain"].Value.Default.Value, "api")
|
||||
assert.NotEmpty(t, server2.Value.Variables.Value["domain"].Value.Description.Value)
|
||||
assert.NotEmpty(t, server2.Value.Variables.Value["host"].Value.Description.Value)
|
||||
assert.Equal(t, server2.Value.Variables.Value["host"].Value.Default.Value, "pb33f.io")
|
||||
assert.Equal(t, "1.2", doc.Info.Value.Version.Value)
|
||||
}
|
||||
|
||||
func TestCreateDocument_Tags(t *testing.T) {
|
||||
assert.Len(t, doc.Tags, 2)
|
||||
assert.Len(t, doc.Tags, 2)
|
||||
|
||||
// tag1
|
||||
assert.Equal(t, "Burgers", doc.Tags[0].Value.Name.Value)
|
||||
assert.NotEmpty(t, doc.Tags[0].Value.Description.Value)
|
||||
assert.NotNil(t, doc.Tags[0].Value.ExternalDocs.Value)
|
||||
assert.Equal(t, "https://pb33f.io", doc.Tags[0].Value.ExternalDocs.Value.URL.Value)
|
||||
assert.NotEmpty(t, doc.Tags[0].Value.ExternalDocs.Value.URL.Value)
|
||||
assert.Len(t, doc.Tags[0].Value.Extensions, 7)
|
||||
// tag1
|
||||
assert.Equal(t, "Burgers", doc.Tags[0].Value.Name.Value)
|
||||
assert.NotEmpty(t, doc.Tags[0].Value.Description.Value)
|
||||
assert.NotNil(t, doc.Tags[0].Value.ExternalDocs.Value)
|
||||
assert.Equal(t, "https://pb33f.io", doc.Tags[0].Value.ExternalDocs.Value.URL.Value)
|
||||
assert.NotEmpty(t, doc.Tags[0].Value.ExternalDocs.Value.URL.Value)
|
||||
assert.Len(t, doc.Tags[0].Value.Extensions, 7)
|
||||
|
||||
for key, extension := range doc.Tags[0].Value.Extensions {
|
||||
switch key.Value {
|
||||
case "x-internal-ting":
|
||||
assert.Equal(t, "somethingSpecial", extension.Value)
|
||||
case "x-internal-tong":
|
||||
assert.Equal(t, int64(1), extension.Value)
|
||||
case "x-internal-tang":
|
||||
assert.Equal(t, 1.2, extension.Value)
|
||||
case "x-internal-tung":
|
||||
assert.Equal(t, true, extension.Value)
|
||||
case "x-internal-arr":
|
||||
assert.Len(t, extension.Value, 2)
|
||||
assert.Equal(t, "one", extension.Value.([]interface{})[0].(string))
|
||||
case "x-internal-arrmap":
|
||||
assert.Len(t, extension.Value, 2)
|
||||
assert.Equal(t, "now", extension.Value.([]interface{})[0].(map[string]interface{})["what"])
|
||||
case "x-something-else":
|
||||
// crazy times in the upside down. this API should be avoided for the higher up use cases.
|
||||
// this is why we will need a higher level API to this model, this looks cool and all, but dude.
|
||||
assert.Equal(t, "now?", extension.Value.(map[string]interface{})["ok"].([]interface{})[0].(map[string]interface{})["what"])
|
||||
}
|
||||
for key, extension := range doc.Tags[0].Value.Extensions {
|
||||
switch key.Value {
|
||||
case "x-internal-ting":
|
||||
assert.Equal(t, "somethingSpecial", extension.Value)
|
||||
case "x-internal-tong":
|
||||
assert.Equal(t, int64(1), extension.Value)
|
||||
case "x-internal-tang":
|
||||
assert.Equal(t, 1.2, extension.Value)
|
||||
case "x-internal-tung":
|
||||
assert.Equal(t, true, extension.Value)
|
||||
case "x-internal-arr":
|
||||
assert.Len(t, extension.Value, 2)
|
||||
assert.Equal(t, "one", extension.Value.([]interface{})[0].(string))
|
||||
case "x-internal-arrmap":
|
||||
assert.Len(t, extension.Value, 2)
|
||||
assert.Equal(t, "now", extension.Value.([]interface{})[0].(map[string]interface{})["what"])
|
||||
case "x-something-else":
|
||||
// crazy times in the upside down. this API should be avoided for the higher up use cases.
|
||||
// this is why we will need a higher level API to this model, this looks cool and all, but dude.
|
||||
assert.Equal(t, "now?", extension.Value.(map[string]interface{})["ok"].([]interface{})[0].(map[string]interface{})["what"])
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// tag2
|
||||
assert.Equal(t, "Dressing", doc.Tags[1].Value.Name.Value)
|
||||
assert.NotEmpty(t, doc.Tags[1].Value.Description.Value)
|
||||
assert.NotNil(t, doc.Tags[1].Value.ExternalDocs.Value)
|
||||
assert.Equal(t, "https://pb33f.io", doc.Tags[1].Value.ExternalDocs.Value.URL.Value)
|
||||
assert.NotEmpty(t, doc.Tags[1].Value.ExternalDocs.Value.URL.Value)
|
||||
assert.Len(t, doc.Tags[1].Value.Extensions, 0)
|
||||
/// tag2
|
||||
assert.Equal(t, "Dressing", doc.Tags[1].Value.Name.Value)
|
||||
assert.NotEmpty(t, doc.Tags[1].Value.Description.Value)
|
||||
assert.NotNil(t, doc.Tags[1].Value.ExternalDocs.Value)
|
||||
assert.Equal(t, "https://pb33f.io", doc.Tags[1].Value.ExternalDocs.Value.URL.Value)
|
||||
assert.NotEmpty(t, doc.Tags[1].Value.ExternalDocs.Value.URL.Value)
|
||||
assert.Len(t, doc.Tags[1].Value.Extensions, 0)
|
||||
|
||||
}
|
||||
|
||||
func TestCreateDocument_Paths(t *testing.T) {
|
||||
assert.Len(t, doc.Paths.Value.PathItems, 6)
|
||||
burgerId := doc.Paths.Value.GetPath("/burgers/{burgerId}")
|
||||
assert.NotNil(t, burgerId)
|
||||
assert.Len(t, burgerId.Value.Get.Value.Parameters, 2)
|
||||
param := burgerId.Value.Get.Value.Parameters[1]
|
||||
assert.Equal(t, "burgerHeader", param.Value.Name.Value)
|
||||
prop := param.Value.Schema.Value.FindProperty("burgerTheme")
|
||||
assert.Equal(t, "something about a theme?", prop.Value.Description.Value)
|
||||
assert.Equal(t, "big-mac", param.Value.Example.Value)
|
||||
|
||||
// check content
|
||||
pContent := param.Value.GetContent("application/json")
|
||||
assert.Equal(t, "somethingNice", pContent.Value.Example.Value)
|
||||
|
||||
}
|
||||
|
||||
@@ -321,6 +321,27 @@ components:
|
||||
example: big-mac
|
||||
description: the name of the burger. use this to order your food
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
example: somethingNice
|
||||
encoding:
|
||||
burgerTheme:
|
||||
contentType: text/plain
|
||||
headers:
|
||||
someHeader:
|
||||
description: this is a header
|
||||
schema:
|
||||
type: string
|
||||
schema:
|
||||
type: object
|
||||
required: [burgerTheme, burgerTime]
|
||||
properties:
|
||||
burgerTheme:
|
||||
type: string
|
||||
description: something about a theme?
|
||||
burgerTime:
|
||||
type: number
|
||||
description: number of burgers ordered this year.
|
||||
BurgerId:
|
||||
in: path
|
||||
name: burgerId
|
||||
|
||||
Reference in New Issue
Block a user