Building out highlevel model

bit by bit, step by step.
This commit is contained in:
Dave Shanley
2022-08-19 10:01:16 -04:00
parent 0bd119f152
commit 0c2c008902
19 changed files with 376 additions and 18 deletions

View File

@@ -3,7 +3,10 @@
package v3
import low "github.com/pb33f/libopenapi/datamodel/low/3.0"
import (
"github.com/pb33f/libopenapi/datamodel/high"
low "github.com/pb33f/libopenapi/datamodel/low/3.0"
)
type Components struct {
Schemas map[string]*Schema
@@ -19,6 +22,24 @@ type Components struct {
low *low.Components
}
func NewComponents(comp *low.Components) *Components {
c := new(Components)
c.low = comp
c.Extensions = high.ExtractExtensions(comp.Extensions)
callbacks := make(map[string]*Callback)
links := make(map[string]*Link)
for k, v := range comp.Callbacks.Value {
callbacks[k.Value] = NewCallback(v.Value)
}
c.Callbacks = callbacks
for k, v := range comp.Links.Value {
links[k.Value] = NewLink(v.Value)
}
c.Links = links
return c
}
func (c *Components) GoLow() *low.Components {
return c.low
}

View File

@@ -11,6 +11,18 @@ type Discriminator struct {
low *low.Discriminator
}
func NewDiscriminator(disc *low.Discriminator) *Discriminator {
d := new(Discriminator)
d.low = disc
d.PropertyName = disc.PropertyName.Value
mapping := make(map[string]string)
for k, v := range disc.Mapping {
mapping[k.Value] = v.Value
}
d.Mapping = mapping
return d
}
func (d *Discriminator) GoLow() *low.Discriminator {
return d.low
}

View File

@@ -3,7 +3,10 @@
package v3
import low "github.com/pb33f/libopenapi/datamodel/low/3.0"
import (
"github.com/pb33f/libopenapi/datamodel/high"
low "github.com/pb33f/libopenapi/datamodel/low/3.0"
)
type Document struct {
Version string
@@ -33,6 +36,11 @@ func NewDocument(document *low.Document) *Document {
tags = append(tags, NewTag(tag.Value))
}
d.Tags = tags
if !document.ExternalDocs.IsEmpty() {
d.ExternalDocs = NewExternalDoc(document.ExternalDocs.Value)
}
d.Extensions = high.ExtractExtensions(document.Extensions)
d.Components = NewComponents(document.Components.Value)
return d
}

View File

@@ -29,6 +29,16 @@ func BenchmarkNewDocument(b *testing.B) {
}
}
func TestNewDocument_Extensions(t *testing.T) {
h := NewDocument(doc)
assert.Equal(t, "darkside", h.Extensions["x-something-something"])
}
func TestNewDocument_ExternalDocs(t *testing.T) {
h := NewDocument(doc)
assert.Equal(t, "https://pb33f.io", h.ExternalDocs.URL)
}
func TestNewDocument_Info(t *testing.T) {
highDoc := NewDocument(doc)
assert.Equal(t, "3.0.1", highDoc.Version)
@@ -45,6 +55,18 @@ func TestNewDocument_Info(t *testing.T) {
assert.Equal(t, 1, wentLow.Version.ValueNode.Line)
assert.Equal(t, 3, wentLow.Info.Value.Title.KeyNode.Line)
wentLower := highDoc.Info.Contact.GoLow()
assert.Equal(t, 8, wentLower.Name.ValueNode.Line)
assert.Equal(t, 11, wentLower.Name.ValueNode.Column)
wentLowAgain := highDoc.Info.GoLow()
assert.Equal(t, 3, wentLowAgain.Title.ValueNode.Line)
assert.Equal(t, 10, wentLowAgain.Title.ValueNode.Column)
wentOnceMore := highDoc.Info.License.GoLow()
assert.Equal(t, 12, wentOnceMore.Name.ValueNode.Line)
assert.Equal(t, 11, wentOnceMore.Name.ValueNode.Column)
}
func TestNewDocument_Servers(t *testing.T) {
@@ -67,10 +89,45 @@ func TestNewDocument_Servers(t *testing.T) {
assert.Equal(t, 5, wentLow.Servers.Value[0].Value.Description.KeyNode.Column)
assert.Equal(t, 45, wentLow.Servers.Value[0].Value.Description.ValueNode.Line)
assert.Equal(t, 18, wentLow.Servers.Value[0].Value.Description.ValueNode.Column)
// holy shit! the perfect Golang OpenAPI Model! high and low! fuck yeah!
wentLower := h.Servers[0].GoLow()
assert.Equal(t, 45, wentLower.Description.ValueNode.Line)
assert.Equal(t, 18, wentLower.Description.ValueNode.Column)
wentLowest := h.Servers[0].Variables["scheme"].GoLow()
assert.Equal(t, 50, wentLowest.Description.ValueNode.Line)
assert.Equal(t, 22, wentLowest.Description.ValueNode.Column)
}
func TestNewDocument_Tags(t *testing.T) {
h := NewDocument(doc)
assert.Len(t, h.Tags, 2)
assert.Equal(t, "Burgers", h.Tags[0].Name)
assert.Equal(t, "All kinds of yummy burgers.", h.Tags[0].Description)
assert.Equal(t, "Find out more", h.Tags[0].ExternalDocs.Description)
assert.Equal(t, "https://pb33f.io", h.Tags[0].ExternalDocs.URL)
assert.Equal(t, "somethingSpecial", h.Tags[0].Extensions["x-internal-ting"])
assert.Equal(t, int64(1), h.Tags[0].Extensions["x-internal-tong"])
assert.Equal(t, 1.2, h.Tags[0].Extensions["x-internal-tang"])
assert.True(t, h.Tags[0].Extensions["x-internal-tung"].(bool))
wentLow := h.Tags[1].GoLow()
assert.Equal(t, 39, wentLow.Description.KeyNode.Line)
assert.Equal(t, 5, wentLow.Description.KeyNode.Column)
wentLower := h.Tags[0].ExternalDocs.GoLow()
assert.Equal(t, 23, wentLower.Description.ValueNode.Line)
assert.Equal(t, 20, wentLower.Description.ValueNode.Column)
}
func TestNewDocument_Components(t *testing.T) {
h := NewDocument(doc)
assert.Len(t, h.Components.Links, 2)
assert.Equal(t, "locateBurger", h.Components.Links["LocateBurger"].OperationId)
assert.Equal(t, "$response.body#/id", h.Components.Links["LocateBurger"].Parameters["burgerId"])
assert.Len(t, h.Components.Callbacks, 1)
//assert.Equal(t, "Callback payload",
// h.Components.Callbacks["BurgerCallback"].Expression["{$request.query.queryUrl}"].Post.RequestBody.Description)
}

View File

@@ -14,6 +14,17 @@ type Encoding struct {
low *low.Encoding
}
func NewEncoding(encoding *low.Encoding) *Encoding {
e := new(Encoding)
e.low = encoding
e.ContentType = encoding.ContentType.Value
e.Style = encoding.Style.Value
e.Explode = encoding.Explode.Value
e.AllowReserved = encoding.AllowReserved.Value
//e.Headers
return e
}
func (e *Encoding) GoLow() *low.Encoding {
return e.low
}

View File

@@ -3,7 +3,11 @@
package v3
import low "github.com/pb33f/libopenapi/datamodel/low/3.0"
import (
"github.com/pb33f/libopenapi/datamodel/high"
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
low "github.com/pb33f/libopenapi/datamodel/low/3.0"
)
type Example struct {
Summary string
@@ -14,6 +18,25 @@ type Example struct {
low *low.Example
}
func NewExample(example *low.Example) *Example {
e := new(Example)
e.low = example
e.Summary = example.Summary.Value
e.Description = example.Description.Value
e.Value = example.Value
e.ExternalValue = example.ExternalValue.Value
e.Extensions = high.ExtractExtensions(example.Extensions)
return e
}
func (e *Example) GoLow() *low.Example {
return e.low
}
func ExtractExamples(elements map[lowmodel.KeyReference[string]]lowmodel.ValueReference[*low.Example]) map[string]*Example {
extracted := make(map[string]*Example)
for k, v := range elements {
extracted[k.Value] = NewExample(v.Value)
}
return extracted
}

View File

@@ -21,6 +21,19 @@ type Header struct {
low *low.Header
}
func NewHeader(header *low.Header) *Header {
h := new(Header)
h.low = header
h.Description = header.Description.Value
h.Required = header.Required.Value
h.Deprecated = header.Deprecated.Value
h.AllowEmptyValue = header.AllowEmptyValue.Value
h.Style = header.Style.Value
// TODO continue this.
return h
}
func (h *Header) GoLow() *low.Header {
return h.low
}

View File

@@ -3,7 +3,10 @@
package v3
import low "github.com/pb33f/libopenapi/datamodel/low/3.0"
import (
"github.com/pb33f/libopenapi/datamodel/high"
low "github.com/pb33f/libopenapi/datamodel/low/3.0"
)
type Link struct {
OperationRef string
@@ -16,6 +19,25 @@ type Link struct {
low *low.Link
}
func NewLink(link *low.Link) *Link {
l := new(Link)
l.low = link
l.OperationRef = link.OperationRef.Value
l.OperationId = link.OperationId.Value
params := make(map[string]string)
for k, v := range link.Parameters.Value {
params[k.Value] = v.Value
}
l.Parameters = params
l.RequestBody = link.RequestBody.Value
l.Description = link.Description.Value
if link.Server.Value != nil {
l.Server = NewServer(link.Server.Value)
}
l.Extensions = high.ExtractExtensions(link.Extensions)
return l
}
func (l *Link) GoLow() *low.Link {
return l.low
}

View File

@@ -3,7 +3,10 @@
package v3
import low "github.com/pb33f/libopenapi/datamodel/low/3.0"
import (
"github.com/pb33f/libopenapi/datamodel/high"
low "github.com/pb33f/libopenapi/datamodel/low/3.0"
)
type MediaType struct {
Schema *Schema
@@ -14,6 +17,21 @@ type MediaType struct {
low *low.MediaType
}
func NewMediaType(mediaType *low.MediaType) *MediaType {
m := new(MediaType)
m.low = mediaType
if !mediaType.Schema.IsEmpty() {
m.Schema = NewSchema(mediaType.Schema.Value)
}
m.Example = mediaType.Example
m.Examples = ExtractExamples(mediaType.Examples.Value)
m.Extensions = high.ExtractExtensions(mediaType.Extensions)
// TODO continue this.
return m
}
func (m *MediaType) GoLow() *low.MediaType {
return m.low
}

View File

@@ -22,6 +22,23 @@ type Operation struct {
low *low.Operation
}
func NewOperation(operation *low.Operation) *Operation {
o := new(Operation)
o.low = operation
var tags []string
for i := range operation.Tags.Value {
tags = append(tags, operation.Tags.Value[i].Value)
}
o.Tags = tags
o.Summary = operation.Summary.Value
o.Description = operation.Description.Value
o.ExternalDocs = NewExternalDoc(operation.ExternalDocs.Value)
o.OperationId = operation.OperationId.Value
// TODO: come back and finish.
return o
}
func (o *Operation) GoLow() *low.Operation {
return o.low
}

View File

@@ -3,7 +3,9 @@
package v3
import low "github.com/pb33f/libopenapi/datamodel/low/3.0"
import (
low "github.com/pb33f/libopenapi/datamodel/low/3.0"
)
type Parameter struct {
Name string
@@ -23,6 +25,24 @@ type Parameter struct {
low *low.Parameter
}
func NewParameter(param *low.Parameter) *Parameter {
p := new(Parameter)
p.low = param
p.Name = param.Name.Value
p.In = param.In.Value
p.Description = param.Description.Value
p.Deprecated = param.Deprecated.Value
p.AllowEmptyValue = param.AllowEmptyValue.Value
p.Style = param.Style.Value
p.Explode = param.Explode.Value
p.AllowReserved = param.AllowReserved.Value
p.Schema = NewSchema(param.Schema.Value)
p.Example = param.Example.Value
p.Examples = ExtractExamples(param.Examples.Value)
return p
}
func (p *Parameter) GoLow() *low.Parameter {
return p.low
}

View File

@@ -22,10 +22,17 @@ type PathItem struct {
low *low.PathItem
}
func NewPathItem(lowPathItem *low.PathItem) *PathItem {
func NewPathItem(pathItem *low.PathItem) *PathItem {
pi := new(PathItem)
pi.Description = lowPathItem.Description.Value
pi.Summary = lowPathItem.Summary.Value
pi.Description = pathItem.Description.Value
pi.Summary = pathItem.Summary.Value
var servers []*Server
for _, ser := range pathItem.Servers.Value {
servers = append(servers, NewServer(ser.Value))
}
pi.Servers = servers
return pi
}

View File

@@ -3,7 +3,11 @@
package v3
import low "github.com/pb33f/libopenapi/datamodel/low/3.0"
import (
"github.com/pb33f/libopenapi/datamodel/high"
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
low "github.com/pb33f/libopenapi/datamodel/low/3.0"
)
type Schema struct {
Title string
@@ -45,6 +49,90 @@ type Schema struct {
low *low.Schema
}
func NewSchema(schema *low.Schema) *Schema {
s := new(Schema)
s.low = schema
s.Title = schema.Title.Value
s.MultipleOf = schema.MultipleOf.Value
s.Maximum = schema.Maximum.Value
s.ExclusiveMaximum = schema.ExclusiveMaximum.Value
s.Minimum = schema.Minimum.Value
s.ExclusiveMinimum = schema.ExclusiveMinimum.Value
s.MaxLength = schema.MaxLength.Value
s.MinLength = schema.MinLength.Value
s.Pattern = schema.Pattern.Value
s.Format = schema.Format.Value
s.MaxItems = schema.MaxItems.Value
s.MinItems = schema.MinItems.Value
s.MaxProperties = schema.MaxProperties.Value
s.MinProperties = schema.MinProperties.Value
s.Type = schema.Type.Value
s.AdditionalProperties = schema.AdditionalProperties.Value
s.Description = schema.Description.Value
s.Default = schema.Default.Value
s.Nullable = schema.Nullable.Value
s.ReadOnly = schema.ReadOnly.Value
s.WriteOnly = schema.WriteOnly.Value
s.Example = schema.Example.Value
s.Deprecated = schema.Deprecated.Value
s.Extensions = high.ExtractExtensions(schema.Extensions)
if !schema.Discriminator.IsEmpty() {
s.Discriminator = NewDiscriminator(schema.Discriminator.Value)
}
if !schema.XML.IsEmpty() {
s.XML = NewXML(schema.XML.Value)
}
if !schema.ExternalDocs.IsEmpty() {
s.ExternalDocs = NewExternalDoc(schema.ExternalDocs.Value)
}
var req []string
for i := range schema.Required.Value {
req = append(req, schema.Required.Value[i].Value)
}
s.Required = req
var enum []string
for i := range schema.Enum.Value {
enum = append(req, schema.Enum.Value[i].Value)
}
s.Enum = enum
totalItems := len(schema.AllOf.Value) + len(schema.OneOf.Value) + len(schema.AnyOf.Value) + len(schema.Not.Value) +
len(schema.Items.Value)
completedChan := make(chan bool)
buildOutSchema := func(schemas []lowmodel.NodeReference[*low.Schema], items *[]*Schema, doneChan chan bool) {
for v := range schemas {
*items = append(*items, NewSchema(schemas[v].Value))
}
doneChan <- true
}
allOf := make([]*Schema, len(schema.AllOf.Value))
oneOf := make([]*Schema, len(schema.OneOf.Value))
anyOf := make([]*Schema, len(schema.AnyOf.Value))
not := make([]*Schema, len(schema.Not.Value))
items := make([]*Schema, len(schema.Items.Value))
go buildOutSchema(schema.AllOf.Value, &allOf, completedChan)
go buildOutSchema(schema.AnyOf.Value, &anyOf, completedChan)
go buildOutSchema(schema.OneOf.Value, &oneOf, completedChan)
go buildOutSchema(schema.Not.Value, &not, completedChan)
go buildOutSchema(schema.Items.Value, &items, completedChan)
complete := 0
for complete < totalItems {
select {
case <-completedChan:
complete++
}
}
return s
}
func (s *Schema) GoLow() *low.Schema {
return s.low
}

View File

@@ -10,6 +10,25 @@ type SecurityRequirement struct {
low *low.SecurityRequirement
}
func NewSecurityRequirement(req *low.SecurityRequirement) *SecurityRequirement {
r := new(SecurityRequirement)
r.low = req
values := make([]map[string][]string, len(req.ValueRequirements))
for i := range req.ValueRequirements {
valmap := make(map[string][]string)
for k, v := range req.ValueRequirements[i].Value {
var mItems []string
for h := range v {
mItems = append(mItems, v[h].Value)
}
valmap[k.Value] = mItems
}
values = append(values, valmap)
}
r.ValueRequirements = values
return r
}
func (s *SecurityRequirement) GoLow() *low.SecurityRequirement {
return s.low
}

View File

@@ -3,7 +3,10 @@
package v3
import low "github.com/pb33f/libopenapi/datamodel/low/3.0"
import (
"github.com/pb33f/libopenapi/datamodel/high"
low "github.com/pb33f/libopenapi/datamodel/low/3.0"
)
type XML struct {
Name string
@@ -15,6 +18,18 @@ type XML struct {
low *low.XML
}
func NewXML(xml *low.XML) *XML {
x := new(XML)
x.low = xml
x.Name = xml.Name.Value
x.Namespace = xml.Namespace.Value
x.Prefix = xml.Namespace.Value
x.Attribute = xml.Attribute.Value
x.Wrapped = xml.Wrapped.Value
x.Extensions = high.ExtractExtensions(xml.Extensions)
return x
}
func (x *XML) GoLow() *low.XML {
return x.low
}

View File

@@ -19,6 +19,8 @@ func CreateDocument(info *datamodel.SpecInfo) (*Document, []error) {
var wg sync.WaitGroup
var errors []error
doc.Extensions = low.ExtractExtensions(info.RootNode.Content[0])
var runExtraction = func(info *datamodel.SpecInfo, doc *Document, idx *index.SpecIndex,
runFunc func(i *datamodel.SpecInfo, d *Document, idx *index.SpecIndex) error,
ers *[]error,

View File

@@ -17,6 +17,6 @@ type Document struct {
Security low.NodeReference[*SecurityRequirement]
Tags low.NodeReference[[]low.ValueReference[*Tag]]
ExternalDocs low.NodeReference[*ExternalDoc]
Extensions map[low.NodeReference[string]]low.NodeReference[any]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
Index *index.SpecIndex
}

View File

@@ -90,10 +90,11 @@ func (sr *SecurityRequirement) Build(root *yaml.Node, idx *index.SpecIndex) erro
Value: currSec.Value,
KeyNode: currSec,
}] = dat
requirements = append(requirements, low.ValueReference[map[low.KeyReference[string]][]low.ValueReference[string]]{
Value: res,
ValueNode: n,
})
requirements = append(requirements,
low.ValueReference[map[low.KeyReference[string]][]low.ValueReference[string]]{
Value: res,
ValueNode: n,
})
}
}
sr.ValueRequirements = requirements

View File

@@ -511,3 +511,7 @@ components:
SomePayload:
type: string
description: some kind of payload for something.
x-something-something: darkside
externalDocs:
description: "Find out more information about our products)"
url: "https://pb33f.io"