mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-09 20:47:44 +00:00
Full model is now in place,
Time to revisit each model and build individual tests to ensure all error handling is in place across the model. Signed-off-by: Dave Shanley <dave@quobix.com>
This commit is contained in:
@@ -10,6 +10,10 @@ type Callback struct {
|
|||||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cb *Callback) FindExpression(exp string) *low.ValueReference[*PathItem] {
|
||||||
|
return FindItemInMap[*PathItem](exp, cb.Expression.Value)
|
||||||
|
}
|
||||||
|
|
||||||
func (cb *Callback) Build(root *yaml.Node) error {
|
func (cb *Callback) Build(root *yaml.Node) error {
|
||||||
extensionMap, err := ExtractExtensions(root)
|
extensionMap, err := ExtractExtensions(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -36,6 +36,26 @@ func (co *Components) FindSecurityScheme(sScheme string) *low.ValueReference[*Se
|
|||||||
return FindItemInMap[*SecurityScheme](sScheme, co.SecuritySchemes.Value)
|
return FindItemInMap[*SecurityScheme](sScheme, co.SecuritySchemes.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (co *Components) FindExample(example string) *low.ValueReference[*Example] {
|
||||||
|
return FindItemInMap[*Example](example, co.Examples.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (co *Components) FindRequestBody(requestBody string) *low.ValueReference[*RequestBody] {
|
||||||
|
return FindItemInMap[*RequestBody](requestBody, co.RequestBodies.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (co *Components) FindHeader(header string) *low.ValueReference[*Header] {
|
||||||
|
return FindItemInMap[*Header](header, co.Headers.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (co *Components) FindLink(link string) *low.ValueReference[*Link] {
|
||||||
|
return FindItemInMap[*Link](link, co.Links.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (co *Components) FindCallback(callback string) *low.ValueReference[*Callback] {
|
||||||
|
return FindItemInMap[*Callback](callback, co.Callbacks.Value)
|
||||||
|
}
|
||||||
|
|
||||||
func (co *Components) Build(root *yaml.Node) error {
|
func (co *Components) Build(root *yaml.Node) error {
|
||||||
extensionMap, err := ExtractExtensions(root)
|
extensionMap, err := ExtractExtensions(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ import (
|
|||||||
|
|
||||||
type Discriminator struct {
|
type Discriminator struct {
|
||||||
PropertyName low.NodeReference[string]
|
PropertyName low.NodeReference[string]
|
||||||
Mapping map[low.NodeReference[string]]low.NodeReference[string]
|
Mapping map[low.KeyReference[string]]low.ValueReference[string]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Discriminator) FindMappingValue(key string) *low.NodeReference[string] {
|
func (d *Discriminator) FindMappingValue(key string) *low.ValueReference[string] {
|
||||||
for k, v := range d.Mapping {
|
for k, v := range d.Mapping {
|
||||||
if k.Value == key {
|
if k.Value == key {
|
||||||
return &v
|
return &v
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ type Document struct {
|
|||||||
Servers low.NodeReference[[]low.ValueReference[*Server]]
|
Servers low.NodeReference[[]low.ValueReference[*Server]]
|
||||||
Paths low.NodeReference[*Paths]
|
Paths low.NodeReference[*Paths]
|
||||||
Components low.NodeReference[*Components]
|
Components low.NodeReference[*Components]
|
||||||
Security []*SecurityRequirement
|
Security low.NodeReference[*SecurityRequirement]
|
||||||
Tags []low.NodeReference[*Tag]
|
Tags low.NodeReference[[]low.ValueReference[*Tag]]
|
||||||
ExternalDocs *ExternalDoc
|
ExternalDocs low.NodeReference[*ExternalDoc]
|
||||||
Extensions map[low.NodeReference[string]]low.NodeReference[any]
|
Extensions map[low.NodeReference[string]]low.NodeReference[any]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,17 +9,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
func FindItemInCollection[T any](item string, collection map[low.KeyReference[string]]map[low.KeyReference[string]]low.ValueReference[T]) *low.ValueReference[T] {
|
|
||||||
for _, c := range collection {
|
|
||||||
for n, o := range c {
|
|
||||||
if n.Value == item {
|
|
||||||
return &o
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func FindItemInMap[T any](item string, collection map[low.KeyReference[string]]low.ValueReference[T]) *low.ValueReference[T] {
|
func FindItemInMap[T any](item string, collection map[low.KeyReference[string]]low.ValueReference[T]) *low.ValueReference[T] {
|
||||||
for n, o := range collection {
|
for n, o := range collection {
|
||||||
if n.Value == item {
|
if n.Value == item {
|
||||||
|
|||||||
@@ -61,11 +61,11 @@ func BuildModel(node *yaml.Node, model interface{}) error {
|
|||||||
func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) error {
|
func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) error {
|
||||||
switch field.Type() {
|
switch field.Type() {
|
||||||
|
|
||||||
case reflect.TypeOf(map[string]low.ObjectReference{}):
|
case reflect.TypeOf(map[string]low.NodeReference[any]{}):
|
||||||
if valueNode != nil {
|
if valueNode != nil {
|
||||||
if utils.IsNodeMap(valueNode) {
|
if utils.IsNodeMap(valueNode) {
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
items := make(map[string]low.ObjectReference)
|
items := make(map[string]low.NodeReference[any])
|
||||||
var currentLabel string
|
var currentLabel string
|
||||||
for i, sliceItem := range valueNode.Content {
|
for i, sliceItem := range valueNode.Content {
|
||||||
if i%2 == 0 {
|
if i%2 == 0 {
|
||||||
@@ -77,7 +77,7 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
items[currentLabel] = low.ObjectReference{
|
items[currentLabel] = low.NodeReference[any]{
|
||||||
Value: decoded,
|
Value: decoded,
|
||||||
ValueNode: sliceItem,
|
ValueNode: sliceItem,
|
||||||
KeyNode: valueNode,
|
KeyNode: valueNode,
|
||||||
@@ -111,33 +111,33 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case reflect.TypeOf(low.ObjectReference{}):
|
case reflect.TypeOf(low.NodeReference[any]{}):
|
||||||
if valueNode != nil {
|
if valueNode != nil {
|
||||||
var decoded map[string]interface{}
|
var decoded interface{}
|
||||||
err := valueNode.Decode(&decoded)
|
err := valueNode.Decode(&decoded)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if utils.IsNodeMap(valueNode) {
|
if utils.IsNodeMap(valueNode) {
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
or := low.ObjectReference{Value: decoded, ValueNode: valueNode}
|
or := low.NodeReference[any]{Value: decoded, ValueNode: valueNode}
|
||||||
field.Set(reflect.ValueOf(or))
|
field.Set(reflect.ValueOf(or))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case reflect.TypeOf([]low.ObjectReference{}):
|
case reflect.TypeOf([]low.NodeReference[any]{}):
|
||||||
if valueNode != nil {
|
if valueNode != nil {
|
||||||
if utils.IsNodeArray(valueNode) {
|
if utils.IsNodeArray(valueNode) {
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
var items []low.ObjectReference
|
var items []low.NodeReference[any]
|
||||||
for _, sliceItem := range valueNode.Content {
|
for _, sliceItem := range valueNode.Content {
|
||||||
var decoded map[string]interface{}
|
var decoded map[string]interface{}
|
||||||
err := sliceItem.Decode(&decoded)
|
err := sliceItem.Decode(&decoded)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
items = append(items, low.ObjectReference{
|
items = append(items, low.NodeReference[any]{
|
||||||
Value: decoded,
|
Value: decoded,
|
||||||
ValueNode: sliceItem,
|
ValueNode: sliceItem,
|
||||||
KeyNode: valueNode,
|
KeyNode: valueNode,
|
||||||
@@ -341,21 +341,21 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
// helper for unpacking string maps.
|
// helper for unpacking string maps.
|
||||||
case reflect.TypeOf(map[low.NodeReference[string]]low.NodeReference[string]{}):
|
case reflect.TypeOf(map[low.KeyReference[string]]low.ValueReference[string]{}):
|
||||||
if valueNode != nil {
|
if valueNode != nil {
|
||||||
if utils.IsNodeMap(valueNode) {
|
if utils.IsNodeMap(valueNode) {
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
items := make(map[low.NodeReference[string]]low.NodeReference[string])
|
items := make(map[low.KeyReference[string]]low.ValueReference[string])
|
||||||
var cf *yaml.Node
|
var cf *yaml.Node
|
||||||
for i, sliceItem := range valueNode.Content {
|
for i, sliceItem := range valueNode.Content {
|
||||||
if i%2 == 0 {
|
if i%2 == 0 {
|
||||||
cf = sliceItem
|
cf = sliceItem
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
items[low.NodeReference[string]{
|
items[low.KeyReference[string]{
|
||||||
Value: cf.Value,
|
Value: cf.Value,
|
||||||
KeyNode: cf,
|
KeyNode: cf,
|
||||||
}] = low.NodeReference[string]{
|
}] = low.ValueReference[string]{
|
||||||
Value: sliceItem.Value,
|
Value: sliceItem.Value,
|
||||||
ValueNode: sliceItem,
|
ValueNode: sliceItem,
|
||||||
}
|
}
|
||||||
@@ -364,19 +364,18 @@ func SetField(field reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) err
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case reflect.TypeOf(low.NodeReference[[]low.NodeReference[string]]{}):
|
case reflect.TypeOf(low.NodeReference[[]low.ValueReference[string]]{}):
|
||||||
if valueNode != nil {
|
if valueNode != nil {
|
||||||
if utils.IsNodeArray(valueNode) {
|
if utils.IsNodeArray(valueNode) {
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
var items []low.NodeReference[string]
|
var items []low.ValueReference[string]
|
||||||
for _, sliceItem := range valueNode.Content {
|
for _, sliceItem := range valueNode.Content {
|
||||||
items = append(items, low.NodeReference[string]{
|
items = append(items, low.ValueReference[string]{
|
||||||
Value: sliceItem.Value,
|
Value: sliceItem.Value,
|
||||||
ValueNode: sliceItem,
|
ValueNode: sliceItem,
|
||||||
KeyNode: valueNode,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
n := low.NodeReference[[]low.NodeReference[string]]{
|
n := low.NodeReference[[]low.ValueReference[string]]{
|
||||||
Value: items,
|
Value: items,
|
||||||
KeyNode: keyNode,
|
KeyNode: keyNode,
|
||||||
ValueNode: valueNode,
|
ValueNode: valueNode,
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ type hotdog struct {
|
|||||||
Temps []low.NodeReference[int]
|
Temps []low.NodeReference[int]
|
||||||
HighTemps []low.NodeReference[int64]
|
HighTemps []low.NodeReference[int64]
|
||||||
Buns []low.NodeReference[bool]
|
Buns []low.NodeReference[bool]
|
||||||
UnknownElements low.ObjectReference
|
UnknownElements low.NodeReference[any]
|
||||||
LotsOfUnknowns []low.ObjectReference
|
LotsOfUnknowns []low.NodeReference[any]
|
||||||
Where map[string]low.ObjectReference
|
Where map[string]low.NodeReference[any]
|
||||||
There map[string]low.NodeReference[string]
|
There map[string]low.NodeReference[string]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ type Schema struct {
|
|||||||
UniqueItems low.NodeReference[int]
|
UniqueItems low.NodeReference[int]
|
||||||
MaxProperties low.NodeReference[int]
|
MaxProperties low.NodeReference[int]
|
||||||
MinProperties low.NodeReference[int]
|
MinProperties low.NodeReference[int]
|
||||||
Required low.NodeReference[[]low.NodeReference[string]]
|
Required low.NodeReference[[]low.ValueReference[string]]
|
||||||
Enum low.NodeReference[[]low.NodeReference[string]]
|
Enum low.NodeReference[[]low.ValueReference[string]]
|
||||||
Type low.NodeReference[string]
|
Type low.NodeReference[string]
|
||||||
AllOf low.NodeReference[[]low.NodeReference[*Schema]]
|
AllOf low.NodeReference[[]low.NodeReference[*Schema]]
|
||||||
OneOf low.NodeReference[[]low.NodeReference[*Schema]]
|
OneOf low.NodeReference[[]low.NodeReference[*Schema]]
|
||||||
@@ -85,12 +85,11 @@ func (s *Schema) BuildLevel(root *yaml.Node, level int) error {
|
|||||||
_, addPLabel, addPNode := utils.FindKeyNodeFull(AdditionalPropertiesLabel, root.Content)
|
_, addPLabel, addPNode := utils.FindKeyNodeFull(AdditionalPropertiesLabel, root.Content)
|
||||||
if addPNode != nil {
|
if addPNode != nil {
|
||||||
if utils.IsNodeMap(addPNode) {
|
if utils.IsNodeMap(addPNode) {
|
||||||
var props map[string]interface{}
|
schema, serr := ExtractObjectRaw[*Schema](addPNode)
|
||||||
err = addPNode.Decode(&props)
|
if serr != nil {
|
||||||
if err != nil {
|
return serr
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
s.AdditionalProperties = low.NodeReference[any]{Value: props, KeyNode: addPLabel, ValueNode: addPNode}
|
s.AdditionalProperties = low.NodeReference[any]{Value: schema, KeyNode: addPLabel, ValueNode: addPNode}
|
||||||
}
|
}
|
||||||
|
|
||||||
if utils.IsNodeBoolValue(addPNode) {
|
if utils.IsNodeBoolValue(addPNode) {
|
||||||
|
|||||||
@@ -24,6 +24,10 @@ type SecurityScheme struct {
|
|||||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SecurityRequirement struct {
|
||||||
|
Value []low.ValueReference[map[low.KeyReference[string]][]low.ValueReference[string]]
|
||||||
|
}
|
||||||
|
|
||||||
func (ss *SecurityScheme) Build(root *yaml.Node) error {
|
func (ss *SecurityScheme) Build(root *yaml.Node) error {
|
||||||
extensionMap, err := ExtractExtensions(root)
|
extensionMap, err := ExtractExtensions(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -42,10 +46,6 @@ func (ss *SecurityScheme) Build(root *yaml.Node) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type SecurityRequirement struct {
|
|
||||||
Value []low.ValueReference[map[low.KeyReference[string]][]low.ValueReference[string]]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sr *SecurityRequirement) FindRequirement(name string) []low.ValueReference[string] {
|
func (sr *SecurityRequirement) FindRequirement(name string) []low.ValueReference[string] {
|
||||||
for _, r := range sr.Value {
|
for _, r := range sr.Value {
|
||||||
for k, v := range r.Value {
|
for k, v := range r.Value {
|
||||||
|
|||||||
@@ -27,12 +27,6 @@ type ValueReference[T any] struct {
|
|||||||
ValueNode *yaml.Node
|
ValueNode *yaml.Node
|
||||||
}
|
}
|
||||||
|
|
||||||
type ObjectReference struct {
|
|
||||||
Value interface{}
|
|
||||||
ValueNode *yaml.Node
|
|
||||||
KeyNode *yaml.Node
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n NodeReference[T]) IsEmpty() bool {
|
func (n NodeReference[T]) IsEmpty() bool {
|
||||||
return n.KeyNode == nil && n.ValueNode == nil
|
return n.KeyNode == nil && n.ValueNode == nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ func TestSpecIndex_PetstoreV3(t *testing.T) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var mappedRefs = 9
|
var mappedRefs = 16
|
||||||
|
|
||||||
func TestSpecIndex_BurgerShop(t *testing.T) {
|
func TestSpecIndex_BurgerShop(t *testing.T) {
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ func TestSpecIndex_BurgerShop(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(t, 5, len(index.GetAllSchemas()))
|
assert.Equal(t, 5, len(index.GetAllSchemas()))
|
||||||
|
|
||||||
assert.Equal(t, 22, len(index.GetAllSequencedReferences()))
|
assert.Equal(t, 30, len(index.GetAllSequencedReferences()))
|
||||||
assert.NotNil(t, index.GetSchemasNode())
|
assert.NotNil(t, index.GetSchemasNode())
|
||||||
assert.NotNil(t, index.GetParametersNode())
|
assert.NotNil(t, index.GetParametersNode())
|
||||||
|
|
||||||
@@ -214,7 +214,7 @@ func TestSpecIndex_BurgerShop(t *testing.T) {
|
|||||||
assert.Equal(t, 2, index.componentsInlineParamUniqueCount)
|
assert.Equal(t, 2, index.componentsInlineParamUniqueCount)
|
||||||
assert.Equal(t, 2, index.GetInlineUniqueParamCount())
|
assert.Equal(t, 2, index.GetInlineUniqueParamCount())
|
||||||
|
|
||||||
assert.Equal(t, 0, len(index.GetAllRequestBodies()))
|
assert.Equal(t, 1, len(index.GetAllRequestBodies()))
|
||||||
assert.NotNil(t, index.GetRootNode())
|
assert.NotNil(t, index.GetRootNode())
|
||||||
assert.NotNil(t, index.GetGlobalTagsNode())
|
assert.NotNil(t, index.GetGlobalTagsNode())
|
||||||
assert.NotNil(t, index.GetPathsNode())
|
assert.NotNil(t, index.GetPathsNode())
|
||||||
@@ -223,7 +223,7 @@ func TestSpecIndex_BurgerShop(t *testing.T) {
|
|||||||
assert.NotNil(t, index.GetOperationParameterReferences())
|
assert.NotNil(t, index.GetOperationParameterReferences())
|
||||||
assert.Equal(t, 3, len(index.GetAllSecuritySchemes()))
|
assert.Equal(t, 3, len(index.GetAllSecuritySchemes()))
|
||||||
assert.Equal(t, 2, len(index.GetAllParameters()))
|
assert.Equal(t, 2, len(index.GetAllParameters()))
|
||||||
assert.Equal(t, 0, len(index.GetAllResponses()))
|
assert.Equal(t, 1, len(index.GetAllResponses()))
|
||||||
assert.Equal(t, 2, len(index.GetInlineOperationDuplicateParameters()))
|
assert.Equal(t, 2, len(index.GetInlineOperationDuplicateParameters()))
|
||||||
assert.Equal(t, 0, len(index.GetReferencesWithSiblings()))
|
assert.Equal(t, 0, len(index.GetReferencesWithSiblings()))
|
||||||
assert.Equal(t, mappedRefs, len(index.GetAllReferences()))
|
assert.Equal(t, mappedRefs, len(index.GetAllReferences()))
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ func CreateDocument(info *datamodel.SpecInfo) (*v3.Document, error) {
|
|||||||
extractTags,
|
extractTags,
|
||||||
extractPaths,
|
extractPaths,
|
||||||
extractComponents,
|
extractComponents,
|
||||||
|
extractSecurity,
|
||||||
|
extractExternalDocs,
|
||||||
}
|
}
|
||||||
wg.Add(len(extractionFuncs))
|
wg.Add(len(extractionFuncs))
|
||||||
for _, f := range extractionFuncs {
|
for _, f := range extractionFuncs {
|
||||||
@@ -69,6 +71,24 @@ func extractInfo(info *datamodel.SpecInfo, doc *v3.Document) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func extractSecurity(info *datamodel.SpecInfo, doc *v3.Document) error {
|
||||||
|
sec, sErr := v3.ExtractObject[*v3.SecurityRequirement](v3.SecurityLabel, info.RootNode)
|
||||||
|
if sErr != nil {
|
||||||
|
return sErr
|
||||||
|
}
|
||||||
|
doc.Security = sec
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractExternalDocs(info *datamodel.SpecInfo, doc *v3.Document) error {
|
||||||
|
extDocs, dErr := v3.ExtractObject[*v3.ExternalDoc](v3.ExternalDocsLabel, info.RootNode)
|
||||||
|
if dErr != nil {
|
||||||
|
return dErr
|
||||||
|
}
|
||||||
|
doc.ExternalDocs = extDocs
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func extractComponents(info *datamodel.SpecInfo, doc *v3.Document) error {
|
func extractComponents(info *datamodel.SpecInfo, doc *v3.Document) error {
|
||||||
_, ln, vn := utils.FindKeyNodeFull(v3.ComponentsLabel, info.RootNode.Content)
|
_, ln, vn := utils.FindKeyNodeFull(v3.ComponentsLabel, info.RootNode.Content)
|
||||||
if vn != nil {
|
if vn != nil {
|
||||||
@@ -117,7 +137,7 @@ func extractTags(info *datamodel.SpecInfo, doc *v3.Document) error {
|
|||||||
_, ln, vn := utils.FindKeyNodeFull(v3.TagsLabel, info.RootNode.Content)
|
_, ln, vn := utils.FindKeyNodeFull(v3.TagsLabel, info.RootNode.Content)
|
||||||
if vn != nil {
|
if vn != nil {
|
||||||
if utils.IsNodeArray(vn) {
|
if utils.IsNodeArray(vn) {
|
||||||
var tags []low.NodeReference[*v3.Tag]
|
var tags []low.ValueReference[*v3.Tag]
|
||||||
for _, tagN := range vn.Content {
|
for _, tagN := range vn.Content {
|
||||||
if utils.IsNodeMap(tagN) {
|
if utils.IsNodeMap(tagN) {
|
||||||
tag := v3.Tag{}
|
tag := v3.Tag{}
|
||||||
@@ -126,14 +146,17 @@ func extractTags(info *datamodel.SpecInfo, doc *v3.Document) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tag.Build(tagN)
|
tag.Build(tagN)
|
||||||
tags = append(tags, low.NodeReference[*v3.Tag]{
|
tags = append(tags, low.ValueReference[*v3.Tag]{
|
||||||
Value: &tag,
|
Value: &tag,
|
||||||
ValueNode: tagN,
|
ValueNode: tagN,
|
||||||
KeyNode: ln,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
doc.Tags = tags
|
doc.Tags = low.NodeReference[[]low.ValueReference[*v3.Tag]]{
|
||||||
|
Value: tags,
|
||||||
|
KeyNode: ln,
|
||||||
|
ValueNode: vn,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -64,17 +64,17 @@ func TestCreateDocument_Servers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateDocument_Tags(t *testing.T) {
|
func TestCreateDocument_Tags(t *testing.T) {
|
||||||
assert.Len(t, doc.Tags, 2)
|
assert.Len(t, doc.Tags.Value, 2)
|
||||||
|
|
||||||
// tag1
|
// tag1
|
||||||
assert.Equal(t, "Burgers", doc.Tags[0].Value.Name.Value)
|
assert.Equal(t, "Burgers", doc.Tags.Value[0].Value.Name.Value)
|
||||||
assert.NotEmpty(t, doc.Tags[0].Value.Description.Value)
|
assert.NotEmpty(t, doc.Tags.Value[0].Value.Description.Value)
|
||||||
assert.NotNil(t, doc.Tags[0].Value.ExternalDocs.Value)
|
assert.NotNil(t, doc.Tags.Value[0].Value.ExternalDocs.Value)
|
||||||
assert.Equal(t, "https://pb33f.io", doc.Tags[0].Value.ExternalDocs.Value.URL.Value)
|
assert.Equal(t, "https://pb33f.io", doc.Tags.Value[0].Value.ExternalDocs.Value.URL.Value)
|
||||||
assert.NotEmpty(t, doc.Tags[0].Value.ExternalDocs.Value.URL.Value)
|
assert.NotEmpty(t, doc.Tags.Value[0].Value.ExternalDocs.Value.URL.Value)
|
||||||
assert.Len(t, doc.Tags[0].Value.Extensions, 7)
|
assert.Len(t, doc.Tags.Value[0].Value.Extensions, 7)
|
||||||
|
|
||||||
for key, extension := range doc.Tags[0].Value.Extensions {
|
for key, extension := range doc.Tags.Value[0].Value.Extensions {
|
||||||
switch key.Value {
|
switch key.Value {
|
||||||
case "x-internal-ting":
|
case "x-internal-ting":
|
||||||
assert.Equal(t, "somethingSpecial", extension.Value)
|
assert.Equal(t, "somethingSpecial", extension.Value)
|
||||||
@@ -99,12 +99,12 @@ func TestCreateDocument_Tags(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// tag2
|
/// tag2
|
||||||
assert.Equal(t, "Dressing", doc.Tags[1].Value.Name.Value)
|
assert.Equal(t, "Dressing", doc.Tags.Value[1].Value.Name.Value)
|
||||||
assert.NotEmpty(t, doc.Tags[1].Value.Description.Value)
|
assert.NotEmpty(t, doc.Tags.Value[1].Value.Description.Value)
|
||||||
assert.NotNil(t, doc.Tags[1].Value.ExternalDocs.Value)
|
assert.NotNil(t, doc.Tags.Value[1].Value.ExternalDocs.Value)
|
||||||
assert.Equal(t, "https://pb33f.io", doc.Tags[1].Value.ExternalDocs.Value.URL.Value)
|
assert.Equal(t, "https://pb33f.io", doc.Tags.Value[1].Value.ExternalDocs.Value.URL.Value)
|
||||||
assert.NotEmpty(t, doc.Tags[1].Value.ExternalDocs.Value.URL.Value)
|
assert.NotEmpty(t, doc.Tags.Value[1].Value.ExternalDocs.Value.URL.Value)
|
||||||
assert.Len(t, doc.Tags[1].Value.Extensions, 0)
|
assert.Len(t, doc.Tags.Value[1].Value.Extensions, 0)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,7 +257,10 @@ func TestCreateDocument_Components_Schemas(t *testing.T) {
|
|||||||
assert.Equal(t, "a frosty cold beverage can be coke or sprite",
|
assert.Equal(t, "a frosty cold beverage can be coke or sprite",
|
||||||
fries.Value.FindProperty("favoriteDrink").Value.Description.Value)
|
fries.Value.FindProperty("favoriteDrink").Value.Description.Value)
|
||||||
|
|
||||||
// check security schemes
|
}
|
||||||
|
|
||||||
|
func TestCreateDocument_Components_SecuritySchemes(t *testing.T) {
|
||||||
|
components := doc.Components.Value
|
||||||
securitySchemes := components.SecuritySchemes.Value
|
securitySchemes := components.SecuritySchemes.Value
|
||||||
assert.Len(t, securitySchemes, 3)
|
assert.Len(t, securitySchemes, 3)
|
||||||
|
|
||||||
@@ -283,3 +286,113 @@ func TestCreateDocument_Components_Schemas(t *testing.T) {
|
|||||||
assert.Equal(t, "modify burgers and stuff", readScope.Value)
|
assert.Equal(t, "modify burgers and stuff", readScope.Value)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCreateDocument_Components_Responses(t *testing.T) {
|
||||||
|
components := doc.Components.Value
|
||||||
|
responses := components.Responses.Value
|
||||||
|
assert.Len(t, responses, 1)
|
||||||
|
|
||||||
|
dressingResponse := components.FindResponse("DressingResponse")
|
||||||
|
assert.NotNil(t, dressingResponse.Value)
|
||||||
|
assert.Equal(t, "all the dressings for a burger.", dressingResponse.Value.Description.Value)
|
||||||
|
assert.Len(t, dressingResponse.Value.Content.Value, 1)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateDocument_Components_Examples(t *testing.T) {
|
||||||
|
components := doc.Components.Value
|
||||||
|
examples := components.Examples.Value
|
||||||
|
assert.Len(t, examples, 1)
|
||||||
|
|
||||||
|
quarterPounder := components.FindExample("QuarterPounder")
|
||||||
|
assert.NotNil(t, quarterPounder.Value)
|
||||||
|
assert.Equal(t, "A juicy two hander sammich", quarterPounder.Value.Summary.Value)
|
||||||
|
assert.NotNil(t, quarterPounder.Value.Value.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateDocument_Components_RequestBodies(t *testing.T) {
|
||||||
|
components := doc.Components.Value
|
||||||
|
requestBodies := components.RequestBodies.Value
|
||||||
|
assert.Len(t, requestBodies, 1)
|
||||||
|
|
||||||
|
burgerRequest := components.FindRequestBody("BurgerRequest")
|
||||||
|
assert.NotNil(t, burgerRequest.Value)
|
||||||
|
assert.Equal(t, "Give us the new burger!", burgerRequest.Value.Description.Value)
|
||||||
|
assert.Len(t, burgerRequest.Value.Content.Value, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateDocument_Components_Headers(t *testing.T) {
|
||||||
|
components := doc.Components.Value
|
||||||
|
headers := components.Headers.Value
|
||||||
|
assert.Len(t, headers, 1)
|
||||||
|
|
||||||
|
useOil := components.FindHeader("UseOil")
|
||||||
|
assert.NotNil(t, useOil.Value)
|
||||||
|
assert.Equal(t, "this is a header", useOil.Value.Description.Value)
|
||||||
|
assert.Equal(t, "string", useOil.Value.Schema.Value.Type.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateDocument_Components_Links(t *testing.T) {
|
||||||
|
components := doc.Components.Value
|
||||||
|
links := components.Links.Value
|
||||||
|
assert.Len(t, links, 2)
|
||||||
|
|
||||||
|
locateBurger := components.FindLink("LocateBurger")
|
||||||
|
assert.NotNil(t, locateBurger.Value)
|
||||||
|
assert.Equal(t, "Go and get a tasty burger", locateBurger.Value.Description.Value)
|
||||||
|
|
||||||
|
anotherLocateBurger := components.FindLink("AnotherLocateBurger")
|
||||||
|
assert.NotNil(t, anotherLocateBurger.Value)
|
||||||
|
assert.Equal(t, "Go and get another really tasty burger", anotherLocateBurger.Value.Description.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateDocument_Doc_Security(t *testing.T) {
|
||||||
|
security := doc.Security.Value
|
||||||
|
assert.NotNil(t, security)
|
||||||
|
assert.Len(t, security.Value, 1)
|
||||||
|
|
||||||
|
oAuth := security.FindRequirement("OAuthScheme")
|
||||||
|
assert.Len(t, oAuth, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateDocument_Callbacks(t *testing.T) {
|
||||||
|
callbacks := doc.Components.Value.Callbacks.Value
|
||||||
|
assert.Len(t, callbacks, 1)
|
||||||
|
|
||||||
|
bCallback := doc.Components.Value.FindCallback("BurgerCallback")
|
||||||
|
assert.NotNil(t, bCallback.Value)
|
||||||
|
assert.Len(t, callbacks, 1)
|
||||||
|
|
||||||
|
exp := bCallback.Value.FindExpression("{$request.query.queryUrl}")
|
||||||
|
assert.NotNil(t, exp.Value)
|
||||||
|
assert.NotNil(t, exp.Value.Post.Value)
|
||||||
|
assert.Equal(t, "Callback payload", exp.Value.Post.Value.RequestBody.Value.Description.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateDocument_Component_Discriminator(t *testing.T) {
|
||||||
|
|
||||||
|
components := doc.Components.Value
|
||||||
|
dsc := components.FindSchema("Drink").Value.Discriminator.Value
|
||||||
|
assert.NotNil(t, dsc)
|
||||||
|
assert.Equal(t, "drinkType", dsc.PropertyName.Value)
|
||||||
|
assert.Equal(t, "some value", dsc.FindMappingValue("drink").Value)
|
||||||
|
assert.Nil(t, dsc.FindMappingValue("don't exist"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateDocument_CheckAdditionalProperties_Schema(t *testing.T) {
|
||||||
|
components := doc.Components.Value
|
||||||
|
d := components.FindSchema("Dressing")
|
||||||
|
assert.NotNil(t, d.Value.AdditionalProperties.Value)
|
||||||
|
if n, ok := d.Value.AdditionalProperties.Value.(*v3.Schema); ok {
|
||||||
|
assert.Equal(t, "something in here.", n.Description.Value)
|
||||||
|
} else {
|
||||||
|
assert.Fail(t, "should be a schema")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateDocument_CheckAdditionalProperties_Bool(t *testing.T) {
|
||||||
|
components := doc.Components.Value
|
||||||
|
d := components.FindSchema("Drink")
|
||||||
|
assert.NotNil(t, d.Value.AdditionalProperties.Value)
|
||||||
|
assert.True(t, d.Value.AdditionalProperties.Value.(bool))
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,6 +12,10 @@ info:
|
|||||||
name: pb33f
|
name: pb33f
|
||||||
url: https://pb33f.io/made-up
|
url: https://pb33f.io/made-up
|
||||||
version: "1.2"
|
version: "1.2"
|
||||||
|
security:
|
||||||
|
- OAuthScheme:
|
||||||
|
- read:burgers
|
||||||
|
- write:burgers
|
||||||
tags:
|
tags:
|
||||||
- name: "Burgers"
|
- name: "Burgers"
|
||||||
description: "All kinds of yummy burgers."
|
description: "All kinds of yummy burgers."
|
||||||
@@ -66,29 +70,12 @@ paths:
|
|||||||
summary: Create a new burger
|
summary: Create a new burger
|
||||||
description: A new burger for our menu, yummy yum yum.
|
description: A new burger for our menu, yummy yum yum.
|
||||||
requestBody:
|
requestBody:
|
||||||
description: Give us the new burger!
|
$ref: '#/components/requestBodies/BurgerRequest'
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/Burger'
|
|
||||||
examples:
|
|
||||||
pbjBurger:
|
|
||||||
summary: A horrible, nutty, sticky mess.
|
|
||||||
value:
|
|
||||||
name: Peanut And Jelly
|
|
||||||
numPatties: 3
|
|
||||||
cakeBurger:
|
|
||||||
summary: A sickly, sweet, atrocity
|
|
||||||
value:
|
|
||||||
name: Chocolate Cake Burger
|
|
||||||
numPatties: 5
|
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
headers:
|
headers:
|
||||||
UseOil:
|
UseOil:
|
||||||
description: this is a header
|
$ref: '#/components/headers/UseOil'
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
description: A tasty burger for you to eat.
|
description: A tasty burger for you to eat.
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
@@ -96,10 +83,7 @@ paths:
|
|||||||
$ref: '#/components/schemas/Burger'
|
$ref: '#/components/schemas/Burger'
|
||||||
examples:
|
examples:
|
||||||
quarterPounder:
|
quarterPounder:
|
||||||
summary: a yummy tasty two patty burger, filled with beefy goodness.
|
$ref: '#/components/examples/QuarterPounder'
|
||||||
value:
|
|
||||||
name: Quarter Pounder with Cheese
|
|
||||||
numPatties: 1
|
|
||||||
filetOFish:
|
filetOFish:
|
||||||
summary: a cripsy fish sammich filled with ocean goodness.
|
summary: a cripsy fish sammich filled with ocean goodness.
|
||||||
value:
|
value:
|
||||||
@@ -107,15 +91,9 @@ paths:
|
|||||||
numPatties: 1
|
numPatties: 1
|
||||||
links:
|
links:
|
||||||
LocateBurger:
|
LocateBurger:
|
||||||
operationId: locateBurger
|
$ref: '#/components/links/LocateBurger'
|
||||||
parameters:
|
|
||||||
burgerId: '$response.body#/id'
|
|
||||||
description: Go and get a tasty burger
|
|
||||||
AnotherLocateBurger:
|
AnotherLocateBurger:
|
||||||
operationId: locateBurger
|
$ref: '#/components/links/AnotherLocateBurger'
|
||||||
parameters:
|
|
||||||
burgerId: '$response.body#/id'
|
|
||||||
description: Go and get a another really tasty burger
|
|
||||||
"500":
|
"500":
|
||||||
description: Unexpected error creating a new burger. Sorry.
|
description: Unexpected error creating a new burger. Sorry.
|
||||||
content:
|
content:
|
||||||
@@ -149,17 +127,7 @@ paths:
|
|||||||
get:
|
get:
|
||||||
callbacks:
|
callbacks:
|
||||||
burgerCallback:
|
burgerCallback:
|
||||||
"{$request.query.queryUrl}":
|
$ref: '#/components/callbacks/BurgerCallback'
|
||||||
post:
|
|
||||||
requestBody:
|
|
||||||
description: Callback payload
|
|
||||||
content:
|
|
||||||
'application/json':
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/SomePayload'
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
description: callback successfully processed
|
|
||||||
operationId: locateBurger
|
operationId: locateBurger
|
||||||
tags:
|
tags:
|
||||||
- "Burgers"
|
- "Burgers"
|
||||||
@@ -177,10 +145,7 @@ paths:
|
|||||||
$ref: '#/components/schemas/Burger'
|
$ref: '#/components/schemas/Burger'
|
||||||
examples:
|
examples:
|
||||||
quarterPounder:
|
quarterPounder:
|
||||||
summary: A juicy two handler sammich
|
$ref: '#/components/examples/QuarterPounder'
|
||||||
value:
|
|
||||||
name: Quarter Pounder with Cheese
|
|
||||||
numPatties: 1
|
|
||||||
filetOFish:
|
filetOFish:
|
||||||
summary: A tasty treat from the sea
|
summary: A tasty treat from the sea
|
||||||
value:
|
value:
|
||||||
@@ -231,15 +196,7 @@ paths:
|
|||||||
required: true
|
required: true
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: all the dressings for a burger.
|
$ref: '#/components/responses/DressingResponse'
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: '#/components/schemas/Dressing'
|
|
||||||
example:
|
|
||||||
- name: Thousand Island
|
|
||||||
"404":
|
"404":
|
||||||
description: Cannot find your burger in which to list dressings. Sorry
|
description: Cannot find your burger in which to list dressings. Sorry
|
||||||
content:
|
content:
|
||||||
@@ -331,6 +288,70 @@ paths:
|
|||||||
example:
|
example:
|
||||||
message: "failed looking up all dressings, something went wrong."
|
message: "failed looking up all dressings, something went wrong."
|
||||||
components:
|
components:
|
||||||
|
callbacks:
|
||||||
|
BurgerCallback:
|
||||||
|
"{$request.query.queryUrl}":
|
||||||
|
post:
|
||||||
|
requestBody:
|
||||||
|
description: Callback payload
|
||||||
|
content:
|
||||||
|
'application/json':
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/SomePayload'
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: callback successfully processes
|
||||||
|
links:
|
||||||
|
LocateBurger:
|
||||||
|
operationId: locateBurger
|
||||||
|
parameters:
|
||||||
|
burgerId: '$response.body#/id'
|
||||||
|
description: Go and get a tasty burger
|
||||||
|
AnotherLocateBurger:
|
||||||
|
operationId: locateBurger
|
||||||
|
parameters:
|
||||||
|
burgerId: '$response.body#/id'
|
||||||
|
description: Go and get another really tasty burger
|
||||||
|
headers:
|
||||||
|
UseOil:
|
||||||
|
description: this is a header
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
requestBodies:
|
||||||
|
BurgerRequest:
|
||||||
|
description: Give us the new burger!
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Burger'
|
||||||
|
examples:
|
||||||
|
pbjBurger:
|
||||||
|
summary: A horrible, nutty, sticky mess.
|
||||||
|
value:
|
||||||
|
name: Peanut And Jelly
|
||||||
|
numPatties: 3
|
||||||
|
cakeBurger:
|
||||||
|
summary: A sickly, sweet, atrocity
|
||||||
|
value:
|
||||||
|
name: Chocolate Cake Burger
|
||||||
|
numPatties: 5
|
||||||
|
examples:
|
||||||
|
QuarterPounder:
|
||||||
|
summary: A juicy two hander sammich
|
||||||
|
value:
|
||||||
|
name: Quarter Pounder with Cheese
|
||||||
|
numPatties: 1
|
||||||
|
responses:
|
||||||
|
DressingResponse:
|
||||||
|
description: all the dressings for a burger.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/Dressing'
|
||||||
|
example:
|
||||||
|
- name: Thousand Island
|
||||||
securitySchemes:
|
securitySchemes:
|
||||||
APIKeyScheme:
|
APIKeyScheme:
|
||||||
type: apiKey
|
type: apiKey
|
||||||
@@ -463,6 +484,9 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
description: The name of your dressing you can pick up from the menu
|
description: The name of your dressing you can pick up from the menu
|
||||||
example: Cheese
|
example: Cheese
|
||||||
|
additionalProperties:
|
||||||
|
type: object
|
||||||
|
description: something in here.
|
||||||
Drink:
|
Drink:
|
||||||
type: object
|
type: object
|
||||||
description: a frosty cold beverage can be coke or sprite
|
description: a frosty cold beverage can be coke or sprite
|
||||||
@@ -481,4 +505,8 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
description: what size man? S/M/L
|
description: what size man? S/M/L
|
||||||
example: M
|
example: M
|
||||||
|
additionalProperties: true
|
||||||
|
discriminator:
|
||||||
|
propertyName: drinkType
|
||||||
|
mapping:
|
||||||
|
drink: some value
|
||||||
Reference in New Issue
Block a user