mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-08 12:37:49 +00:00
High-level base documentation is complete.
Examples and every model completed, 1/6th of the way through models.
This commit is contained in:
@@ -4,239 +4,270 @@
|
|||||||
package base
|
package base
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/high"
|
"github.com/pb33f/libopenapi/datamodel/high"
|
||||||
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
|
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Schema represents a
|
// Schema represents a JSON Schema that support Swagger, OpenAPI 3 and OpenAPI 3.1
|
||||||
|
//
|
||||||
|
// Until 3.1 OpenAPI had a strange relationship with JSON Schema. It's been a super-set/sub-set
|
||||||
|
// mix, which has been confusing. So, instead of building a bunch of different models, we have compressed
|
||||||
|
// all variations into a single model that makes it easy to support multiple spec types.
|
||||||
|
//
|
||||||
|
// - v2 schema: https://swagger.io/specification/v2/#schemaObject
|
||||||
|
// - v3 schema: https://swagger.io/specification/#schema-object
|
||||||
|
// - v3.1 schema: https://spec.openapis.org/oas/v3.1.0#schema-object
|
||||||
type Schema struct {
|
type Schema struct {
|
||||||
SchemaTypeRef string
|
|
||||||
Title string
|
// 3.1 only, used to define a dialect for this schema, label is '$schema'.
|
||||||
MultipleOf int64
|
SchemaTypeRef string
|
||||||
Maximum int64
|
|
||||||
ExclusiveMaximumBool bool
|
// In versions 2 and 3.0, this ExclusiveMaximum can only be a boolean.
|
||||||
ExclusiveMaximum int64
|
ExclusiveMaximumBool bool
|
||||||
Minimum int64
|
|
||||||
ExclusiveMinimum int64
|
// In version 3.1, ExclusiveMaximum is an integer.
|
||||||
ExclusiveMinimumBool bool
|
ExclusiveMaximum int64
|
||||||
MaxLength int64
|
|
||||||
MinLength int64
|
// In versions 2 and 3.0, this ExclusiveMinimum can only be a boolean.
|
||||||
Pattern string
|
ExclusiveMinimum int64
|
||||||
Format string
|
|
||||||
MaxItems int64
|
// In version 3.1, ExclusiveMinimum is an integer.
|
||||||
MinItems int64
|
ExclusiveMinimumBool bool
|
||||||
UniqueItems int64
|
|
||||||
MaxProperties int64
|
// In versions 2 and 3.0, this Type is a single value, so array will only ever have one value
|
||||||
MinProperties int64
|
// in version 3.1, Type can be multiple values
|
||||||
Required []string
|
Type []string
|
||||||
Enum []string
|
|
||||||
Type []string
|
// Schemas are resolved on demand using a SchemaProxy
|
||||||
AllOf []*SchemaProxy
|
AllOf []*SchemaProxy
|
||||||
OneOf []*SchemaProxy
|
|
||||||
AnyOf []*SchemaProxy
|
// Polymorphic Schemas are only available in version 3+
|
||||||
Not []*SchemaProxy
|
OneOf []*SchemaProxy
|
||||||
Items []*SchemaProxy
|
AnyOf []*SchemaProxy
|
||||||
Properties map[string]*SchemaProxy
|
Discriminator *Discriminator
|
||||||
AdditionalProperties any
|
|
||||||
Description string
|
// in 3.1 examples can be an array (which is recommended)
|
||||||
Default any
|
Examples []any
|
||||||
Nullable bool
|
|
||||||
Discriminator *Discriminator
|
// Compatible with all versions
|
||||||
ReadOnly bool
|
Not []*SchemaProxy
|
||||||
WriteOnly bool
|
Items []*SchemaProxy
|
||||||
XML *XML
|
Properties map[string]*SchemaProxy
|
||||||
ExternalDocs *ExternalDoc
|
Title string
|
||||||
Example any
|
MultipleOf int64
|
||||||
Examples []any
|
Maximum int64
|
||||||
Deprecated bool
|
Minimum int64
|
||||||
Extensions map[string]any
|
MaxLength int64
|
||||||
low *base.Schema
|
MinLength int64
|
||||||
|
Pattern string
|
||||||
|
Format string
|
||||||
|
MaxItems int64
|
||||||
|
MinItems int64
|
||||||
|
UniqueItems int64
|
||||||
|
MaxProperties int64
|
||||||
|
MinProperties int64
|
||||||
|
Required []string
|
||||||
|
Enum []string
|
||||||
|
AdditionalProperties any
|
||||||
|
Description string
|
||||||
|
Default any
|
||||||
|
Nullable bool
|
||||||
|
ReadOnly bool
|
||||||
|
WriteOnly bool
|
||||||
|
XML *XML
|
||||||
|
ExternalDocs *ExternalDoc
|
||||||
|
Example any
|
||||||
|
Deprecated bool
|
||||||
|
Extensions map[string]any
|
||||||
|
low *base.Schema
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewSchema will create a new high-level schema from a low-level one.
|
||||||
func NewSchema(schema *base.Schema) *Schema {
|
func NewSchema(schema *base.Schema) *Schema {
|
||||||
s := new(Schema)
|
s := new(Schema)
|
||||||
s.low = schema
|
s.low = schema
|
||||||
s.Title = schema.Title.Value
|
s.Title = schema.Title.Value
|
||||||
s.MultipleOf = schema.MultipleOf.Value
|
s.MultipleOf = schema.MultipleOf.Value
|
||||||
s.Maximum = schema.Maximum.Value
|
s.Maximum = schema.Maximum.Value
|
||||||
s.Minimum = schema.Minimum.Value
|
s.Minimum = schema.Minimum.Value
|
||||||
// if we're dealing with a 3.0 spec using a bool
|
// if we're dealing with a 3.0 spec using a bool
|
||||||
if !schema.ExclusiveMaximum.IsEmpty() && schema.ExclusiveMaximum.Value.IsA() {
|
if !schema.ExclusiveMaximum.IsEmpty() && schema.ExclusiveMaximum.Value.IsA() {
|
||||||
s.ExclusiveMaximumBool = schema.ExclusiveMaximum.Value.A
|
s.ExclusiveMaximumBool = schema.ExclusiveMaximum.Value.A
|
||||||
}
|
}
|
||||||
// if we're dealing with a 3.1 spec using an int
|
// if we're dealing with a 3.1 spec using an int
|
||||||
if !schema.ExclusiveMaximum.IsEmpty() && schema.ExclusiveMaximum.Value.IsB() {
|
if !schema.ExclusiveMaximum.IsEmpty() && schema.ExclusiveMaximum.Value.IsB() {
|
||||||
s.ExclusiveMaximum = schema.ExclusiveMaximum.Value.B
|
s.ExclusiveMaximum = schema.ExclusiveMaximum.Value.B
|
||||||
}
|
}
|
||||||
// if we're dealing with a 3.0 spec using a bool
|
// if we're dealing with a 3.0 spec using a bool
|
||||||
if !schema.ExclusiveMinimum.IsEmpty() && schema.ExclusiveMinimum.Value.IsA() {
|
if !schema.ExclusiveMinimum.IsEmpty() && schema.ExclusiveMinimum.Value.IsA() {
|
||||||
s.ExclusiveMinimumBool = schema.ExclusiveMinimum.Value.A
|
s.ExclusiveMinimumBool = schema.ExclusiveMinimum.Value.A
|
||||||
}
|
}
|
||||||
// if we're dealing with a 3.1 spec, using an int
|
// if we're dealing with a 3.1 spec, using an int
|
||||||
if !schema.ExclusiveMinimum.IsEmpty() && schema.ExclusiveMinimum.Value.IsB() {
|
if !schema.ExclusiveMinimum.IsEmpty() && schema.ExclusiveMinimum.Value.IsB() {
|
||||||
s.ExclusiveMinimum = schema.ExclusiveMinimum.Value.B
|
s.ExclusiveMinimum = schema.ExclusiveMinimum.Value.B
|
||||||
}
|
}
|
||||||
s.MaxLength = schema.MaxLength.Value
|
s.MaxLength = schema.MaxLength.Value
|
||||||
s.MinLength = schema.MinLength.Value
|
s.MinLength = schema.MinLength.Value
|
||||||
s.Pattern = schema.Pattern.Value
|
s.Pattern = schema.Pattern.Value
|
||||||
s.Format = schema.Format.Value
|
s.Format = schema.Format.Value
|
||||||
s.MaxItems = schema.MaxItems.Value
|
s.MaxItems = schema.MaxItems.Value
|
||||||
s.MinItems = schema.MinItems.Value
|
s.MinItems = schema.MinItems.Value
|
||||||
s.MaxProperties = schema.MaxProperties.Value
|
s.MaxProperties = schema.MaxProperties.Value
|
||||||
s.MinProperties = schema.MinProperties.Value
|
s.MinProperties = schema.MinProperties.Value
|
||||||
|
|
||||||
// 3.0 spec is a single value
|
// 3.0 spec is a single value
|
||||||
if !schema.Type.IsEmpty() && schema.Type.Value.IsA() {
|
if !schema.Type.IsEmpty() && schema.Type.Value.IsA() {
|
||||||
s.Type = []string{schema.Type.Value.A}
|
s.Type = []string{schema.Type.Value.A}
|
||||||
}
|
}
|
||||||
// 3.1 spec may have multiple values
|
// 3.1 spec may have multiple values
|
||||||
if !schema.Type.IsEmpty() && schema.Type.Value.IsB() {
|
if !schema.Type.IsEmpty() && schema.Type.Value.IsB() {
|
||||||
for i := range schema.Type.Value.B {
|
for i := range schema.Type.Value.B {
|
||||||
s.Type = append(s.Type, schema.Type.Value.B[i].Value)
|
s.Type = append(s.Type, schema.Type.Value.B[i].Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.AdditionalProperties = schema.AdditionalProperties.Value
|
s.AdditionalProperties = schema.AdditionalProperties.Value
|
||||||
s.Description = schema.Description.Value
|
s.Description = schema.Description.Value
|
||||||
s.Default = schema.Default.Value
|
s.Default = schema.Default.Value
|
||||||
s.Nullable = schema.Nullable.Value
|
s.Nullable = schema.Nullable.Value
|
||||||
s.ReadOnly = schema.ReadOnly.Value
|
s.ReadOnly = schema.ReadOnly.Value
|
||||||
s.WriteOnly = schema.WriteOnly.Value
|
s.WriteOnly = schema.WriteOnly.Value
|
||||||
s.Example = schema.Example.Value
|
s.Example = schema.Example.Value
|
||||||
s.Deprecated = schema.Deprecated.Value
|
s.Deprecated = schema.Deprecated.Value
|
||||||
s.Extensions = high.ExtractExtensions(schema.Extensions)
|
s.Extensions = high.ExtractExtensions(schema.Extensions)
|
||||||
if !schema.Discriminator.IsEmpty() {
|
if !schema.Discriminator.IsEmpty() {
|
||||||
s.Discriminator = NewDiscriminator(schema.Discriminator.Value)
|
s.Discriminator = NewDiscriminator(schema.Discriminator.Value)
|
||||||
}
|
}
|
||||||
if !schema.XML.IsEmpty() {
|
if !schema.XML.IsEmpty() {
|
||||||
s.XML = NewXML(schema.XML.Value)
|
s.XML = NewXML(schema.XML.Value)
|
||||||
}
|
}
|
||||||
if !schema.ExternalDocs.IsEmpty() {
|
if !schema.ExternalDocs.IsEmpty() {
|
||||||
s.ExternalDocs = NewExternalDoc(schema.ExternalDocs.Value)
|
s.ExternalDocs = NewExternalDoc(schema.ExternalDocs.Value)
|
||||||
}
|
}
|
||||||
var req []string
|
var req []string
|
||||||
for i := range schema.Required.Value {
|
for i := range schema.Required.Value {
|
||||||
req = append(req, schema.Required.Value[i].Value)
|
req = append(req, schema.Required.Value[i].Value)
|
||||||
}
|
}
|
||||||
s.Required = req
|
s.Required = req
|
||||||
|
|
||||||
var enum []string
|
var enum []string
|
||||||
for i := range schema.Enum.Value {
|
for i := range schema.Enum.Value {
|
||||||
enum = append(enum, schema.Enum.Value[i].Value)
|
enum = append(enum, schema.Enum.Value[i].Value)
|
||||||
}
|
}
|
||||||
s.Enum = enum
|
s.Enum = enum
|
||||||
|
|
||||||
// async work.
|
// async work.
|
||||||
// any polymorphic properties need to be handled in their own threads
|
// any polymorphic properties need to be handled in their own threads
|
||||||
// any properties each need to be processed in their own thread.
|
// any properties each need to be processed in their own thread.
|
||||||
// we go as fast as we can.
|
// we go as fast as we can.
|
||||||
|
|
||||||
polyCompletedChan := make(chan bool)
|
polyCompletedChan := make(chan bool)
|
||||||
propsChan := make(chan bool)
|
propsChan := make(chan bool)
|
||||||
errChan := make(chan error)
|
errChan := make(chan error)
|
||||||
|
|
||||||
// schema async
|
// schema async
|
||||||
buildOutSchema := func(schemas []lowmodel.ValueReference[*base.SchemaProxy], items *[]*SchemaProxy,
|
buildOutSchema := func(schemas []lowmodel.ValueReference[*base.SchemaProxy], items *[]*SchemaProxy,
|
||||||
doneChan chan bool, e chan error) {
|
doneChan chan bool, e chan error) {
|
||||||
bChan := make(chan *SchemaProxy)
|
bChan := make(chan *SchemaProxy)
|
||||||
|
|
||||||
// for every item, build schema async
|
// for every item, build schema async
|
||||||
buildSchemaChild := func(sch lowmodel.ValueReference[*base.SchemaProxy], bChan chan *SchemaProxy) {
|
buildSchemaChild := func(sch lowmodel.ValueReference[*base.SchemaProxy], bChan chan *SchemaProxy) {
|
||||||
p := &SchemaProxy{schema: &lowmodel.NodeReference[*base.SchemaProxy]{
|
p := &SchemaProxy{schema: &lowmodel.NodeReference[*base.SchemaProxy]{
|
||||||
ValueNode: sch.ValueNode,
|
ValueNode: sch.ValueNode,
|
||||||
Value: sch.Value,
|
Value: sch.Value,
|
||||||
}}
|
}}
|
||||||
bChan <- p
|
bChan <- p
|
||||||
}
|
}
|
||||||
totalSchemas := len(schemas)
|
totalSchemas := len(schemas)
|
||||||
for v := range schemas {
|
for v := range schemas {
|
||||||
go buildSchemaChild(schemas[v], bChan)
|
go buildSchemaChild(schemas[v], bChan)
|
||||||
}
|
}
|
||||||
j := 0
|
j := 0
|
||||||
for j < totalSchemas {
|
for j < totalSchemas {
|
||||||
select {
|
select {
|
||||||
case t := <-bChan:
|
case t := <-bChan:
|
||||||
j++
|
j++
|
||||||
*items = append(*items, t)
|
*items = append(*items, t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
doneChan <- true
|
doneChan <- true
|
||||||
}
|
}
|
||||||
|
|
||||||
// props async
|
// props async
|
||||||
plock := sync.RWMutex{}
|
plock := sync.RWMutex{}
|
||||||
var buildProps = func(k lowmodel.KeyReference[string], v lowmodel.ValueReference[*base.SchemaProxy], c chan bool,
|
var buildProps = func(k lowmodel.KeyReference[string], v lowmodel.ValueReference[*base.SchemaProxy], c chan bool,
|
||||||
props map[string]*SchemaProxy) {
|
props map[string]*SchemaProxy) {
|
||||||
defer plock.Unlock()
|
defer plock.Unlock()
|
||||||
plock.Lock()
|
plock.Lock()
|
||||||
props[k.Value] = &SchemaProxy{schema: &lowmodel.NodeReference[*base.SchemaProxy]{
|
props[k.Value] = &SchemaProxy{schema: &lowmodel.NodeReference[*base.SchemaProxy]{
|
||||||
Value: v.Value,
|
Value: v.Value,
|
||||||
KeyNode: k.KeyNode,
|
KeyNode: k.KeyNode,
|
||||||
ValueNode: v.ValueNode,
|
ValueNode: v.ValueNode,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
s.Properties = props
|
s.Properties = props
|
||||||
c <- true
|
c <- true
|
||||||
}
|
}
|
||||||
|
|
||||||
props := make(map[string]*SchemaProxy)
|
props := make(map[string]*SchemaProxy)
|
||||||
for k, v := range schema.Properties.Value {
|
for k, v := range schema.Properties.Value {
|
||||||
go buildProps(k, v, propsChan, props)
|
go buildProps(k, v, propsChan, props)
|
||||||
}
|
}
|
||||||
|
|
||||||
var allOf []*SchemaProxy
|
var allOf []*SchemaProxy
|
||||||
var oneOf []*SchemaProxy
|
var oneOf []*SchemaProxy
|
||||||
var anyOf []*SchemaProxy
|
var anyOf []*SchemaProxy
|
||||||
var not []*SchemaProxy
|
var not []*SchemaProxy
|
||||||
var items []*SchemaProxy
|
var items []*SchemaProxy
|
||||||
|
|
||||||
if !schema.AllOf.IsEmpty() {
|
if !schema.AllOf.IsEmpty() {
|
||||||
go buildOutSchema(schema.AllOf.Value, &allOf, polyCompletedChan, errChan)
|
go buildOutSchema(schema.AllOf.Value, &allOf, polyCompletedChan, errChan)
|
||||||
}
|
}
|
||||||
if !schema.AnyOf.IsEmpty() {
|
if !schema.AnyOf.IsEmpty() {
|
||||||
go buildOutSchema(schema.AnyOf.Value, &anyOf, polyCompletedChan, errChan)
|
go buildOutSchema(schema.AnyOf.Value, &anyOf, polyCompletedChan, errChan)
|
||||||
}
|
}
|
||||||
if !schema.OneOf.IsEmpty() {
|
if !schema.OneOf.IsEmpty() {
|
||||||
go buildOutSchema(schema.OneOf.Value, &oneOf, polyCompletedChan, errChan)
|
go buildOutSchema(schema.OneOf.Value, &oneOf, polyCompletedChan, errChan)
|
||||||
}
|
}
|
||||||
if !schema.Not.IsEmpty() {
|
if !schema.Not.IsEmpty() {
|
||||||
go buildOutSchema(schema.Not.Value, ¬, polyCompletedChan, errChan)
|
go buildOutSchema(schema.Not.Value, ¬, polyCompletedChan, errChan)
|
||||||
}
|
}
|
||||||
if !schema.Items.IsEmpty() {
|
if !schema.Items.IsEmpty() {
|
||||||
go buildOutSchema(schema.Items.Value, &items, polyCompletedChan, errChan)
|
go buildOutSchema(schema.Items.Value, &items, polyCompletedChan, errChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
completeChildren := 0
|
completeChildren := 0
|
||||||
completedProps := 0
|
completedProps := 0
|
||||||
totalProps := len(schema.Properties.Value)
|
totalProps := len(schema.Properties.Value)
|
||||||
totalChildren := len(schema.AllOf.Value) + len(schema.OneOf.Value) + len(schema.AnyOf.Value) + len(schema.Items.Value) + len(schema.Not.Value)
|
totalChildren := len(schema.AllOf.Value) + len(schema.OneOf.Value) + len(schema.AnyOf.Value) + len(schema.Items.Value) + len(schema.Not.Value)
|
||||||
if totalProps+totalChildren > 0 {
|
if totalProps+totalChildren > 0 {
|
||||||
allDone:
|
allDone:
|
||||||
for true {
|
for true {
|
||||||
select {
|
select {
|
||||||
case <-polyCompletedChan:
|
case <-polyCompletedChan:
|
||||||
completeChildren++
|
completeChildren++
|
||||||
if totalProps == completedProps && totalChildren == completeChildren {
|
if totalProps == completedProps && totalChildren == completeChildren {
|
||||||
break allDone
|
break allDone
|
||||||
}
|
}
|
||||||
case <-propsChan:
|
case <-propsChan:
|
||||||
completedProps++
|
completedProps++
|
||||||
if totalProps == completedProps && totalChildren == completeChildren {
|
if totalProps == completedProps && totalChildren == completeChildren {
|
||||||
break allDone
|
break allDone
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.OneOf = oneOf
|
s.OneOf = oneOf
|
||||||
s.AnyOf = anyOf
|
s.AnyOf = anyOf
|
||||||
s.AllOf = allOf
|
s.AllOf = allOf
|
||||||
s.Items = items
|
s.Items = items
|
||||||
s.Not = not
|
s.Not = not
|
||||||
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GoLow will return the low-level instance of Schema that was used to create the high level one.
|
||||||
func (s *Schema) GoLow() *base.Schema {
|
func (s *Schema) GoLow() *base.Schema {
|
||||||
return s.low
|
return s.low
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,15 +8,52 @@ import (
|
|||||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SchemaProxy exists as a stub that will create a Schema once (and only once) the Schema() method is called. An
|
||||||
|
// underlying low-level SchemaProxy backs this high-level one.
|
||||||
|
//
|
||||||
|
// Why use a Proxy design?
|
||||||
|
//
|
||||||
|
// There are three reasons.
|
||||||
|
//
|
||||||
|
// 1. Circular References and Endless Loops.
|
||||||
|
//
|
||||||
|
// JSON Schema allows for references to be used. This means references can loop around and create infinite recursive
|
||||||
|
// structures, These 'Circular references' technically mean a schema can NEVER be resolved, not without breaking the
|
||||||
|
// loop somewhere along the chain.
|
||||||
|
//
|
||||||
|
// Polymorphism in the form of 'oneOf' and 'anyOf' in version 3+ only exacerbates the problem.
|
||||||
|
//
|
||||||
|
// These circular traps can be discovered using the resolver, however it's still not enough to stop endless loops and
|
||||||
|
// endless goroutine spawning. A proxy design means that resolving occurs on demand and runs down a single level only.
|
||||||
|
// preventing any run-away loops.
|
||||||
|
//
|
||||||
|
// 2. Performance
|
||||||
|
//
|
||||||
|
// Even without circular references, Polymorphism creates large additional resolving chains that take a long time
|
||||||
|
// and slow things down when building. By preventing recursion through every polymorphic item, building models is kept
|
||||||
|
// fast and snappy, which is desired for realtime processing of specs.
|
||||||
|
//
|
||||||
|
// - Q: Yeah, but, why not just use state to avoiding re-visiting seen polymorphic nodes?
|
||||||
|
// - A: It's slow, takes up memory and still has runaway potential in very, very long chains.
|
||||||
|
//
|
||||||
|
// 3. Short Circuit Errors.
|
||||||
|
//
|
||||||
|
// Schemas are where things can get messy, mainly because the Schema standard changes between versions, and
|
||||||
|
// it's not actually JSONSchema until 3.1, so lots of times a bad schema will break parsing. Errors are only found
|
||||||
|
// when a schema is needed, so the rest of the document is parsed and ready to use.
|
||||||
type SchemaProxy struct {
|
type SchemaProxy struct {
|
||||||
schema *low.NodeReference[*base.SchemaProxy]
|
schema *low.NodeReference[*base.SchemaProxy]
|
||||||
buildError error
|
buildError error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewSchemaProxy creates a new high-level SchemaProxy from a low-level one.
|
||||||
func NewSchemaProxy(schema *low.NodeReference[*base.SchemaProxy]) *SchemaProxy {
|
func NewSchemaProxy(schema *low.NodeReference[*base.SchemaProxy]) *SchemaProxy {
|
||||||
return &SchemaProxy{schema: schema}
|
return &SchemaProxy{schema: schema}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Schema will create a new Schema instance using NewSchema from the low-level SchemaProxy backing this high-level one.
|
||||||
|
// If there is a problem building the Schema, then this method will return nil. Use GetBuildError to gain access
|
||||||
|
// to that building error.
|
||||||
func (sp *SchemaProxy) Schema() *Schema {
|
func (sp *SchemaProxy) Schema() *Schema {
|
||||||
s := sp.schema.Value.Schema()
|
s := sp.schema.Value.Schema()
|
||||||
if s == nil {
|
if s == nil {
|
||||||
@@ -26,6 +63,7 @@ func (sp *SchemaProxy) Schema() *Schema {
|
|||||||
return NewSchema(s)
|
return NewSchema(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetBuildError returns any error that was thrown when calling Schema()
|
||||||
func (sp *SchemaProxy) GetBuildError() error {
|
func (sp *SchemaProxy) GetBuildError() error {
|
||||||
return sp.buildError
|
return sp.buildError
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,18 +4,19 @@
|
|||||||
package base
|
package base
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"fmt"
|
||||||
lowbase "github.com/pb33f/libopenapi/datamodel/low/base"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/index"
|
lowbase "github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/pb33f/libopenapi/index"
|
||||||
"gopkg.in/yaml.v3"
|
"github.com/stretchr/testify/assert"
|
||||||
"testing"
|
"gopkg.in/yaml.v3"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewSchemaProxy(t *testing.T) {
|
func TestNewSchemaProxy(t *testing.T) {
|
||||||
|
|
||||||
// check proxy
|
// check proxy
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
rice:
|
rice:
|
||||||
type: string
|
type: string
|
||||||
@@ -28,34 +29,34 @@ func TestNewSchemaProxy(t *testing.T) {
|
|||||||
rice:
|
rice:
|
||||||
$ref: '#/components/schemas/rice'`
|
$ref: '#/components/schemas/rice'`
|
||||||
|
|
||||||
var idxNode, compNode yaml.Node
|
var idxNode, compNode yaml.Node
|
||||||
mErr := yaml.Unmarshal([]byte(yml), &idxNode)
|
mErr := yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
assert.NoError(t, mErr)
|
assert.NoError(t, mErr)
|
||||||
idx := index.NewSpecIndex(&idxNode)
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
yml = `properties:
|
yml = `properties:
|
||||||
rice:
|
rice:
|
||||||
$ref: '#/components/schemas/I-do-not-exist'`
|
$ref: '#/components/schemas/I-do-not-exist'`
|
||||||
|
|
||||||
_ = yaml.Unmarshal([]byte(yml), &compNode)
|
_ = yaml.Unmarshal([]byte(yml), &compNode)
|
||||||
|
|
||||||
sp := new(lowbase.SchemaProxy)
|
sp := new(lowbase.SchemaProxy)
|
||||||
err := sp.Build(compNode.Content[0], idx)
|
err := sp.Build(compNode.Content[0], idx)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
lowproxy := low.NodeReference[*lowbase.SchemaProxy]{
|
lowproxy := low.NodeReference[*lowbase.SchemaProxy]{
|
||||||
Value: sp,
|
Value: sp,
|
||||||
ValueNode: idxNode.Content[0],
|
ValueNode: idxNode.Content[0],
|
||||||
}
|
}
|
||||||
|
|
||||||
sch1 := SchemaProxy{schema: &lowproxy}
|
sch1 := SchemaProxy{schema: &lowproxy}
|
||||||
assert.Nil(t, sch1.Schema())
|
assert.Nil(t, sch1.Schema())
|
||||||
assert.Error(t, sch1.GetBuildError())
|
assert.Error(t, sch1.GetBuildError())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewSchemaProxy_WithObject(t *testing.T) {
|
func TestNewSchemaProxy_WithObject(t *testing.T) {
|
||||||
|
|
||||||
testSpec := `type: object
|
testSpec := `type: object
|
||||||
description: something object
|
description: something object
|
||||||
discriminator:
|
discriminator:
|
||||||
propertyName: athing
|
propertyName: athing
|
||||||
@@ -164,32 +165,32 @@ externalDocs:
|
|||||||
enum: [fish, cake]
|
enum: [fish, cake]
|
||||||
required: [cake, fish]`
|
required: [cake, fish]`
|
||||||
|
|
||||||
var compNode yaml.Node
|
var compNode yaml.Node
|
||||||
_ = yaml.Unmarshal([]byte(testSpec), &compNode)
|
_ = yaml.Unmarshal([]byte(testSpec), &compNode)
|
||||||
|
|
||||||
sp := new(lowbase.SchemaProxy)
|
sp := new(lowbase.SchemaProxy)
|
||||||
err := sp.Build(compNode.Content[0], nil)
|
err := sp.Build(compNode.Content[0], nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
lowproxy := low.NodeReference[*lowbase.SchemaProxy]{
|
lowproxy := low.NodeReference[*lowbase.SchemaProxy]{
|
||||||
Value: sp,
|
Value: sp,
|
||||||
ValueNode: compNode.Content[0],
|
ValueNode: compNode.Content[0],
|
||||||
}
|
}
|
||||||
|
|
||||||
schemaProxy := NewSchemaProxy(&lowproxy)
|
schemaProxy := NewSchemaProxy(&lowproxy)
|
||||||
compiled := schemaProxy.Schema()
|
compiled := schemaProxy.Schema()
|
||||||
|
|
||||||
assert.NotNil(t, compiled)
|
assert.NotNil(t, compiled)
|
||||||
assert.Nil(t, schemaProxy.GetBuildError())
|
assert.Nil(t, schemaProxy.GetBuildError())
|
||||||
|
|
||||||
wentLow := compiled.GoLow()
|
wentLow := compiled.GoLow()
|
||||||
assert.Equal(t, 102, wentLow.AdditionalProperties.ValueNode.Line)
|
assert.Equal(t, 102, wentLow.AdditionalProperties.ValueNode.Line)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewSchemaProxy_WithObject_FinishPoly(t *testing.T) {
|
func TestNewSchemaProxy_WithObject_FinishPoly(t *testing.T) {
|
||||||
|
|
||||||
testSpec := `type: object
|
testSpec := `type: object
|
||||||
description: something object
|
description: something object
|
||||||
discriminator:
|
discriminator:
|
||||||
propertyName: athing
|
propertyName: athing
|
||||||
@@ -294,35 +295,99 @@ externalDocs:
|
|||||||
enum: [fish, cake]
|
enum: [fish, cake]
|
||||||
required: [cake, fish]`
|
required: [cake, fish]`
|
||||||
|
|
||||||
var compNode yaml.Node
|
var compNode yaml.Node
|
||||||
_ = yaml.Unmarshal([]byte(testSpec), &compNode)
|
_ = yaml.Unmarshal([]byte(testSpec), &compNode)
|
||||||
|
|
||||||
sp := new(lowbase.SchemaProxy)
|
sp := new(lowbase.SchemaProxy)
|
||||||
err := sp.Build(compNode.Content[0], nil)
|
err := sp.Build(compNode.Content[0], nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
lowproxy := low.NodeReference[*lowbase.SchemaProxy]{
|
lowproxy := low.NodeReference[*lowbase.SchemaProxy]{
|
||||||
Value: sp,
|
Value: sp,
|
||||||
ValueNode: compNode.Content[0],
|
ValueNode: compNode.Content[0],
|
||||||
}
|
}
|
||||||
|
|
||||||
schemaProxy := NewSchemaProxy(&lowproxy)
|
schemaProxy := NewSchemaProxy(&lowproxy)
|
||||||
compiled := schemaProxy.Schema()
|
compiled := schemaProxy.Schema()
|
||||||
|
|
||||||
assert.NotNil(t, compiled)
|
assert.NotNil(t, compiled)
|
||||||
assert.Nil(t, schemaProxy.GetBuildError())
|
assert.Nil(t, schemaProxy.GetBuildError())
|
||||||
|
|
||||||
assert.True(t, compiled.ExclusiveMaximumBool)
|
assert.True(t, compiled.ExclusiveMaximumBool)
|
||||||
assert.False(t, compiled.ExclusiveMinimumBool)
|
assert.False(t, compiled.ExclusiveMinimumBool)
|
||||||
assert.Equal(t, int64(123), compiled.Properties["somethingB"].Schema().ExclusiveMinimum)
|
assert.Equal(t, int64(123), compiled.Properties["somethingB"].Schema().ExclusiveMinimum)
|
||||||
assert.Equal(t, int64(334), compiled.Properties["somethingB"].Schema().ExclusiveMaximum)
|
assert.Equal(t, int64(334), compiled.Properties["somethingB"].Schema().ExclusiveMaximum)
|
||||||
assert.Len(t, compiled.Properties["somethingB"].Schema().Properties["somethingBProp"].Schema().Type, 2)
|
assert.Len(t, compiled.Properties["somethingB"].Schema().Properties["somethingBProp"].Schema().Type, 2)
|
||||||
|
|
||||||
wentLow := compiled.GoLow()
|
wentLow := compiled.GoLow()
|
||||||
assert.Equal(t, 96, wentLow.AdditionalProperties.ValueNode.Line)
|
assert.Equal(t, 96, wentLow.AdditionalProperties.ValueNode.Line)
|
||||||
assert.Equal(t, 100, wentLow.XML.ValueNode.Line)
|
assert.Equal(t, 100, wentLow.XML.ValueNode.Line)
|
||||||
|
|
||||||
wentLower := compiled.XML.GoLow()
|
wentLower := compiled.XML.GoLow()
|
||||||
assert.Equal(t, 100, wentLower.Name.ValueNode.Line)
|
assert.Equal(t, 100, wentLower.Name.ValueNode.Line)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleNewSchema() {
|
||||||
|
|
||||||
|
// create an example schema object
|
||||||
|
// this can be either JSON or YAML.
|
||||||
|
yml := `
|
||||||
|
title: this is a schema
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
aProperty:
|
||||||
|
description: this is an integer property
|
||||||
|
type: integer
|
||||||
|
format: int64`
|
||||||
|
|
||||||
|
// unmarshal raw bytes
|
||||||
|
var node yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &node)
|
||||||
|
|
||||||
|
// build out the low-level model
|
||||||
|
var lowSchema lowbase.Schema
|
||||||
|
_ = low.BuildModel(&node, &lowSchema)
|
||||||
|
_ = lowSchema.Build(node.Content[0], nil)
|
||||||
|
|
||||||
|
// build the high level model
|
||||||
|
highSchema := NewSchema(&lowSchema)
|
||||||
|
|
||||||
|
// print out the description of 'aProperty'
|
||||||
|
fmt.Print(highSchema.Properties["aProperty"].Schema().Description)
|
||||||
|
// Output: this is an integer property
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleNewSchemaProxy() {
|
||||||
|
|
||||||
|
// create an example schema object
|
||||||
|
// this can be either JSON or YAML.
|
||||||
|
yml := `
|
||||||
|
title: this is a schema
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
aProperty:
|
||||||
|
description: this is an integer property
|
||||||
|
type: integer
|
||||||
|
format: int64`
|
||||||
|
|
||||||
|
// unmarshal raw bytes
|
||||||
|
var node yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &node)
|
||||||
|
|
||||||
|
// build out the low-level model
|
||||||
|
var lowSchema lowbase.SchemaProxy
|
||||||
|
_ = low.BuildModel(&node, &lowSchema)
|
||||||
|
_ = lowSchema.Build(node.Content[0], nil)
|
||||||
|
|
||||||
|
// build the high level schema proxy
|
||||||
|
highSchema := NewSchemaProxy(&low.NodeReference[*lowbase.SchemaProxy]{
|
||||||
|
Value: &lowSchema,
|
||||||
|
})
|
||||||
|
|
||||||
|
// print out the description of 'aProperty'
|
||||||
|
fmt.Print(highSchema.Schema().Properties["aProperty"].Schema().Description)
|
||||||
|
// Output: this is an integer property
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,38 +4,44 @@
|
|||||||
package base
|
package base
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/high"
|
"github.com/pb33f/libopenapi/datamodel/high"
|
||||||
low "github.com/pb33f/libopenapi/datamodel/low/base"
|
low "github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Tag represents a high-level Tag instance that is backed by a low-level one.
|
||||||
|
// - v2: https://swagger.io/specification/v2/#tagObject
|
||||||
|
// - v3: https://swagger.io/specification/#tag-object
|
||||||
type Tag struct {
|
type Tag struct {
|
||||||
Name string
|
Name string
|
||||||
Description string
|
Description string
|
||||||
ExternalDocs *ExternalDoc
|
ExternalDocs *ExternalDoc
|
||||||
Extensions map[string]any
|
Extensions map[string]any
|
||||||
low *low.Tag
|
low *low.Tag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewTag creates a new high-level Tag instance that is backed by a low-level one.
|
||||||
func NewTag(tag *low.Tag) *Tag {
|
func NewTag(tag *low.Tag) *Tag {
|
||||||
t := new(Tag)
|
t := new(Tag)
|
||||||
t.low = tag
|
t.low = tag
|
||||||
if !tag.Name.IsEmpty() {
|
if !tag.Name.IsEmpty() {
|
||||||
t.Name = tag.Name.Value
|
t.Name = tag.Name.Value
|
||||||
}
|
}
|
||||||
if !tag.Description.IsEmpty() {
|
if !tag.Description.IsEmpty() {
|
||||||
t.Description = tag.Description.Value
|
t.Description = tag.Description.Value
|
||||||
}
|
}
|
||||||
if !tag.ExternalDocs.IsEmpty() {
|
if !tag.ExternalDocs.IsEmpty() {
|
||||||
t.ExternalDocs = NewExternalDoc(tag.ExternalDocs.Value)
|
t.ExternalDocs = NewExternalDoc(tag.ExternalDocs.Value)
|
||||||
}
|
}
|
||||||
t.Extensions = high.ExtractExtensions(tag.Extensions)
|
t.Extensions = high.ExtractExtensions(tag.Extensions)
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GoLow returns the low-level Tag instance used to create the high-level one.
|
||||||
func (t *Tag) GoLow() *low.Tag {
|
func (t *Tag) GoLow() *low.Tag {
|
||||||
return t.low
|
return t.low
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Experimental mutation API.
|
||||||
//func (t *Tag) SetName(value string) {
|
//func (t *Tag) SetName(value string) {
|
||||||
// t.GoLow().Name.ValueNode.Value = value
|
// t.GoLow().Name.ValueNode.Value = value
|
||||||
//}
|
//}
|
||||||
|
|||||||
@@ -4,37 +4,66 @@
|
|||||||
package base
|
package base
|
||||||
|
|
||||||
import (
|
import (
|
||||||
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
|
"fmt"
|
||||||
lowbase "github.com/pb33f/libopenapi/datamodel/low/base"
|
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/stretchr/testify/assert"
|
lowbase "github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
"gopkg.in/yaml.v3"
|
"github.com/stretchr/testify/assert"
|
||||||
"testing"
|
"gopkg.in/yaml.v3"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewTag(t *testing.T) {
|
func TestNewTag(t *testing.T) {
|
||||||
|
|
||||||
var cNode yaml.Node
|
var cNode yaml.Node
|
||||||
|
|
||||||
yml := `name: chicken
|
yml := `name: chicken
|
||||||
description: nuggets
|
description: nuggets
|
||||||
externalDocs:
|
externalDocs:
|
||||||
url: https://pb33f.io
|
url: https://pb33f.io
|
||||||
x-hack: code`
|
x-hack: code`
|
||||||
|
|
||||||
_ = yaml.Unmarshal([]byte(yml), &cNode)
|
_ = yaml.Unmarshal([]byte(yml), &cNode)
|
||||||
|
|
||||||
var lowTag lowbase.Tag
|
var lowTag lowbase.Tag
|
||||||
_ = lowmodel.BuildModel(&cNode, &lowTag)
|
_ = lowmodel.BuildModel(&cNode, &lowTag)
|
||||||
_ = lowTag.Build(cNode.Content[0], nil)
|
_ = lowTag.Build(cNode.Content[0], nil)
|
||||||
|
|
||||||
highTag := NewTag(&lowTag)
|
highTag := NewTag(&lowTag)
|
||||||
|
|
||||||
assert.Equal(t, "chicken", highTag.Name)
|
assert.Equal(t, "chicken", highTag.Name)
|
||||||
assert.Equal(t, "nuggets", highTag.Description)
|
assert.Equal(t, "nuggets", highTag.Description)
|
||||||
assert.Equal(t, "https://pb33f.io", highTag.ExternalDocs.URL)
|
assert.Equal(t, "https://pb33f.io", highTag.ExternalDocs.URL)
|
||||||
assert.Equal(t, "code", highTag.Extensions["x-hack"])
|
assert.Equal(t, "code", highTag.Extensions["x-hack"])
|
||||||
|
|
||||||
wentLow := highTag.GoLow()
|
wentLow := highTag.GoLow()
|
||||||
assert.Equal(t, 5, wentLow.FindExtension("x-hack").ValueNode.Line)
|
assert.Equal(t, 5, wentLow.FindExtension("x-hack").ValueNode.Line)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleNewTag() {
|
||||||
|
|
||||||
|
// create an example schema object
|
||||||
|
// this can be either JSON or YAML.
|
||||||
|
yml := `
|
||||||
|
name: Purchases
|
||||||
|
description: All kinds of purchase related operations
|
||||||
|
externalDocs:
|
||||||
|
url: https://pb33f.io/purchases
|
||||||
|
x-hack: code`
|
||||||
|
|
||||||
|
// unmarshal raw bytes
|
||||||
|
var node yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &node)
|
||||||
|
|
||||||
|
// build out the low-level model
|
||||||
|
var lowTag lowbase.Tag
|
||||||
|
_ = lowmodel.BuildModel(&node, &lowTag)
|
||||||
|
_ = lowTag.Build(node.Content[0], nil)
|
||||||
|
|
||||||
|
// build the high level tag
|
||||||
|
highTag := NewTag(&lowTag)
|
||||||
|
|
||||||
|
// print out the tag name
|
||||||
|
fmt.Print(highTag.Name)
|
||||||
|
// Output: Purchases
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,32 +4,38 @@
|
|||||||
package base
|
package base
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/high"
|
"github.com/pb33f/libopenapi/datamodel/high"
|
||||||
low "github.com/pb33f/libopenapi/datamodel/low/base"
|
low "github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// XML represents a high-level representation of an XML object defined by all versions of OpenAPI and backed by
|
||||||
|
// low-level XML object.
|
||||||
|
// v2 - https://swagger.io/specification/v2/#xmlObject
|
||||||
|
// v3 - https://swagger.io/specification/#xml-object
|
||||||
type XML struct {
|
type XML struct {
|
||||||
Name string
|
Name string
|
||||||
Namespace string
|
Namespace string
|
||||||
Prefix string
|
Prefix string
|
||||||
Attribute bool
|
Attribute bool
|
||||||
Wrapped bool
|
Wrapped bool
|
||||||
Extensions map[string]any
|
Extensions map[string]any
|
||||||
low *low.XML
|
low *low.XML
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewXML creates a new high-level XML instance from a low-level one.
|
||||||
func NewXML(xml *low.XML) *XML {
|
func NewXML(xml *low.XML) *XML {
|
||||||
x := new(XML)
|
x := new(XML)
|
||||||
x.low = xml
|
x.low = xml
|
||||||
x.Name = xml.Name.Value
|
x.Name = xml.Name.Value
|
||||||
x.Namespace = xml.Namespace.Value
|
x.Namespace = xml.Namespace.Value
|
||||||
x.Prefix = xml.Namespace.Value
|
x.Prefix = xml.Namespace.Value
|
||||||
x.Attribute = xml.Attribute.Value
|
x.Attribute = xml.Attribute.Value
|
||||||
x.Wrapped = xml.Wrapped.Value
|
x.Wrapped = xml.Wrapped.Value
|
||||||
x.Extensions = high.ExtractExtensions(xml.Extensions)
|
x.Extensions = high.ExtractExtensions(xml.Extensions)
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GoLow returns the low level XML reference used to create the high level one.
|
||||||
func (x *XML) GoLow() *low.XML {
|
func (x *XML) GoLow() *low.XML {
|
||||||
return x.low
|
return x.low
|
||||||
}
|
}
|
||||||
|
|||||||
36
datamodel/high/base/xml_test.go
Normal file
36
datamodel/high/base/xml_test.go
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package base
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
|
||||||
|
lowbase "github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleNewXML() {
|
||||||
|
|
||||||
|
// create an example schema object
|
||||||
|
// this can be either JSON or YAML.
|
||||||
|
yml := `
|
||||||
|
namespace: https://pb33f.io/schema
|
||||||
|
prefix: sample`
|
||||||
|
|
||||||
|
// unmarshal raw bytes
|
||||||
|
var node yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &node)
|
||||||
|
|
||||||
|
// build out the low-level model
|
||||||
|
var lowXML lowbase.XML
|
||||||
|
_ = lowmodel.BuildModel(&node, &lowXML)
|
||||||
|
_ = lowXML.Build(node.Content[0], nil)
|
||||||
|
|
||||||
|
// build the high level tag
|
||||||
|
highXML := NewXML(&lowXML)
|
||||||
|
|
||||||
|
// print out the XML namespace
|
||||||
|
fmt.Print(highXML.Namespace)
|
||||||
|
// Output: https://pb33f.io/schema
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,20 +1,21 @@
|
|||||||
package base
|
package base
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"gopkg.in/yaml.v3"
|
"github.com/pb33f/libopenapi/index"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type XML struct {
|
type XML struct {
|
||||||
Name low.NodeReference[string]
|
Name low.NodeReference[string]
|
||||||
Namespace low.NodeReference[string]
|
Namespace low.NodeReference[string]
|
||||||
Prefix low.NodeReference[string]
|
Prefix low.NodeReference[string]
|
||||||
Attribute low.NodeReference[bool]
|
Attribute low.NodeReference[bool]
|
||||||
Wrapped low.NodeReference[bool]
|
Wrapped low.NodeReference[bool]
|
||||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *XML) Build(root *yaml.Node) error {
|
func (x *XML) Build(root *yaml.Node, _ *index.SpecIndex) error {
|
||||||
x.Extensions = low.ExtractExtensions(root)
|
x.Extensions = low.ExtractExtensions(root)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user