mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-06 12:37:49 +00:00
Added NodeMap to all low level objects.
this sync map tracks all the nodes that apply to this object.
This commit is contained in:
@@ -150,7 +150,7 @@ components:
|
|||||||
assert.ErrorIs(t, unwrap[0], ErrInvalidModel)
|
assert.ErrorIs(t, unwrap[0], ErrInvalidModel)
|
||||||
unwrapNext := utils.UnwrapErrors(unwrap[1])
|
unwrapNext := utils.UnwrapErrors(unwrap[1])
|
||||||
require.Len(t, unwrapNext, 2)
|
require.Len(t, unwrapNext, 2)
|
||||||
assert.Equal(t, "component 'bork' does not exist in the specification", unwrapNext[0].Error())
|
assert.Equal(t, "component `bork` does not exist in the specification", unwrapNext[0].Error())
|
||||||
assert.Equal(t, "cannot resolve reference `bork`, it's missing: $bork [5:7]", unwrapNext[1].Error())
|
assert.Equal(t, "cannot resolve reference `bork`, it's missing: $bork [5:7]", unwrapNext[1].Error())
|
||||||
|
|
||||||
logEntries := strings.Split(byteBuf.String(), "\n")
|
logEntries := strings.Split(byteBuf.String(), "\n")
|
||||||
|
|||||||
@@ -72,6 +72,14 @@ func CreateSchemaProxyRef(ref string) *SchemaProxy {
|
|||||||
return &SchemaProxy{refStr: ref, lock: &sync.Mutex{}}
|
return &SchemaProxy{refStr: ref, lock: &sync.Mutex{}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetValueNode returns the value node of the SchemaProxy.
|
||||||
|
func (sp *SchemaProxy) GetValueNode() *yaml.Node {
|
||||||
|
if sp.schema != nil {
|
||||||
|
return sp.schema.ValueNode
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Schema will create a new Schema instance using NewSchema from the low-level SchemaProxy backing this high-level one.
|
// 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
|
// If there is a problem building the Schema, then this method will return nil. Use GetBuildError to gain access
|
||||||
// to that building error.
|
// to that building error.
|
||||||
|
|||||||
@@ -443,7 +443,7 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, entry *nodes.NodeEntry) *ya
|
|||||||
lr := lut.(low.IsReferenced)
|
lr := lut.(low.IsReferenced)
|
||||||
ut := reflect.ValueOf(lr)
|
ut := reflect.ValueOf(lr)
|
||||||
if !ut.IsNil() {
|
if !ut.IsNil() {
|
||||||
if lut.(low.IsReferenced).IsReference() {
|
if lr != nil && lr.IsReference() {
|
||||||
if !n.Resolve {
|
if !n.Resolve {
|
||||||
valueNode = n.renderReference(lut.(low.IsReferenced))
|
valueNode = n.renderReference(lut.(low.IsReferenced))
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -155,6 +155,11 @@ func (d *Document) GoLow() *low.Document {
|
|||||||
return d.low
|
return d.low
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GoLowUntyped returns the low-level Document that was used to create the high level one, however, it's untyped.
|
||||||
|
func (d *Document) GoLowUntyped() any {
|
||||||
|
return d.low
|
||||||
|
}
|
||||||
|
|
||||||
// Render will return a YAML representation of the Document object as a byte slice.
|
// Render will return a YAML representation of the Document object as a byte slice.
|
||||||
func (d *Document) Render() ([]byte, error) {
|
func (d *Document) Render() ([]byte, error) {
|
||||||
return yaml.Marshal(d)
|
return yaml.Marshal(d)
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ func TestNewDocument_Info(t *testing.T) {
|
|||||||
assert.Equal(t, "1.2", highDoc.Info.Version)
|
assert.Equal(t, "1.2", highDoc.Info.Version)
|
||||||
assert.Equal(t, "https://pb33f.io/schema", highDoc.JsonSchemaDialect)
|
assert.Equal(t, "https://pb33f.io/schema", highDoc.JsonSchemaDialect)
|
||||||
|
|
||||||
|
assert.NotNil(t, highDoc.GoLowUntyped())
|
||||||
wentLow := highDoc.GoLow()
|
wentLow := highDoc.GoLow()
|
||||||
assert.Equal(t, 1, wentLow.Version.ValueNode.Line)
|
assert.Equal(t, 1, wentLow.Version.ValueNode.Line)
|
||||||
assert.Equal(t, 3, wentLow.Info.Value.Title.KeyNode.Line)
|
assert.Equal(t, 3, wentLow.Info.Value.Title.KeyNode.Line)
|
||||||
|
|||||||
@@ -23,14 +23,14 @@ type Contact struct {
|
|||||||
KeyNode *yaml.Node
|
KeyNode *yaml.Node
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build is not implemented for Contact (there is nothing to build).
|
func (c *Contact) Build(ctx context.Context, keyNode, root *yaml.Node, _ *index.SpecIndex) error {
|
||||||
func (c *Contact) Build(_ context.Context, keyNode, root *yaml.Node, _ *index.SpecIndex) error {
|
|
||||||
c.KeyNode = keyNode
|
c.KeyNode = keyNode
|
||||||
c.RootNode = root
|
c.RootNode = root
|
||||||
c.Reference = new(low.Reference)
|
c.Reference = new(low.Reference)
|
||||||
// not implemented.
|
c.Nodes = low.ExtractNodes(ctx, root)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
30
datamodel/low/base/context.go
Normal file
30
datamodel/low/base/context.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright 2023-2024 Princess Beef Heavy Industries, LLC / Dave Shanley
|
||||||
|
// https://pb33f.io
|
||||||
|
|
||||||
|
package base
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ModelContext is a struct that holds various persistent data structures for the model
|
||||||
|
// that passes through the entire model building process.
|
||||||
|
type ModelContext struct {
|
||||||
|
SchemaCache *sync.Map
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetModelContext will return the ModelContext from a context.Context object
|
||||||
|
// if it is available, otherwise it will return nil.
|
||||||
|
func GetModelContext(ctx context.Context) *ModelContext {
|
||||||
|
if ctx == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if ctx.Value("modelCtx") == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if c, ok := ctx.Value("modelCtx").(*ModelContext); ok {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ package base
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
@@ -23,7 +24,20 @@ import (
|
|||||||
type Discriminator struct {
|
type Discriminator struct {
|
||||||
PropertyName low.NodeReference[string]
|
PropertyName low.NodeReference[string]
|
||||||
Mapping low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[string]]]
|
Mapping low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[string]]]
|
||||||
|
KeyNode *yaml.Node
|
||||||
|
RootNode *yaml.Node
|
||||||
low.Reference
|
low.Reference
|
||||||
|
low.NodeMap
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRootNode will return the root yaml node of the Discriminator object
|
||||||
|
func (d *Discriminator) GetRootNode() *yaml.Node {
|
||||||
|
return d.RootNode
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKeyNode will return the key yaml node of the Discriminator object
|
||||||
|
func (d *Discriminator) GetKeyNode() *yaml.Node {
|
||||||
|
return d.KeyNode
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindMappingValue will return a ValueReference containing the string mapping value
|
// FindMappingValue will return a ValueReference containing the string mapping value
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ type Example struct {
|
|||||||
KeyNode *yaml.Node
|
KeyNode *yaml.Node
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindExtension returns a ValueReference containing the extension value, if found.
|
// FindExtension returns a ValueReference containing the extension value, if found.
|
||||||
@@ -67,12 +68,13 @@ func (ex *Example) Hash() [32]byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build extracts extensions and example value
|
// Build extracts extensions and example value
|
||||||
func (ex *Example) Build(_ context.Context, keyNode, root *yaml.Node, _ *index.SpecIndex) error {
|
func (ex *Example) Build(ctx context.Context, keyNode, root *yaml.Node, _ *index.SpecIndex) error {
|
||||||
ex.KeyNode = keyNode
|
ex.KeyNode = keyNode
|
||||||
root = utils.NodeAlias(root)
|
root = utils.NodeAlias(root)
|
||||||
ex.RootNode = root
|
ex.RootNode = root
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
ex.Reference = new(low.Reference)
|
ex.Reference = new(low.Reference)
|
||||||
|
ex.Nodes = low.ExtractNodes(ctx, root)
|
||||||
ex.Extensions = low.ExtractExtensions(root)
|
ex.Extensions = low.ExtractExtensions(root)
|
||||||
_, ln, vn := utils.FindKeyNodeFull(ValueLabel, root.Content)
|
_, ln, vn := utils.FindKeyNodeFull(ValueLabel, root.Content)
|
||||||
|
|
||||||
@@ -82,6 +84,23 @@ func (ex *Example) Build(_ context.Context, keyNode, root *yaml.Node, _ *index.S
|
|||||||
KeyNode: ln,
|
KeyNode: ln,
|
||||||
ValueNode: vn,
|
ValueNode: vn,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// extract nodes for all value nodes down the tree.
|
||||||
|
expChildNodes := low.ExtractNodesRecursive(ctx, vn)
|
||||||
|
expChildNodes.Range(func(k, v interface{}) bool {
|
||||||
|
if arr, ko := v.([]*yaml.Node); ko {
|
||||||
|
if ext, ok := ex.Nodes.Load(k); ok {
|
||||||
|
if extArr, kk := ext.([]*yaml.Node); kk {
|
||||||
|
ex.Nodes.Store(k, append(extArr, arr...))
|
||||||
|
} else {
|
||||||
|
ex.Nodes.Store(k, arr)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ex.Nodes.Store(k, arr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ type ExternalDoc struct {
|
|||||||
KeyNode *yaml.Node
|
KeyNode *yaml.Node
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindExtension returns a ValueReference containing the extension value, if found.
|
// FindExtension returns a ValueReference containing the extension value, if found.
|
||||||
@@ -46,12 +47,13 @@ func (ex *ExternalDoc) GetKeyNode() *yaml.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build will extract extensions from the ExternalDoc instance.
|
// Build will extract extensions from the ExternalDoc instance.
|
||||||
func (ex *ExternalDoc) Build(_ context.Context, keyNode, root *yaml.Node, idx *index.SpecIndex) error {
|
func (ex *ExternalDoc) Build(ctx context.Context, keyNode, root *yaml.Node, idx *index.SpecIndex) error {
|
||||||
ex.KeyNode = keyNode
|
ex.KeyNode = keyNode
|
||||||
root = utils.NodeAlias(root)
|
root = utils.NodeAlias(root)
|
||||||
ex.RootNode = root
|
ex.RootNode = root
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
ex.Reference = new(low.Reference)
|
ex.Reference = new(low.Reference)
|
||||||
|
ex.Nodes = low.ExtractNodes(ctx, root)
|
||||||
ex.Extensions = low.ExtractExtensions(root)
|
ex.Extensions = low.ExtractExtensions(root)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ type Info struct {
|
|||||||
KeyNode *yaml.Node
|
KeyNode *yaml.Node
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindExtension attempts to locate an extension with the supplied key
|
// FindExtension attempts to locate an extension with the supplied key
|
||||||
@@ -64,6 +65,7 @@ func (i *Info) Build(ctx context.Context, keyNode, root *yaml.Node, idx *index.S
|
|||||||
i.RootNode = root
|
i.RootNode = root
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
i.Reference = new(low.Reference)
|
i.Reference = new(low.Reference)
|
||||||
|
i.Nodes = low.ExtractNodes(ctx, root)
|
||||||
i.Extensions = low.ExtractExtensions(root)
|
i.Extensions = low.ExtractExtensions(root)
|
||||||
|
|
||||||
// extract contact
|
// extract contact
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ type License struct {
|
|||||||
KeyNode *yaml.Node
|
KeyNode *yaml.Node
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build out a license, complain if both a URL and identifier are present as they are mutually exclusive
|
// Build out a license, complain if both a URL and identifier are present as they are mutually exclusive
|
||||||
@@ -34,6 +35,8 @@ func (l *License) Build(ctx context.Context, keyNode, root *yaml.Node, idx *inde
|
|||||||
l.RootNode = root
|
l.RootNode = root
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
l.Reference = new(low.Reference)
|
l.Reference = new(low.Reference)
|
||||||
|
no := low.ExtractNodes(ctx, root)
|
||||||
|
l.Nodes = no
|
||||||
if l.URL.Value != "" && l.Identifier.Value != "" {
|
if l.URL.Value != "" && l.Identifier.Value != "" {
|
||||||
return fmt.Errorf("license cannot have both a URL and an identifier, they are mutually exclusive")
|
return fmt.Errorf("license cannot have both a URL and an identifier, they are mutually exclusive")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ type Schema struct {
|
|||||||
Index *index.SpecIndex
|
Index *index.SpecIndex
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash will calculate a SHA256 hash from the values of the schema, This allows equality checking against
|
// Hash will calculate a SHA256 hash from the values of the schema, This allows equality checking against
|
||||||
@@ -470,8 +471,11 @@ func (s *Schema) Build(ctx context.Context, root *yaml.Node, idx *index.SpecInde
|
|||||||
root = utils.NodeAlias(root)
|
root = utils.NodeAlias(root)
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
s.Reference = new(low.Reference)
|
s.Reference = new(low.Reference)
|
||||||
|
no := low.ExtractNodes(ctx, root)
|
||||||
|
s.Nodes = no
|
||||||
s.Index = idx
|
s.Index = idx
|
||||||
s.RootNode = root
|
s.RootNode = root
|
||||||
|
|
||||||
if h, _, _ := utils.IsNodeRefValue(root); h {
|
if h, _, _ := utils.IsNodeRefValue(root); h {
|
||||||
ref, _, err, fctx := low.LocateRefNodeWithContext(ctx, root, idx)
|
ref, _, err, fctx := low.LocateRefNodeWithContext(ctx, root, idx)
|
||||||
if ref != nil {
|
if ref != nil {
|
||||||
@@ -497,6 +501,20 @@ func (s *Schema) Build(ctx context.Context, root *yaml.Node, idx *index.SpecInde
|
|||||||
|
|
||||||
s.extractExtensions(root)
|
s.extractExtensions(root)
|
||||||
|
|
||||||
|
// if the schema has required values, extract the nodes for them.
|
||||||
|
if s.Required.Value != nil {
|
||||||
|
for _, r := range s.Required.Value {
|
||||||
|
s.AddNode(r.ValueNode.Line, r.ValueNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// same thing with enums
|
||||||
|
if s.Enum.Value != nil {
|
||||||
|
for _, e := range s.Enum.Value {
|
||||||
|
s.AddNode(e.ValueNode.Line, e.ValueNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// determine schema type, singular (3.0) or multiple (3.1), use a variable value
|
// determine schema type, singular (3.0) or multiple (3.1), use a variable value
|
||||||
_, typeLabel, typeValue := utils.FindKeyNodeFullTop(TypeLabel, root.Content)
|
_, typeLabel, typeValue := utils.FindKeyNodeFullTop(TypeLabel, root.Content)
|
||||||
if typeValue != nil {
|
if typeValue != nil {
|
||||||
@@ -630,6 +648,24 @@ func (s *Schema) Build(ctx context.Context, root *yaml.Node, idx *index.SpecInde
|
|||||||
_, expLabel, expNode := utils.FindKeyNodeFullTop(ExampleLabel, root.Content)
|
_, expLabel, expNode := utils.FindKeyNodeFullTop(ExampleLabel, root.Content)
|
||||||
if expNode != nil {
|
if expNode != nil {
|
||||||
s.Example = low.NodeReference[*yaml.Node]{Value: expNode, KeyNode: expLabel, ValueNode: expNode}
|
s.Example = low.NodeReference[*yaml.Node]{Value: expNode, KeyNode: expLabel, ValueNode: expNode}
|
||||||
|
|
||||||
|
// extract nodes for all value nodes down the tree.
|
||||||
|
expChildNodes := low.ExtractNodesRecursive(ctx, expNode)
|
||||||
|
// map to the local schema
|
||||||
|
expChildNodes.Range(func(k, v interface{}) bool {
|
||||||
|
if arr, ko := v.([]*yaml.Node); ko {
|
||||||
|
if ext, ok := s.Nodes.Load(k); ok {
|
||||||
|
if extArr, kk := ext.([]*yaml.Node); kk {
|
||||||
|
s.Nodes.Store(k, append(extArr, arr...))
|
||||||
|
} else {
|
||||||
|
s.Nodes.Store(k, arr)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s.Nodes.Store(k, arr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle examples if set.(3.1)
|
// handle examples if set.(3.1)
|
||||||
@@ -645,6 +681,23 @@ func (s *Schema) Build(ctx context.Context, root *yaml.Node, idx *index.SpecInde
|
|||||||
ValueNode: expArrNode,
|
ValueNode: expArrNode,
|
||||||
KeyNode: expArrLabel,
|
KeyNode: expArrLabel,
|
||||||
}
|
}
|
||||||
|
// extract nodes for all value nodes down the tree.
|
||||||
|
expChildNodes := low.ExtractNodesRecursive(ctx, expArrNode)
|
||||||
|
// map to the local schema
|
||||||
|
expChildNodes.Range(func(k, v interface{}) bool {
|
||||||
|
if arr, ko := v.([]*yaml.Node); ko {
|
||||||
|
if ext, ok := s.Nodes.Load(k); ok {
|
||||||
|
if extArr, kk := ext.([]*yaml.Node); kk {
|
||||||
|
s.Nodes.Store(k, append(extArr, arr...))
|
||||||
|
} else {
|
||||||
|
s.Nodes.Store(k, arr)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s.Nodes.Store(k, arr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -674,7 +727,23 @@ func (s *Schema) Build(ctx context.Context, root *yaml.Node, idx *index.SpecInde
|
|||||||
if discNode != nil {
|
if discNode != nil {
|
||||||
var discriminator Discriminator
|
var discriminator Discriminator
|
||||||
_ = low.BuildModel(discNode, &discriminator)
|
_ = low.BuildModel(discNode, &discriminator)
|
||||||
|
discriminator.KeyNode = discLabel
|
||||||
|
discriminator.RootNode = discNode
|
||||||
|
discriminator.Nodes = low.ExtractNodes(ctx, discNode)
|
||||||
s.Discriminator = low.NodeReference[*Discriminator]{Value: &discriminator, KeyNode: discLabel, ValueNode: discNode}
|
s.Discriminator = low.NodeReference[*Discriminator]{Value: &discriminator, KeyNode: discLabel, ValueNode: discNode}
|
||||||
|
// add discriminator nodes, because there is no build method.
|
||||||
|
dn := low.ExtractNodesRecursive(ctx, discNode)
|
||||||
|
dn.Range(func(key, val any) bool {
|
||||||
|
if n, ok := val.([]*yaml.Node); ok {
|
||||||
|
for _, g := range n {
|
||||||
|
discriminator.AddNode(key.(int), g)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if n, ok := val.(*yaml.Node); ok {
|
||||||
|
discriminator.AddNode(key.(int), n)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle externalDocs if set.
|
// handle externalDocs if set.
|
||||||
@@ -683,6 +752,7 @@ func (s *Schema) Build(ctx context.Context, root *yaml.Node, idx *index.SpecInde
|
|||||||
var exDoc ExternalDoc
|
var exDoc ExternalDoc
|
||||||
_ = low.BuildModel(extDocNode, &exDoc)
|
_ = low.BuildModel(extDocNode, &exDoc)
|
||||||
_ = exDoc.Build(ctx, extDocLabel, extDocNode, idx) // throws no errors, can't check for one.
|
_ = exDoc.Build(ctx, extDocLabel, extDocNode, idx) // throws no errors, can't check for one.
|
||||||
|
exDoc.Nodes = low.ExtractNodes(ctx, extDocNode)
|
||||||
s.ExternalDocs = low.NodeReference[*ExternalDoc]{Value: &exDoc, KeyNode: extDocLabel, ValueNode: extDocNode}
|
s.ExternalDocs = low.NodeReference[*ExternalDoc]{Value: &exDoc, KeyNode: extDocLabel, ValueNode: extDocNode}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -693,11 +763,12 @@ func (s *Schema) Build(ctx context.Context, root *yaml.Node, idx *index.SpecInde
|
|||||||
_ = low.BuildModel(xmlNode, &xml)
|
_ = low.BuildModel(xmlNode, &xml)
|
||||||
// extract extensions if set.
|
// extract extensions if set.
|
||||||
_ = xml.Build(xmlNode, idx) // returns no errors, can't check for one.
|
_ = xml.Build(xmlNode, idx) // returns no errors, can't check for one.
|
||||||
|
xml.Nodes = low.ExtractNodes(ctx, xmlNode)
|
||||||
s.XML = low.NodeReference[*XML]{Value: &xml, KeyNode: xmlLabel, ValueNode: xmlNode}
|
s.XML = low.NodeReference[*XML]{Value: &xml, KeyNode: xmlLabel, ValueNode: xmlNode}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle properties
|
// handle properties
|
||||||
props, err := buildPropertyMap(ctx, root, idx, PropertiesLabel)
|
props, err := buildPropertyMap(ctx, s, root, idx, PropertiesLabel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -706,7 +777,7 @@ func (s *Schema) Build(ctx context.Context, root *yaml.Node, idx *index.SpecInde
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handle dependent schemas
|
// handle dependent schemas
|
||||||
props, err = buildPropertyMap(ctx, root, idx, DependentSchemasLabel)
|
props, err = buildPropertyMap(ctx, s, root, idx, DependentSchemasLabel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -715,7 +786,7 @@ func (s *Schema) Build(ctx context.Context, root *yaml.Node, idx *index.SpecInde
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handle pattern properties
|
// handle pattern properties
|
||||||
props, err = buildPropertyMap(ctx, root, idx, PatternPropertiesLabel)
|
props, err = buildPropertyMap(ctx, s, root, idx, PatternPropertiesLabel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -1013,7 +1084,7 @@ func (s *Schema) Build(ctx context.Context, root *yaml.Node, idx *index.SpecInde
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildPropertyMap(ctx context.Context, root *yaml.Node, idx *index.SpecIndex, label string) (*low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[*SchemaProxy]]], error) {
|
func buildPropertyMap(ctx context.Context, parent *Schema, root *yaml.Node, idx *index.SpecIndex, label string) (*low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[*SchemaProxy]]], error) {
|
||||||
_, propLabel, propsNode := utils.FindKeyNodeFullTop(label, root.Content)
|
_, propLabel, propsNode := utils.FindKeyNodeFullTop(label, root.Content)
|
||||||
if propsNode != nil {
|
if propsNode != nil {
|
||||||
propertyMap := orderedmap.New[low.KeyReference[string], low.ValueReference[*SchemaProxy]]()
|
propertyMap := orderedmap.New[low.KeyReference[string], low.ValueReference[*SchemaProxy]]()
|
||||||
@@ -1021,6 +1092,7 @@ func buildPropertyMap(ctx context.Context, root *yaml.Node, idx *index.SpecIndex
|
|||||||
for i, prop := range propsNode.Content {
|
for i, prop := range propsNode.Content {
|
||||||
if i%2 == 0 {
|
if i%2 == 0 {
|
||||||
currentProp = prop
|
currentProp = prop
|
||||||
|
parent.Nodes.Store(prop.Line, prop)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
@@ -54,6 +55,7 @@ type SchemaProxy struct {
|
|||||||
rendered *Schema
|
rendered *Schema
|
||||||
buildError error
|
buildError error
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
*low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build will prepare the SchemaProxy for rendering, it does not build the Schema, only sets up internal state.
|
// Build will prepare the SchemaProxy for rendering, it does not build the Schema, only sets up internal state.
|
||||||
@@ -66,6 +68,8 @@ func (sp *SchemaProxy) Build(ctx context.Context, key, value *yaml.Node, idx *in
|
|||||||
if rf, _, r := utils.IsNodeRefValue(value); rf {
|
if rf, _, r := utils.IsNodeRefValue(value); rf {
|
||||||
sp.SetReference(r, value)
|
sp.SetReference(r, value)
|
||||||
}
|
}
|
||||||
|
var m sync.Map
|
||||||
|
sp.NodeMap = &low.NodeMap{Nodes: &m}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +97,14 @@ func (sp *SchemaProxy) Schema() *Schema {
|
|||||||
}
|
}
|
||||||
schema.ParentProxy = sp // https://github.com/pb33f/libopenapi/issues/29
|
schema.ParentProxy = sp // https://github.com/pb33f/libopenapi/issues/29
|
||||||
sp.rendered = schema
|
sp.rendered = schema
|
||||||
|
|
||||||
|
// for all the nodes added, copy them over to the schema
|
||||||
|
if sp.NodeMap != nil {
|
||||||
|
sp.NodeMap.Nodes.Range(func(key, value any) bool {
|
||||||
|
schema.AddNode(key.(int), value.(*yaml.Node))
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
return schema
|
return schema
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,3 +170,12 @@ func (sp *SchemaProxy) Hash() [32]byte {
|
|||||||
// hash reference value only, do not resolve!
|
// hash reference value only, do not resolve!
|
||||||
return sha256.Sum256([]byte(sp.GetReference()))
|
return sha256.Sum256([]byte(sp.GetReference()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddNode stores nodes in the underlying schema if rendered, otherwise holds in the proxy until build.
|
||||||
|
func (sp *SchemaProxy) AddNode(key int, node *yaml.Node) {
|
||||||
|
if sp.rendered != nil {
|
||||||
|
sp.rendered.AddNode(key, node)
|
||||||
|
} else {
|
||||||
|
sp.Nodes.Store(key, node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -31,15 +31,18 @@ type SecurityRequirement struct {
|
|||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
ContainsEmptyRequirement bool // if a requirement is empty (this means it's optional)
|
ContainsEmptyRequirement bool // if a requirement is empty (this means it's optional)
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build will extract security requirements from the node (the structure is odd, to be honest)
|
// Build will extract security requirements from the node (the structure is odd, to be honest)
|
||||||
func (s *SecurityRequirement) Build(_ context.Context, keyNode, root *yaml.Node, _ *index.SpecIndex) error {
|
func (s *SecurityRequirement) Build(ctx context.Context, keyNode, root *yaml.Node, _ *index.SpecIndex) error {
|
||||||
|
|
||||||
s.KeyNode = keyNode
|
s.KeyNode = keyNode
|
||||||
root = utils.NodeAlias(root)
|
root = utils.NodeAlias(root)
|
||||||
s.RootNode = root
|
s.RootNode = root
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
s.Reference = new(low.Reference)
|
s.Reference = new(low.Reference)
|
||||||
|
s.Nodes = low.ExtractNodes(ctx, root)
|
||||||
var labelNode *yaml.Node
|
var labelNode *yaml.Node
|
||||||
valueMap := orderedmap.New[low.KeyReference[string], low.ValueReference[[]low.ValueReference[string]]]()
|
valueMap := orderedmap.New[low.KeyReference[string], low.ValueReference[[]low.ValueReference[string]]]()
|
||||||
var arr []low.ValueReference[string]
|
var arr []low.ValueReference[string]
|
||||||
@@ -57,6 +60,7 @@ func (s *SecurityRequirement) Build(_ context.Context, keyNode, root *yaml.Node,
|
|||||||
Value: root.Content[i].Content[j].Value,
|
Value: root.Content[i].Content[j].Value,
|
||||||
ValueNode: root.Content[i].Content[j],
|
ValueNode: root.Content[i].Content[j],
|
||||||
})
|
})
|
||||||
|
s.Nodes.Store(root.Content[i].Content[j].Line, root.Content[i].Content[j])
|
||||||
}
|
}
|
||||||
valueMap.Set(
|
valueMap.Set(
|
||||||
low.KeyReference[string]{
|
low.KeyReference[string]{
|
||||||
@@ -76,6 +80,7 @@ func (s *SecurityRequirement) Build(_ context.Context, keyNode, root *yaml.Node,
|
|||||||
Value: valueMap,
|
Value: valueMap,
|
||||||
ValueNode: root,
|
ValueNode: root,
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ type Tag struct {
|
|||||||
KeyNode *yaml.Node
|
KeyNode *yaml.Node
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindExtension returns a ValueReference containing the extension value, if found.
|
// FindExtension returns a ValueReference containing the extension value, if found.
|
||||||
@@ -53,7 +54,9 @@ func (t *Tag) Build(ctx context.Context, keyNode, root *yaml.Node, idx *index.Sp
|
|||||||
t.RootNode = root
|
t.RootNode = root
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
t.Reference = new(low.Reference)
|
t.Reference = new(low.Reference)
|
||||||
|
t.Nodes = low.ExtractNodes(ctx, root)
|
||||||
t.Extensions = low.ExtractExtensions(root)
|
t.Extensions = low.ExtractExtensions(root)
|
||||||
|
low.ExtractExtensionNodes(ctx, t.Extensions, t.Nodes)
|
||||||
|
|
||||||
// extract externalDocs
|
// extract externalDocs
|
||||||
extDocs, err := low.ExtractObject[*ExternalDoc](ctx, ExternalDocsLabel, root, idx)
|
extDocs, err := low.ExtractObject[*ExternalDoc](ctx, ExternalDocsLabel, root, idx)
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ type XML struct {
|
|||||||
Extensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]
|
Extensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build will extract extensions from the XML instance.
|
// Build will extract extensions from the XML instance.
|
||||||
@@ -38,6 +39,7 @@ func (x *XML) Build(root *yaml.Node, _ *index.SpecIndex) error {
|
|||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
x.RootNode = root
|
x.RootNode = root
|
||||||
x.Reference = new(low.Reference)
|
x.Reference = new(low.Reference)
|
||||||
|
x.Nodes = low.ExtractNodes(nil, root)
|
||||||
x.Extensions = low.ExtractExtensions(root)
|
x.Extensions = low.ExtractExtensions(root)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
148
datamodel/low/node_map.go
Normal file
148
datamodel/low/node_map.go
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
// Copyright 2023-2024 Princess Beef Heavy Industries, LLC / Dave Shanley
|
||||||
|
// https://pb33f.io
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
package low
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HasNodes is an interface that defines a method to get a map of nodes
|
||||||
|
type HasNodes interface {
|
||||||
|
GetNodes() map[int][]*yaml.Node
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddNodes is an interface that defined a method to add nodes.
|
||||||
|
type AddNodes interface {
|
||||||
|
AddNode(key int, node *yaml.Node)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NodeMap represents a map of yaml nodes
|
||||||
|
type NodeMap struct {
|
||||||
|
|
||||||
|
// Nodes is a sync map of nodes for this object, and the key is the line number of the node
|
||||||
|
// a line can contain many nodes (in JSON), so the value is a slice of *yaml.Node
|
||||||
|
Nodes *sync.Map `yaml:"-" json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddNode will add a node to the NodeMap
|
||||||
|
func (nm *NodeMap) AddNode(key int, node *yaml.Node) {
|
||||||
|
if existing, ok := nm.Nodes.Load(key); ok {
|
||||||
|
if ext, ko := existing.(*yaml.Node); ko {
|
||||||
|
nm.Nodes.Store(key, []*yaml.Node{ext, node})
|
||||||
|
}
|
||||||
|
if ext, ko := existing.([]*yaml.Node); ko {
|
||||||
|
ext = append(ext, node)
|
||||||
|
nm.Nodes.Store(key, ext)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nm.Nodes.Store(key, []*yaml.Node{node})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNodes will return the map of nodes
|
||||||
|
func (nm *NodeMap) GetNodes() map[int][]*yaml.Node {
|
||||||
|
composed := make(map[int][]*yaml.Node)
|
||||||
|
nm.Nodes.Range(func(key, value interface{}) bool {
|
||||||
|
if v, ok := value.([]*yaml.Node); ok {
|
||||||
|
composed[key.(int)] = v
|
||||||
|
}
|
||||||
|
if v, ok := value.(*yaml.Node); ok {
|
||||||
|
composed[key.(int)] = []*yaml.Node{v}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
if len(composed) <= 0 {
|
||||||
|
composed[0] = []*yaml.Node{} // return an empty slice if there are no nodes
|
||||||
|
}
|
||||||
|
return composed
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractNodes will iterate over a *yaml.Node and extract all nodes with a line number into a map
|
||||||
|
func (nm *NodeMap) ExtractNodes(node *yaml.Node, recurse bool) {
|
||||||
|
if node == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// if the node has content, iterate over it and extract every top level line number
|
||||||
|
if node.Content != nil {
|
||||||
|
for i := 0; i < len(node.Content); i++ {
|
||||||
|
if node.Content[i].Line != 0 && len(node.Content[i].Content) <= 0 {
|
||||||
|
nm.AddNode(node.Content[i].Line, node.Content[i])
|
||||||
|
}
|
||||||
|
if node.Content[i].Line != 0 && len(node.Content[i].Content) > 0 {
|
||||||
|
if recurse {
|
||||||
|
nm.AddNode(node.Content[i].Line, node.Content[i])
|
||||||
|
nm.ExtractNodes(node.Content[i], recurse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContainsLine will return true if the NodeMap contains a node with the supplied line number
|
||||||
|
func (nm *NodeMap) ContainsLine(line int, recurse bool) bool {
|
||||||
|
if _, ok := nm.Nodes.Load(line); ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractNodes will extract all nodes from a yaml.Node and return them in a map
|
||||||
|
func ExtractNodes(_ context.Context, root *yaml.Node) *sync.Map {
|
||||||
|
var syncMap sync.Map
|
||||||
|
nm := &NodeMap{Nodes: &syncMap}
|
||||||
|
nm.ExtractNodes(root, false)
|
||||||
|
return nm.Nodes
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractNodesRecursive will extract all nodes from a yaml.Node and return them in a map, just like ExtractNodes
|
||||||
|
// however, this version will dive-down the tree and extract all nodes from all child nodes as well until the tree
|
||||||
|
// is done.
|
||||||
|
func ExtractNodesRecursive(_ context.Context, root *yaml.Node) *sync.Map {
|
||||||
|
var syncMap sync.Map
|
||||||
|
nm := &NodeMap{Nodes: &syncMap}
|
||||||
|
nm.ExtractNodes(root, true)
|
||||||
|
return nm.Nodes
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractExtensionNodes will extract all extension nodes from a map of extensions, recursively.
|
||||||
|
func ExtractExtensionNodes(_ context.Context,
|
||||||
|
extensionMap *orderedmap.Map[KeyReference[string],
|
||||||
|
ValueReference[*yaml.Node]], nodeMap *sync.Map) {
|
||||||
|
|
||||||
|
// range over the extension map and extract all nodes
|
||||||
|
for extPairs := extensionMap.First(); extPairs != nil; extPairs = extPairs.Next() {
|
||||||
|
k := extPairs.Key()
|
||||||
|
v := extPairs.Value()
|
||||||
|
|
||||||
|
results := []*yaml.Node{k.KeyNode}
|
||||||
|
var newNodeMap sync.Map
|
||||||
|
nm := &NodeMap{Nodes: &newNodeMap}
|
||||||
|
if len(v.ValueNode.Content) > 0 {
|
||||||
|
nm.ExtractNodes(v.ValueNode, true)
|
||||||
|
nm.Nodes.Range(func(key, value interface{}) bool {
|
||||||
|
for _, n := range value.([]*yaml.Node) {
|
||||||
|
results = append(results, n)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
results = append(results, v.ValueNode)
|
||||||
|
}
|
||||||
|
if k.KeyNode.Line == v.ValueNode.Line {
|
||||||
|
nodeMap.Store(k.KeyNode.Line, results)
|
||||||
|
} else {
|
||||||
|
nodeMap.Store(k.KeyNode.Line, results[0])
|
||||||
|
gingo := results[1:]
|
||||||
|
for _, y := range gingo {
|
||||||
|
nodeMap.Store(y.Line, []*yaml.Node{y})
|
||||||
|
}
|
||||||
|
//nodeMap.Store(v.ValueNode.Line, gingo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
111
datamodel/low/node_map_test.go
Normal file
111
datamodel/low/node_map_test.go
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
// Copyright 2023-2024 Princess Beef Heavy Industries, LLC / Dave Shanley
|
||||||
|
// https://pb33f.io
|
||||||
|
|
||||||
|
package low
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_NodeMapExtractNodes(t *testing.T) {
|
||||||
|
|
||||||
|
yml := `one: hello
|
||||||
|
two: there
|
||||||
|
three: nice one
|
||||||
|
four:
|
||||||
|
shoes: yes
|
||||||
|
socks: of course
|
||||||
|
`
|
||||||
|
|
||||||
|
var root yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &root)
|
||||||
|
var syncMap sync.Map
|
||||||
|
nm := &NodeMap{Nodes: &syncMap}
|
||||||
|
nm.ExtractNodes(root.Content[0], false)
|
||||||
|
testTheThing(t, nm)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func testTheThing(t *testing.T, nm *NodeMap) {
|
||||||
|
count := 0
|
||||||
|
nm.Nodes.Range(func(key, value interface{}) bool {
|
||||||
|
count++
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.Equal(t, 4, count)
|
||||||
|
|
||||||
|
nodes := nm.GetNodes()
|
||||||
|
|
||||||
|
assert.Equal(t, 2, len(nodes[1]))
|
||||||
|
assert.Equal(t, 2, len(nodes[2]))
|
||||||
|
assert.Equal(t, 2, len(nodes[3]))
|
||||||
|
assert.Equal(t, 1, len(nodes[4]))
|
||||||
|
assert.Equal(t, "one", nodes[1][0].Value)
|
||||||
|
assert.Equal(t, "hello", nodes[1][1].Value)
|
||||||
|
assert.Equal(t, "two", nodes[2][0].Value)
|
||||||
|
assert.Equal(t, "there", nodes[2][1].Value)
|
||||||
|
assert.Equal(t, "three", nodes[3][0].Value)
|
||||||
|
assert.Equal(t, "nice one", nodes[3][1].Value)
|
||||||
|
assert.Equal(t, "four", nodes[4][0].Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testTheThingUnmarshalled(t *testing.T, nm *sync.Map) {
|
||||||
|
n := &NodeMap{Nodes: nm}
|
||||||
|
nodes := n.GetNodes()
|
||||||
|
|
||||||
|
assert.Equal(t, 2, len(nodes[1]))
|
||||||
|
assert.Equal(t, 2, len(nodes[2]))
|
||||||
|
assert.Equal(t, 2, len(nodes[3]))
|
||||||
|
assert.Equal(t, 1, len(nodes[4]))
|
||||||
|
assert.Equal(t, "one", nodes[1][0].Value)
|
||||||
|
assert.Equal(t, "hello", nodes[1][1].Value)
|
||||||
|
assert.Equal(t, "two", nodes[2][0].Value)
|
||||||
|
assert.Equal(t, "there", nodes[2][1].Value)
|
||||||
|
assert.Equal(t, "three", nodes[3][0].Value)
|
||||||
|
assert.Equal(t, "nice one", nodes[3][1].Value)
|
||||||
|
assert.Equal(t, "four", nodes[4][0].Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExtractNodes(t *testing.T) {
|
||||||
|
|
||||||
|
yml := `one: hello
|
||||||
|
two: there
|
||||||
|
three: nice one
|
||||||
|
four:
|
||||||
|
shoes: yes
|
||||||
|
socks: of course
|
||||||
|
`
|
||||||
|
|
||||||
|
var root yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(yml), &root)
|
||||||
|
|
||||||
|
nm := ExtractNodes(nil, root.Content[0])
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
nm.Range(func(key, value interface{}) bool {
|
||||||
|
count++
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.Equal(t, 4, count)
|
||||||
|
testTheThingUnmarshalled(t, nm)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExtractNodes_Nil(t *testing.T) {
|
||||||
|
var syncMap sync.Map
|
||||||
|
nm := &NodeMap{Nodes: &syncMap}
|
||||||
|
nm.ExtractNodes(nil, false)
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
nm.Nodes.Range(func(key, value interface{}) bool {
|
||||||
|
count++
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.Equal(t, 0, count)
|
||||||
|
}
|
||||||
@@ -29,6 +29,7 @@ type Callback struct {
|
|||||||
KeyNode *yaml.Node
|
KeyNode *yaml.Node
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExtensions returns all Callback extensions and satisfies the low.HasExtensions interface.
|
// GetExtensions returns all Callback extensions and satisfies the low.HasExtensions interface.
|
||||||
@@ -58,14 +59,18 @@ func (cb *Callback) Build(ctx context.Context, keyNode, root *yaml.Node, idx *in
|
|||||||
cb.RootNode = root
|
cb.RootNode = root
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
cb.Reference = new(low.Reference)
|
cb.Reference = new(low.Reference)
|
||||||
|
cb.Nodes = low.ExtractNodes(ctx, root)
|
||||||
cb.Extensions = low.ExtractExtensions(root)
|
cb.Extensions = low.ExtractExtensions(root)
|
||||||
|
low.ExtractExtensionNodes(ctx, cb.Extensions, cb.Nodes)
|
||||||
|
|
||||||
expressions, err := extractPathItemsMap(ctx, root, idx)
|
expressions, err := extractPathItemsMap(ctx, root, idx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cb.Expression = expressions
|
cb.Expression = expressions
|
||||||
|
for xp := expressions.First(); xp != nil; xp = xp.Next() {
|
||||||
|
cb.Nodes.Store(xp.Key().KeyNode.Line, xp.Key().KeyNode)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@@ -38,6 +39,7 @@ type Components struct {
|
|||||||
KeyNode *yaml.Node
|
KeyNode *yaml.Node
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
type componentBuildResult[T any] struct {
|
type componentBuildResult[T any] struct {
|
||||||
@@ -139,7 +141,9 @@ func (co *Components) Build(ctx context.Context, root *yaml.Node, idx *index.Spe
|
|||||||
root = utils.NodeAlias(root)
|
root = utils.NodeAlias(root)
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
co.Reference = new(low.Reference)
|
co.Reference = new(low.Reference)
|
||||||
|
co.Nodes = low.ExtractNodes(ctx, root)
|
||||||
co.Extensions = low.ExtractExtensions(root)
|
co.Extensions = low.ExtractExtensions(root)
|
||||||
|
low.ExtractExtensionNodes(ctx, co.Extensions, co.Nodes)
|
||||||
co.RootNode = root
|
co.RootNode = root
|
||||||
co.KeyNode = root
|
co.KeyNode = root
|
||||||
var reterr error
|
var reterr error
|
||||||
@@ -156,55 +160,55 @@ func (co *Components) Build(ctx context.Context, root *yaml.Node, idx *index.Spe
|
|||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
schemas, err := extractComponentValues[*base.SchemaProxy](ctx, SchemasLabel, root, idx)
|
schemas, err := extractComponentValues[*base.SchemaProxy](ctx, SchemasLabel, root, idx, co)
|
||||||
captureError(err)
|
captureError(err)
|
||||||
co.Schemas = schemas
|
co.Schemas = schemas
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
parameters, err := extractComponentValues[*Parameter](ctx, ParametersLabel, root, idx)
|
parameters, err := extractComponentValues[*Parameter](ctx, ParametersLabel, root, idx, co)
|
||||||
captureError(err)
|
captureError(err)
|
||||||
co.Parameters = parameters
|
co.Parameters = parameters
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
responses, err := extractComponentValues[*Response](ctx, ResponsesLabel, root, idx)
|
responses, err := extractComponentValues[*Response](ctx, ResponsesLabel, root, idx, co)
|
||||||
captureError(err)
|
captureError(err)
|
||||||
co.Responses = responses
|
co.Responses = responses
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
examples, err := extractComponentValues[*base.Example](ctx, base.ExamplesLabel, root, idx)
|
examples, err := extractComponentValues[*base.Example](ctx, base.ExamplesLabel, root, idx, co)
|
||||||
captureError(err)
|
captureError(err)
|
||||||
co.Examples = examples
|
co.Examples = examples
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
requestBodies, err := extractComponentValues[*RequestBody](ctx, RequestBodiesLabel, root, idx)
|
requestBodies, err := extractComponentValues[*RequestBody](ctx, RequestBodiesLabel, root, idx, co)
|
||||||
captureError(err)
|
captureError(err)
|
||||||
co.RequestBodies = requestBodies
|
co.RequestBodies = requestBodies
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
headers, err := extractComponentValues[*Header](ctx, HeadersLabel, root, idx)
|
headers, err := extractComponentValues[*Header](ctx, HeadersLabel, root, idx, co)
|
||||||
captureError(err)
|
captureError(err)
|
||||||
co.Headers = headers
|
co.Headers = headers
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
securitySchemes, err := extractComponentValues[*SecurityScheme](ctx, SecuritySchemesLabel, root, idx)
|
securitySchemes, err := extractComponentValues[*SecurityScheme](ctx, SecuritySchemesLabel, root, idx, co)
|
||||||
captureError(err)
|
captureError(err)
|
||||||
co.SecuritySchemes = securitySchemes
|
co.SecuritySchemes = securitySchemes
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
links, err := extractComponentValues[*Link](ctx, LinksLabel, root, idx)
|
links, err := extractComponentValues[*Link](ctx, LinksLabel, root, idx, co)
|
||||||
captureError(err)
|
captureError(err)
|
||||||
co.Links = links
|
co.Links = links
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
callbacks, err := extractComponentValues[*Callback](ctx, CallbacksLabel, root, idx)
|
callbacks, err := extractComponentValues[*Callback](ctx, CallbacksLabel, root, idx, co)
|
||||||
captureError(err)
|
captureError(err)
|
||||||
co.Callbacks = callbacks
|
co.Callbacks = callbacks
|
||||||
wg.Done()
|
wg.Done()
|
||||||
@@ -217,12 +221,13 @@ func (co *Components) Build(ctx context.Context, root *yaml.Node, idx *index.Spe
|
|||||||
// extractComponentValues converts all the YAML nodes of a component type to
|
// extractComponentValues converts all the YAML nodes of a component type to
|
||||||
// low level model.
|
// low level model.
|
||||||
// Process each node in parallel.
|
// Process each node in parallel.
|
||||||
func extractComponentValues[T low.Buildable[N], N any](ctx context.Context, label string, root *yaml.Node, idx *index.SpecIndex) (low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[T]]], error) {
|
func extractComponentValues[T low.Buildable[N], N any](ctx context.Context, label string, root *yaml.Node, idx *index.SpecIndex, co *Components) (low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[T]]], error) {
|
||||||
var emptyResult low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[T]]]
|
var emptyResult low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[T]]]
|
||||||
_, nodeLabel, nodeValue := utils.FindKeyNodeFullTop(label, root.Content)
|
_, nodeLabel, nodeValue := utils.FindKeyNodeFullTop(label, root.Content)
|
||||||
if nodeValue == nil {
|
if nodeValue == nil {
|
||||||
return emptyResult, nil
|
return emptyResult, nil
|
||||||
}
|
}
|
||||||
|
co.Nodes.Store(nodeLabel.Line, nodeLabel)
|
||||||
componentValues := orderedmap.New[low.KeyReference[string], low.ValueReference[T]]()
|
componentValues := orderedmap.New[low.KeyReference[string], low.ValueReference[T]]()
|
||||||
if utils.IsNodeArray(nodeValue) {
|
if utils.IsNodeArray(nodeValue) {
|
||||||
return emptyResult, fmt.Errorf("node is array, cannot be used in components: line %d, column %d", nodeValue.Line, nodeValue.Column)
|
return emptyResult, fmt.Errorf("node is array, cannot be used in components: line %d, column %d", nodeValue.Line, nodeValue.Column)
|
||||||
@@ -298,6 +303,21 @@ func extractComponentValues[T low.Buildable[N], N any](ctx context.Context, labe
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return componentBuildResult[T]{}, err
|
return componentBuildResult[T]{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nType := reflect.TypeOf(n)
|
||||||
|
nValue := reflect.ValueOf(n)
|
||||||
|
|
||||||
|
// Check if the type implements low.HasKeyNode
|
||||||
|
hasKeyNodeType := reflect.TypeOf((*low.HasKeyNode)(nil)).Elem()
|
||||||
|
if nType.Implements(hasKeyNodeType) {
|
||||||
|
r := nValue.Interface()
|
||||||
|
if h, ok := r.(low.HasKeyNode); ok {
|
||||||
|
if k, ko := r.(low.AddNodes); ko {
|
||||||
|
k.AddNode(h.GetKeyNode().Line, h.GetKeyNode())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
return componentBuildResult[T]{
|
return componentBuildResult[T]{
|
||||||
key: low.KeyReference[string]{
|
key: low.KeyReference[string]{
|
||||||
KeyNode: currentLabel,
|
KeyNode: currentLabel,
|
||||||
@@ -315,6 +335,10 @@ func extractComponentValues[T low.Buildable[N], N any](ctx context.Context, labe
|
|||||||
return emptyResult, err
|
return emptyResult, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//for rt := componentValues.First(); rt != nil; rt = rt.Next() {
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
|
||||||
results := low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[T]]]{
|
results := low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[T]]]{
|
||||||
KeyNode: nodeLabel,
|
KeyNode: nodeLabel,
|
||||||
ValueNode: nodeValue,
|
ValueNode: nodeValue,
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ func createDocument(info *datamodel.SpecInfo, config *datamodel.DocumentConfigur
|
|||||||
}
|
}
|
||||||
version = low.NodeReference[string]{Value: versionNode.Value, KeyNode: labelNode, ValueNode: versionNode}
|
version = low.NodeReference[string]{Value: versionNode.Value, KeyNode: labelNode, ValueNode: versionNode}
|
||||||
doc := Document{Version: version}
|
doc := Document{Version: version}
|
||||||
|
doc.Nodes = low.ExtractNodes(nil, info.RootNode.Content[0])
|
||||||
// create an index config and shadow the document configuration.
|
// create an index config and shadow the document configuration.
|
||||||
idxConfig := index.CreateClosedAPIIndexConfig()
|
idxConfig := index.CreateClosedAPIIndexConfig()
|
||||||
idxConfig.SpecInfo = info
|
idxConfig.SpecInfo = info
|
||||||
@@ -130,7 +130,12 @@ func createDocument(info *datamodel.SpecInfo, config *datamodel.DocumentConfigur
|
|||||||
doc.Index = rolodex.GetRootIndex()
|
doc.Index = rolodex.GetRootIndex()
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
var cacheMap sync.Map
|
||||||
|
modelContext := base.ModelContext{SchemaCache: &cacheMap}
|
||||||
|
ctx := context.WithValue(context.Background(), "modelCtx", &modelContext)
|
||||||
|
|
||||||
doc.Extensions = low.ExtractExtensions(info.RootNode.Content[0])
|
doc.Extensions = low.ExtractExtensions(info.RootNode.Content[0])
|
||||||
|
low.ExtractExtensionNodes(ctx, doc.Extensions, doc.Nodes)
|
||||||
|
|
||||||
// if set, extract jsonSchemaDialect (3.1)
|
// if set, extract jsonSchemaDialect (3.1)
|
||||||
_, dialectLabel, dialectNode := utils.FindKeyNodeFull(JSONSchemaDialectLabel, info.RootNode.Content)
|
_, dialectLabel, dialectNode := utils.FindKeyNodeFull(JSONSchemaDialectLabel, info.RootNode.Content)
|
||||||
@@ -161,8 +166,6 @@ func createDocument(info *datamodel.SpecInfo, config *datamodel.DocumentConfigur
|
|||||||
extractWebhooks,
|
extractWebhooks,
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
wg.Add(len(extractionFuncs))
|
wg.Add(len(extractionFuncs))
|
||||||
if config.Logger != nil {
|
if config.Logger != nil {
|
||||||
config.Logger.Debug("running extractions")
|
config.Logger.Debug("running extractions")
|
||||||
@@ -310,6 +313,9 @@ func extractWebhooks(ctx context.Context, info *datamodel.SpecInfo, doc *Documen
|
|||||||
KeyNode: hooksL,
|
KeyNode: hooksL,
|
||||||
ValueNode: hooksN,
|
ValueNode: hooksN,
|
||||||
}
|
}
|
||||||
|
for xj := hooks.First(); xj != nil; xj = xj.Next() {
|
||||||
|
xj.Value().Value.Nodes.Store(xj.Key().KeyNode.Line, xj.Key().KeyNode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,6 +86,8 @@ type Document struct {
|
|||||||
|
|
||||||
// Rolodex is a reference to the rolodex used when creating this document.
|
// Rolodex is a reference to the rolodex used when creating this document.
|
||||||
Rolodex *index.Rolodex
|
Rolodex *index.Rolodex
|
||||||
|
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindSecurityRequirement will attempt to locate a security requirement string from a supplied name.
|
// FindSecurityRequirement will attempt to locate a security requirement string from a supplied name.
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ type Encoding struct {
|
|||||||
KeyNode *yaml.Node
|
KeyNode *yaml.Node
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindHeader attempts to locate a Header with the supplied name
|
// FindHeader attempts to locate a Header with the supplied name
|
||||||
@@ -67,6 +68,7 @@ func (en *Encoding) Build(ctx context.Context, keyNode, root *yaml.Node, idx *in
|
|||||||
root = utils.NodeAlias(root)
|
root = utils.NodeAlias(root)
|
||||||
en.RootNode = root
|
en.RootNode = root
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
|
en.Nodes = low.ExtractNodes(ctx, root)
|
||||||
en.Reference = new(low.Reference)
|
en.Reference = new(low.Reference)
|
||||||
headers, hL, hN, err := low.ExtractMap[*Header](ctx, HeadersLabel, root, idx)
|
headers, hL, hN, err := low.ExtractMap[*Header](ctx, HeadersLabel, root, idx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -78,6 +80,10 @@ func (en *Encoding) Build(ctx context.Context, keyNode, root *yaml.Node, idx *in
|
|||||||
KeyNode: hL,
|
KeyNode: hL,
|
||||||
ValueNode: hN,
|
ValueNode: hN,
|
||||||
}
|
}
|
||||||
|
en.Nodes.Store(hL.Line, hL)
|
||||||
|
for xj := headers.First(); xj != nil; xj = xj.Next() {
|
||||||
|
xj.Value().Value.Nodes.Store(xj.Key().KeyNode.Line, xj.Key().KeyNode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ type Header struct {
|
|||||||
KeyNode *yaml.Node
|
KeyNode *yaml.Node
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindExtension will attempt to locate an extension with the supplied name
|
// FindExtension will attempt to locate an extension with the supplied name
|
||||||
@@ -104,8 +105,9 @@ func (h *Header) Build(ctx context.Context, keyNode, root *yaml.Node, idx *index
|
|||||||
h.RootNode = root
|
h.RootNode = root
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
h.Reference = new(low.Reference)
|
h.Reference = new(low.Reference)
|
||||||
|
h.Nodes = low.ExtractNodes(ctx, root)
|
||||||
h.Extensions = low.ExtractExtensions(root)
|
h.Extensions = low.ExtractExtensions(root)
|
||||||
|
low.ExtractExtensionNodes(ctx, h.Extensions, h.Nodes)
|
||||||
// handle example if set.
|
// handle example if set.
|
||||||
_, expLabel, expNode := utils.FindKeyNodeFull(base.ExampleLabel, root.Content)
|
_, expLabel, expNode := utils.FindKeyNodeFull(base.ExampleLabel, root.Content)
|
||||||
if expNode != nil {
|
if expNode != nil {
|
||||||
@@ -114,6 +116,12 @@ func (h *Header) Build(ctx context.Context, keyNode, root *yaml.Node, idx *index
|
|||||||
ValueNode: expNode,
|
ValueNode: expNode,
|
||||||
KeyNode: expLabel,
|
KeyNode: expLabel,
|
||||||
}
|
}
|
||||||
|
h.Nodes.Store(expLabel.Line, expLabel)
|
||||||
|
m := low.ExtractNodes(ctx, expNode)
|
||||||
|
m.Range(func(key, value any) bool {
|
||||||
|
h.Nodes.Store(key, value)
|
||||||
|
return true
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle examples if set.
|
// handle examples if set.
|
||||||
@@ -127,6 +135,7 @@ func (h *Header) Build(ctx context.Context, keyNode, root *yaml.Node, idx *index
|
|||||||
KeyNode: expsL,
|
KeyNode: expsL,
|
||||||
ValueNode: expsN,
|
ValueNode: expsN,
|
||||||
}
|
}
|
||||||
|
h.Nodes.Store(expsL.Line, expsL)
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle schema
|
// handle schema
|
||||||
@@ -148,6 +157,9 @@ func (h *Header) Build(ctx context.Context, keyNode, root *yaml.Node, idx *index
|
|||||||
KeyNode: cL,
|
KeyNode: cL,
|
||||||
ValueNode: cN,
|
ValueNode: cN,
|
||||||
}
|
}
|
||||||
|
if cL != nil {
|
||||||
|
h.Nodes.Store(cL.Line, cL)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ type Link struct {
|
|||||||
KeyNode *yaml.Node
|
KeyNode *yaml.Node
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExtensions returns all Link extensions and satisfies the low.HasExtensions interface.
|
// GetExtensions returns all Link extensions and satisfies the low.HasExtensions interface.
|
||||||
@@ -72,7 +73,17 @@ func (l *Link) Build(ctx context.Context, keyNode, root *yaml.Node, idx *index.S
|
|||||||
l.RootNode = root
|
l.RootNode = root
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
l.Reference = new(low.Reference)
|
l.Reference = new(low.Reference)
|
||||||
|
l.Nodes = low.ExtractNodes(ctx, root)
|
||||||
l.Extensions = low.ExtractExtensions(root)
|
l.Extensions = low.ExtractExtensions(root)
|
||||||
|
low.ExtractExtensionNodes(ctx, l.Extensions, l.Nodes)
|
||||||
|
|
||||||
|
// extract parameter nodes.
|
||||||
|
if l.Parameters.Value != nil && l.Parameters.Value.Len() > 0 {
|
||||||
|
for fk := l.Parameters.Value.First(); fk != nil; fk = fk.Next() {
|
||||||
|
l.Nodes.Store(fk.Key().KeyNode.Line, fk.Key().KeyNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// extract server.
|
// extract server.
|
||||||
ser, sErr := low.ExtractObject[*Server](ctx, ServerLabel, root, idx)
|
ser, sErr := low.ExtractObject[*Server](ctx, ServerLabel, root, idx)
|
||||||
if sErr != nil {
|
if sErr != nil {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ type MediaType struct {
|
|||||||
KeyNode *yaml.Node
|
KeyNode *yaml.Node
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExtensions returns all MediaType extensions and satisfies the low.HasExtensions interface.
|
// GetExtensions returns all MediaType extensions and satisfies the low.HasExtensions interface.
|
||||||
@@ -74,12 +75,20 @@ func (mt *MediaType) Build(ctx context.Context, keyNode, root *yaml.Node, idx *i
|
|||||||
mt.RootNode = root
|
mt.RootNode = root
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
mt.Reference = new(low.Reference)
|
mt.Reference = new(low.Reference)
|
||||||
|
mt.Nodes = low.ExtractNodes(ctx, root)
|
||||||
mt.Extensions = low.ExtractExtensions(root)
|
mt.Extensions = low.ExtractExtensions(root)
|
||||||
|
low.ExtractExtensionNodes(ctx, mt.Extensions, mt.Nodes)
|
||||||
|
|
||||||
// handle example if set.
|
// handle example if set.
|
||||||
_, expLabel, expNode := utils.FindKeyNodeFullTop(base.ExampleLabel, root.Content)
|
_, expLabel, expNode := utils.FindKeyNodeFullTop(base.ExampleLabel, root.Content)
|
||||||
if expNode != nil {
|
if expNode != nil {
|
||||||
mt.Example = low.NodeReference[*yaml.Node]{Value: expNode, KeyNode: expLabel, ValueNode: expNode}
|
mt.Example = low.NodeReference[*yaml.Node]{Value: expNode, KeyNode: expLabel, ValueNode: expNode}
|
||||||
|
mt.Nodes.Store(expLabel.Line, expLabel)
|
||||||
|
m := low.ExtractNodesRecursive(ctx, expNode)
|
||||||
|
m.Range(func(key, value any) bool {
|
||||||
|
mt.Nodes.Store(key, value)
|
||||||
|
return true
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle schema
|
// handle schema
|
||||||
@@ -97,11 +106,16 @@ func (mt *MediaType) Build(ctx context.Context, keyNode, root *yaml.Node, idx *i
|
|||||||
return eErr
|
return eErr
|
||||||
}
|
}
|
||||||
if exps != nil && slices.Contains(root.Content, expsL) {
|
if exps != nil && slices.Contains(root.Content, expsL) {
|
||||||
|
mt.Nodes.Store(expsL.Line, expsL)
|
||||||
|
for xj := exps.First(); xj != nil; xj = xj.Next() {
|
||||||
|
xj.Value().Value.Nodes.Store(xj.Key().KeyNode.Line, xj.Key().KeyNode)
|
||||||
|
}
|
||||||
mt.Examples = low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[*base.Example]]]{
|
mt.Examples = low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[*base.Example]]]{
|
||||||
Value: exps,
|
Value: exps,
|
||||||
KeyNode: expsL,
|
KeyNode: expsL,
|
||||||
ValueNode: expsN,
|
ValueNode: expsN,
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle encoding
|
// handle encoding
|
||||||
@@ -115,6 +129,10 @@ func (mt *MediaType) Build(ctx context.Context, keyNode, root *yaml.Node, idx *i
|
|||||||
KeyNode: encsL,
|
KeyNode: encsL,
|
||||||
ValueNode: encsN,
|
ValueNode: encsN,
|
||||||
}
|
}
|
||||||
|
mt.Nodes.Store(encsL.Line, encsL)
|
||||||
|
for xj := encs.First(); xj != nil; xj = xj.Next() {
|
||||||
|
xj.Value().Value.Nodes.Store(xj.Key().KeyNode.Line, xj.Key().KeyNode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ type OAuthFlows struct {
|
|||||||
KeyNode *yaml.Node
|
KeyNode *yaml.Node
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExtensions returns all OAuthFlows extensions and satisfies the low.HasExtensions interface.
|
// GetExtensions returns all OAuthFlows extensions and satisfies the low.HasExtensions interface.
|
||||||
@@ -56,6 +57,7 @@ func (o *OAuthFlows) Build(ctx context.Context, keyNode, root *yaml.Node, idx *i
|
|||||||
o.RootNode = root
|
o.RootNode = root
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
o.Reference = new(low.Reference)
|
o.Reference = new(low.Reference)
|
||||||
|
o.Nodes = low.ExtractNodes(ctx, root)
|
||||||
o.Extensions = low.ExtractExtensions(root)
|
o.Extensions = low.ExtractExtensions(root)
|
||||||
|
|
||||||
v, vErr := low.ExtractObject[*OAuthFlow](ctx, ImplicitLabel, root, idx)
|
v, vErr := low.ExtractObject[*OAuthFlow](ctx, ImplicitLabel, root, idx)
|
||||||
@@ -113,6 +115,7 @@ type OAuthFlow struct {
|
|||||||
Extensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]
|
Extensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExtensions returns all OAuthFlow extensions and satisfies the low.HasExtensions interface.
|
// GetExtensions returns all OAuthFlow extensions and satisfies the low.HasExtensions interface.
|
||||||
@@ -136,9 +139,18 @@ func (o *OAuthFlow) GetRootNode() *yaml.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build will extract extensions from the node.
|
// Build will extract extensions from the node.
|
||||||
func (o *OAuthFlow) Build(_ context.Context, _, root *yaml.Node, idx *index.SpecIndex) error {
|
func (o *OAuthFlow) Build(ctx context.Context, _, root *yaml.Node, idx *index.SpecIndex) error {
|
||||||
o.Reference = new(low.Reference)
|
o.Reference = new(low.Reference)
|
||||||
|
o.Nodes = low.ExtractNodes(ctx, root)
|
||||||
o.Extensions = low.ExtractExtensions(root)
|
o.Extensions = low.ExtractExtensions(root)
|
||||||
|
low.ExtractExtensionNodes(ctx, o.Extensions, o.Nodes)
|
||||||
|
|
||||||
|
if o.Scopes.Value != nil && o.Scopes.Value.Len() > 0 {
|
||||||
|
for fk := o.Scopes.Value.First(); fk != nil; fk = fk.Next() {
|
||||||
|
o.Nodes.Store(fk.Key().KeyNode.Line, fk.Key().KeyNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
o.RootNode = root
|
o.RootNode = root
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ type Operation struct {
|
|||||||
KeyNode *yaml.Node
|
KeyNode *yaml.Node
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindCallback will attempt to locate a Callback instance by the supplied name.
|
// FindCallback will attempt to locate a Callback instance by the supplied name.
|
||||||
@@ -77,7 +78,9 @@ func (o *Operation) Build(ctx context.Context, keyNode, root *yaml.Node, idx *in
|
|||||||
root = utils.NodeAlias(root)
|
root = utils.NodeAlias(root)
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
o.Reference = new(low.Reference)
|
o.Reference = new(low.Reference)
|
||||||
|
o.Nodes = low.ExtractNodes(ctx, root)
|
||||||
o.Extensions = low.ExtractExtensions(root)
|
o.Extensions = low.ExtractExtensions(root)
|
||||||
|
low.ExtractExtensionNodes(ctx, o.Extensions, o.Nodes)
|
||||||
|
|
||||||
// extract externalDocs
|
// extract externalDocs
|
||||||
extDocs, dErr := low.ExtractObject[*base.ExternalDoc](ctx, base.ExternalDocsLabel, root, idx)
|
extDocs, dErr := low.ExtractObject[*base.ExternalDoc](ctx, base.ExternalDocsLabel, root, idx)
|
||||||
@@ -97,6 +100,7 @@ func (o *Operation) Build(ctx context.Context, keyNode, root *yaml.Node, idx *in
|
|||||||
KeyNode: ln,
|
KeyNode: ln,
|
||||||
ValueNode: vn,
|
ValueNode: vn,
|
||||||
}
|
}
|
||||||
|
o.Nodes.Store(ln.Line, ln)
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract request body
|
// extract request body
|
||||||
@@ -106,6 +110,17 @@ func (o *Operation) Build(ctx context.Context, keyNode, root *yaml.Node, idx *in
|
|||||||
}
|
}
|
||||||
o.RequestBody = rBody
|
o.RequestBody = rBody
|
||||||
|
|
||||||
|
// extract tags, but only extract nodes, the model has already been built
|
||||||
|
k, v := utils.FindKeyNode(TagsLabel, root.Content)
|
||||||
|
if k != nil && v != nil {
|
||||||
|
o.Nodes.Store(k.Line, k)
|
||||||
|
nm := low.ExtractNodesRecursive(ctx, v)
|
||||||
|
nm.Range(func(key, value interface{}) bool {
|
||||||
|
o.Nodes.Store(key, value)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// extract responses
|
// extract responses
|
||||||
respBody, respErr := low.ExtractObject[*Responses](ctx, ResponsesLabel, root, idx)
|
respBody, respErr := low.ExtractObject[*Responses](ctx, ResponsesLabel, root, idx)
|
||||||
if respErr != nil {
|
if respErr != nil {
|
||||||
@@ -124,6 +139,10 @@ func (o *Operation) Build(ctx context.Context, keyNode, root *yaml.Node, idx *in
|
|||||||
KeyNode: cbL,
|
KeyNode: cbL,
|
||||||
ValueNode: cbN,
|
ValueNode: cbN,
|
||||||
}
|
}
|
||||||
|
o.Nodes.Store(cbL.Line, cbL)
|
||||||
|
for xj := callbacks.First(); xj != nil; xj = xj.Next() {
|
||||||
|
xj.Value().Value.Nodes.Store(xj.Key().KeyNode.Line, xj.Key().KeyNode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract security
|
// extract security
|
||||||
@@ -139,6 +158,7 @@ func (o *Operation) Build(ctx context.Context, keyNode, root *yaml.Node, idx *in
|
|||||||
KeyNode: sln,
|
KeyNode: sln,
|
||||||
ValueNode: svn,
|
ValueNode: svn,
|
||||||
}
|
}
|
||||||
|
o.Nodes.Store(sln.Line, sln)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if security is set, but no requirements are defined.
|
// if security is set, but no requirements are defined.
|
||||||
@@ -149,6 +169,7 @@ func (o *Operation) Build(ctx context.Context, keyNode, root *yaml.Node, idx *in
|
|||||||
KeyNode: sln,
|
KeyNode: sln,
|
||||||
ValueNode: svn,
|
ValueNode: svn,
|
||||||
}
|
}
|
||||||
|
o.Nodes.Store(sln.Line, svn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract servers
|
// extract servers
|
||||||
@@ -162,6 +183,7 @@ func (o *Operation) Build(ctx context.Context, keyNode, root *yaml.Node, idx *in
|
|||||||
KeyNode: sl,
|
KeyNode: sl,
|
||||||
ValueNode: sn,
|
ValueNode: sn,
|
||||||
}
|
}
|
||||||
|
o.Nodes.Store(sl.Line, sl)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ type Parameter struct {
|
|||||||
Content low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[*MediaType]]]
|
Content low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[*MediaType]]]
|
||||||
Extensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]
|
Extensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRootNode returns the root yaml node of the Parameter object.
|
// GetRootNode returns the root yaml node of the Parameter object.
|
||||||
@@ -79,12 +80,15 @@ func (p *Parameter) Build(ctx context.Context, keyNode, root *yaml.Node, idx *in
|
|||||||
p.RootNode = root
|
p.RootNode = root
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
p.Reference = new(low.Reference)
|
p.Reference = new(low.Reference)
|
||||||
|
p.Nodes = low.ExtractNodes(ctx, root)
|
||||||
p.Extensions = low.ExtractExtensions(root)
|
p.Extensions = low.ExtractExtensions(root)
|
||||||
|
low.ExtractExtensionNodes(ctx, p.Extensions, p.Nodes)
|
||||||
|
|
||||||
// handle example if set.
|
// handle example if set.
|
||||||
_, expLabel, expNode := utils.FindKeyNodeFullTop(base.ExampleLabel, root.Content)
|
_, expLabel, expNode := utils.FindKeyNodeFullTop(base.ExampleLabel, root.Content)
|
||||||
if expNode != nil {
|
if expNode != nil {
|
||||||
p.Example = low.NodeReference[*yaml.Node]{Value: expNode, KeyNode: expLabel, ValueNode: expNode}
|
p.Example = low.NodeReference[*yaml.Node]{Value: expNode, KeyNode: expLabel, ValueNode: expNode}
|
||||||
|
p.Nodes.Store(expLabel.Line, expLabel)
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle schema
|
// handle schema
|
||||||
@@ -108,6 +112,10 @@ func (p *Parameter) Build(ctx context.Context, keyNode, root *yaml.Node, idx *in
|
|||||||
KeyNode: expsL,
|
KeyNode: expsL,
|
||||||
ValueNode: expsN,
|
ValueNode: expsN,
|
||||||
}
|
}
|
||||||
|
p.Nodes.Store(expsL.Line, expsL)
|
||||||
|
for xj := exps.First(); xj != nil; xj = xj.Next() {
|
||||||
|
xj.Value().Value.Nodes.Store(xj.Key().KeyNode.Line, xj.Key().KeyNode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle content, if set.
|
// handle content, if set.
|
||||||
@@ -120,6 +128,13 @@ func (p *Parameter) Build(ctx context.Context, keyNode, root *yaml.Node, idx *in
|
|||||||
KeyNode: cL,
|
KeyNode: cL,
|
||||||
ValueNode: cN,
|
ValueNode: cN,
|
||||||
}
|
}
|
||||||
|
if cL != nil {
|
||||||
|
p.Nodes.Store(cL.Line, cL)
|
||||||
|
for xj := con.First(); xj != nil; xj = xj.Next() {
|
||||||
|
xj.Value().Value.Nodes.Store(xj.Key().KeyNode.Line, xj.Key().KeyNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ type PathItem struct {
|
|||||||
KeyNode *yaml.Node
|
KeyNode *yaml.Node
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash will return a consistent SHA256 Hash of the PathItem object
|
// Hash will return a consistent SHA256 Hash of the PathItem object
|
||||||
@@ -121,13 +122,14 @@ func (p *PathItem) Build(ctx context.Context, keyNode, root *yaml.Node, idx *ind
|
|||||||
p.RootNode = root
|
p.RootNode = root
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
p.Reference = new(low.Reference)
|
p.Reference = new(low.Reference)
|
||||||
|
p.Nodes = low.ExtractNodes(ctx, root)
|
||||||
p.Extensions = low.ExtractExtensions(root)
|
p.Extensions = low.ExtractExtensions(root)
|
||||||
|
low.ExtractExtensionNodes(ctx, p.Extensions, p.Nodes)
|
||||||
skip := false
|
skip := false
|
||||||
var currentNode *yaml.Node
|
var currentNode *yaml.Node
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
var errors []error
|
var errors []error
|
||||||
|
|
||||||
var ops []low.NodeReference[*Operation]
|
var ops []low.NodeReference[*Operation]
|
||||||
|
|
||||||
// extract parameters
|
// extract parameters
|
||||||
@@ -141,6 +143,7 @@ func (p *PathItem) Build(ctx context.Context, keyNode, root *yaml.Node, idx *ind
|
|||||||
KeyNode: ln,
|
KeyNode: ln,
|
||||||
ValueNode: vn,
|
ValueNode: vn,
|
||||||
}
|
}
|
||||||
|
p.Nodes.Store(ln.Line, ln)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, ln, vn = utils.FindKeyNodeFullTop(ServersLabel, root.Content)
|
_, ln, vn = utils.FindKeyNodeFullTop(ServersLabel, root.Content)
|
||||||
@@ -163,6 +166,7 @@ func (p *PathItem) Build(ctx context.Context, keyNode, root *yaml.Node, idx *ind
|
|||||||
KeyNode: ln,
|
KeyNode: ln,
|
||||||
ValueNode: vn,
|
ValueNode: vn,
|
||||||
}
|
}
|
||||||
|
p.Nodes.Store(ln.Line, ln)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ type Paths struct {
|
|||||||
KeyNode *yaml.Node
|
KeyNode *yaml.Node
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRootNode returns the root yaml node of the Paths object.
|
// GetRootNode returns the root yaml node of the Paths object.
|
||||||
@@ -82,7 +83,9 @@ func (p *Paths) Build(ctx context.Context, keyNode, root *yaml.Node, idx *index.
|
|||||||
p.RootNode = root
|
p.RootNode = root
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
p.Reference = new(low.Reference)
|
p.Reference = new(low.Reference)
|
||||||
|
p.Nodes = low.ExtractNodes(ctx, root)
|
||||||
p.Extensions = low.ExtractExtensions(root)
|
p.Extensions = low.ExtractExtensions(root)
|
||||||
|
low.ExtractExtensionNodes(ctx, p.Extensions, p.Nodes)
|
||||||
|
|
||||||
pathsMap, err := extractPathItemsMap(ctx, root, idx)
|
pathsMap, err := extractPathItemsMap(ctx, root, idx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ type RequestBody struct {
|
|||||||
KeyNode *yaml.Node
|
KeyNode *yaml.Node
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRootNode returns the root yaml node of the RequestBody object.
|
// GetRootNode returns the root yaml node of the RequestBody object.
|
||||||
@@ -60,7 +61,9 @@ func (rb *RequestBody) Build(ctx context.Context, keyNode, root *yaml.Node, idx
|
|||||||
rb.RootNode = root
|
rb.RootNode = root
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
rb.Reference = new(low.Reference)
|
rb.Reference = new(low.Reference)
|
||||||
|
rb.Nodes = low.ExtractNodes(ctx, root)
|
||||||
rb.Extensions = low.ExtractExtensions(root)
|
rb.Extensions = low.ExtractExtensions(root)
|
||||||
|
low.ExtractExtensionNodes(ctx, rb.Extensions, rb.Nodes)
|
||||||
|
|
||||||
// handle content, if set.
|
// handle content, if set.
|
||||||
con, cL, cN, cErr := low.ExtractMap[*MediaType](ctx, ContentLabel, root, idx)
|
con, cL, cN, cErr := low.ExtractMap[*MediaType](ctx, ContentLabel, root, idx)
|
||||||
@@ -73,6 +76,10 @@ func (rb *RequestBody) Build(ctx context.Context, keyNode, root *yaml.Node, idx
|
|||||||
KeyNode: cL,
|
KeyNode: cL,
|
||||||
ValueNode: cN,
|
ValueNode: cN,
|
||||||
}
|
}
|
||||||
|
rb.Nodes.Store(cL.Line, cL)
|
||||||
|
for xj := con.First(); xj != nil; xj = xj.Next() {
|
||||||
|
xj.Value().Value.Nodes.Store(xj.Key().KeyNode.Line, xj.Key().KeyNode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ type Response struct {
|
|||||||
KeyNode *yaml.Node
|
KeyNode *yaml.Node
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRootNode returns the root yaml node of the Response object.
|
// GetRootNode returns the root yaml node of the Response object.
|
||||||
@@ -74,7 +75,9 @@ func (r *Response) Build(ctx context.Context, keyNode, root *yaml.Node, idx *ind
|
|||||||
r.RootNode = root
|
r.RootNode = root
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
r.Reference = new(low.Reference)
|
r.Reference = new(low.Reference)
|
||||||
|
r.Nodes = low.ExtractNodes(ctx, root)
|
||||||
r.Extensions = low.ExtractExtensions(root)
|
r.Extensions = low.ExtractExtensions(root)
|
||||||
|
low.ExtractExtensionNodes(ctx, r.Extensions, r.Nodes)
|
||||||
|
|
||||||
// extract headers
|
// extract headers
|
||||||
headers, lN, kN, err := low.ExtractMapExtensions[*Header](ctx, HeadersLabel, root, idx, true)
|
headers, lN, kN, err := low.ExtractMapExtensions[*Header](ctx, HeadersLabel, root, idx, true)
|
||||||
@@ -87,6 +90,10 @@ func (r *Response) Build(ctx context.Context, keyNode, root *yaml.Node, idx *ind
|
|||||||
KeyNode: lN,
|
KeyNode: lN,
|
||||||
ValueNode: kN,
|
ValueNode: kN,
|
||||||
}
|
}
|
||||||
|
r.Nodes.Store(lN.Line, lN)
|
||||||
|
for xj := headers.First(); xj != nil; xj = xj.Next() {
|
||||||
|
xj.Value().Value.Nodes.Store(xj.Key().KeyNode.Line, xj.Key().KeyNode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
con, clN, cN, cErr := low.ExtractMap[*MediaType](ctx, ContentLabel, root, idx)
|
con, clN, cN, cErr := low.ExtractMap[*MediaType](ctx, ContentLabel, root, idx)
|
||||||
@@ -99,6 +106,10 @@ func (r *Response) Build(ctx context.Context, keyNode, root *yaml.Node, idx *ind
|
|||||||
KeyNode: clN,
|
KeyNode: clN,
|
||||||
ValueNode: cN,
|
ValueNode: cN,
|
||||||
}
|
}
|
||||||
|
r.Nodes.Store(clN.Line, clN)
|
||||||
|
for xj := con.First(); xj != nil; xj = xj.Next() {
|
||||||
|
xj.Value().Value.Nodes.Store(xj.Key().KeyNode.Line, xj.Key().KeyNode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle links if set
|
// handle links if set
|
||||||
@@ -112,6 +123,10 @@ func (r *Response) Build(ctx context.Context, keyNode, root *yaml.Node, idx *ind
|
|||||||
KeyNode: linkLabel,
|
KeyNode: linkLabel,
|
||||||
ValueNode: linkValue,
|
ValueNode: linkValue,
|
||||||
}
|
}
|
||||||
|
r.Nodes.Store(linkLabel.Line, linkLabel)
|
||||||
|
for xj := links.First(); xj != nil; xj = xj.Next() {
|
||||||
|
xj.Value().Value.Nodes.Store(xj.Key().KeyNode.Line, xj.Key().KeyNode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ type Responses struct {
|
|||||||
KeyNode *yaml.Node
|
KeyNode *yaml.Node
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRootNode returns the root yaml node of the Responses object.
|
// GetRootNode returns the root yaml node of the Responses object.
|
||||||
@@ -64,7 +65,9 @@ func (r *Responses) Build(ctx context.Context, keyNode, root *yaml.Node, idx *in
|
|||||||
root = utils.NodeAlias(root)
|
root = utils.NodeAlias(root)
|
||||||
r.RootNode = root
|
r.RootNode = root
|
||||||
r.Reference = new(low.Reference)
|
r.Reference = new(low.Reference)
|
||||||
|
r.Nodes = low.ExtractNodes(ctx, root)
|
||||||
r.Extensions = low.ExtractExtensions(root)
|
r.Extensions = low.ExtractExtensions(root)
|
||||||
|
low.ExtractExtensionNodes(ctx, r.Extensions, r.Nodes)
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
if utils.IsNodeMap(root) {
|
if utils.IsNodeMap(root) {
|
||||||
codes, err := low.ExtractMapNoLookup[*Response](ctx, root, idx)
|
codes, err := low.ExtractMapNoLookup[*Response](ctx, root, idx)
|
||||||
@@ -73,12 +76,17 @@ func (r *Responses) Build(ctx context.Context, keyNode, root *yaml.Node, idx *in
|
|||||||
}
|
}
|
||||||
if codes != nil {
|
if codes != nil {
|
||||||
r.Codes = codes
|
r.Codes = codes
|
||||||
|
for codePairs := codes.First(); codePairs != nil; codePairs = codePairs.Next() {
|
||||||
|
code := codePairs.Key()
|
||||||
|
r.Nodes.Store(code.KeyNode.Line, code.KeyNode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def := r.getDefault()
|
def := r.getDefault()
|
||||||
if def != nil {
|
if def != nil {
|
||||||
// default is bundled into codes, pull it out
|
// default is bundled into codes, pull it out
|
||||||
r.Default = *def
|
r.Default = *def
|
||||||
|
r.Nodes.Store(def.KeyNode.Line, def.KeyNode)
|
||||||
// remove default from codes
|
// remove default from codes
|
||||||
r.deleteCode(DefaultLabel)
|
r.deleteCode(DefaultLabel)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ type SecurityScheme struct {
|
|||||||
KeyNode *yaml.Node
|
KeyNode *yaml.Node
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRootNode returns the root yaml node of the SecurityScheme object.
|
// GetRootNode returns the root yaml node of the SecurityScheme object.
|
||||||
@@ -67,7 +68,9 @@ func (ss *SecurityScheme) Build(ctx context.Context, keyNode, root *yaml.Node, i
|
|||||||
ss.RootNode = root
|
ss.RootNode = root
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
ss.Reference = new(low.Reference)
|
ss.Reference = new(low.Reference)
|
||||||
|
ss.Nodes = low.ExtractNodes(ctx, root)
|
||||||
ss.Extensions = low.ExtractExtensions(root)
|
ss.Extensions = low.ExtractExtensions(root)
|
||||||
|
low.ExtractExtensionNodes(ctx, ss.Extensions, ss.Nodes)
|
||||||
|
|
||||||
oa, oaErr := low.ExtractObject[*OAuthFlows](ctx, OAuthFlowsLabel, root, idx)
|
oa, oaErr := low.ExtractObject[*OAuthFlows](ctx, OAuthFlowsLabel, root, idx)
|
||||||
if oaErr != nil {
|
if oaErr != nil {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ type Server struct {
|
|||||||
KeyNode *yaml.Node
|
KeyNode *yaml.Node
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRootNode returns the root yaml node of the Server object.
|
// GetRootNode returns the root yaml node of the Server object.
|
||||||
@@ -43,13 +44,16 @@ func (s *Server) FindVariable(serverVar string) *low.ValueReference[*ServerVaria
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build will extract server variables from the supplied node.
|
// Build will extract server variables from the supplied node.
|
||||||
func (s *Server) Build(_ context.Context, keyNode, root *yaml.Node, _ *index.SpecIndex) error {
|
func (s *Server) Build(ctx context.Context, keyNode, root *yaml.Node, _ *index.SpecIndex) error {
|
||||||
s.KeyNode = keyNode
|
s.KeyNode = keyNode
|
||||||
root = utils.NodeAlias(root)
|
root = utils.NodeAlias(root)
|
||||||
s.RootNode = root
|
s.RootNode = root
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
s.Reference = new(low.Reference)
|
s.Reference = new(low.Reference)
|
||||||
|
s.Nodes = low.ExtractNodes(ctx, root)
|
||||||
s.Extensions = low.ExtractExtensions(root)
|
s.Extensions = low.ExtractExtensions(root)
|
||||||
|
low.ExtractExtensionNodes(ctx, s.Extensions, s.Nodes)
|
||||||
|
|
||||||
kn, vars := utils.FindKeyNode(VariablesLabel, root.Content)
|
kn, vars := utils.FindKeyNode(VariablesLabel, root.Content)
|
||||||
if vars == nil {
|
if vars == nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -57,20 +61,26 @@ func (s *Server) Build(_ context.Context, keyNode, root *yaml.Node, _ *index.Spe
|
|||||||
variablesMap := orderedmap.New[low.KeyReference[string], low.ValueReference[*ServerVariable]]()
|
variablesMap := orderedmap.New[low.KeyReference[string], low.ValueReference[*ServerVariable]]()
|
||||||
if utils.IsNodeMap(vars) {
|
if utils.IsNodeMap(vars) {
|
||||||
var currentNode string
|
var currentNode string
|
||||||
var keyNode *yaml.Node
|
var localKeyNode *yaml.Node
|
||||||
for i, varNode := range vars.Content {
|
for i, varNode := range vars.Content {
|
||||||
if i%2 == 0 {
|
if i%2 == 0 {
|
||||||
currentNode = varNode.Value
|
currentNode = varNode.Value
|
||||||
keyNode = varNode
|
localKeyNode = varNode
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
variable := ServerVariable{}
|
variable := ServerVariable{}
|
||||||
variable.Reference = new(low.Reference)
|
variable.Reference = new(low.Reference)
|
||||||
_ = low.BuildModel(varNode, &variable)
|
_ = low.BuildModel(varNode, &variable)
|
||||||
|
variable.Nodes = low.ExtractNodesRecursive(ctx, varNode)
|
||||||
|
if localKeyNode != nil {
|
||||||
|
variable.Nodes.Store(localKeyNode.Line, localKeyNode)
|
||||||
|
}
|
||||||
|
variable.RootNode = varNode
|
||||||
|
variable.KeyNode = localKeyNode
|
||||||
variablesMap.Set(
|
variablesMap.Set(
|
||||||
low.KeyReference[string]{
|
low.KeyReference[string]{
|
||||||
Value: currentNode,
|
Value: currentNode,
|
||||||
KeyNode: keyNode,
|
KeyNode: localKeyNode,
|
||||||
},
|
},
|
||||||
low.ValueReference[*ServerVariable]{
|
low.ValueReference[*ServerVariable]{
|
||||||
ValueNode: varNode,
|
ValueNode: varNode,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -19,7 +20,20 @@ type ServerVariable struct {
|
|||||||
Enum []low.NodeReference[string]
|
Enum []low.NodeReference[string]
|
||||||
Default low.NodeReference[string]
|
Default low.NodeReference[string]
|
||||||
Description low.NodeReference[string]
|
Description low.NodeReference[string]
|
||||||
|
KeyNode *yaml.Node
|
||||||
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
|
low.NodeMap
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRootNode returns the root yaml node of the ServerVariable object.
|
||||||
|
func (s *ServerVariable) GetRootNode() *yaml.Node {
|
||||||
|
return s.RootNode
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKeyNode returns the key yaml node of the ServerVariable object.
|
||||||
|
func (s *ServerVariable) GetKeyNode() *yaml.Node {
|
||||||
|
return s.RootNode
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash will return a consistent SHA256 Hash of the ServerVariable object
|
// Hash will return a consistent SHA256 Hash of the ServerVariable object
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ const (
|
|||||||
// used by the library, this contains the top of the document tree that every single low model is based off.
|
// used by the library, this contains the top of the document tree that every single low model is based off.
|
||||||
type SpecInfo struct {
|
type SpecInfo struct {
|
||||||
SpecType string `json:"type"`
|
SpecType string `json:"type"`
|
||||||
|
NumLines int `json:"numLines"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
VersionNumeric float32 `json:"versionNumeric"`
|
VersionNumeric float32 `json:"versionNumeric"`
|
||||||
SpecFormat string `json:"format"`
|
SpecFormat string `json:"format"`
|
||||||
@@ -62,7 +63,8 @@ func ExtractSpecInfoWithDocumentCheck(spec []byte, bypass bool) (*SpecInfo, erro
|
|||||||
// set original bytes
|
// set original bytes
|
||||||
specInfo.SpecBytes = &spec
|
specInfo.SpecBytes = &spec
|
||||||
|
|
||||||
runes := []rune(strings.TrimSpace(string(spec)))
|
stringSpec := string(spec)
|
||||||
|
runes := []rune(strings.TrimSpace(stringSpec))
|
||||||
if len(runes) <= 0 {
|
if len(runes) <= 0 {
|
||||||
return specInfo, errors.New("there is nothing in the spec, it's empty - so there is nothing to be done")
|
return specInfo, errors.New("there is nothing in the spec, it's empty - so there is nothing to be done")
|
||||||
}
|
}
|
||||||
@@ -73,6 +75,8 @@ func ExtractSpecInfoWithDocumentCheck(spec []byte, bypass bool) (*SpecInfo, erro
|
|||||||
specInfo.SpecFileType = YAMLFileType
|
specInfo.SpecFileType = YAMLFileType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
specInfo.NumLines = strings.Count(stringSpec, "\n") + 1
|
||||||
|
|
||||||
err := yaml.Unmarshal(spec, &parsedSpec)
|
err := yaml.Unmarshal(spec, &parsedSpec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to parse specification: %s", err.Error())
|
return nil, fmt.Errorf("unable to parse specification: %s", err.Error())
|
||||||
|
|||||||
@@ -365,7 +365,7 @@ func TestDocument_RenderAndReload_WithErrors(t *testing.T) {
|
|||||||
|
|
||||||
_, _, _, errors := doc.RenderAndReload()
|
_, _, _, errors := doc.RenderAndReload()
|
||||||
assert.Len(t, errors, 2)
|
assert.Len(t, errors, 2)
|
||||||
assert.Equal(t, errors[0].Error(), "component '#/components/schemas/Pet' does not exist in the specification")
|
assert.Equal(t, errors[0].Error(), "component `#/components/schemas/Pet` does not exist in the specification")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDocument_Render(t *testing.T) {
|
func TestDocument_Render(t *testing.T) {
|
||||||
|
|||||||
1
go.mod
1
go.mod
@@ -7,6 +7,7 @@ require (
|
|||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.8.4
|
||||||
github.com/vmware-labs/yaml-jsonpath v0.3.2
|
github.com/vmware-labs/yaml-jsonpath v0.3.2
|
||||||
github.com/wk8/go-ordered-map/v2 v2.1.8
|
github.com/wk8/go-ordered-map/v2 v2.1.8
|
||||||
|
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -274,7 +274,7 @@ paths:
|
|||||||
|
|
||||||
index := NewSpecIndexWithConfig(&rootNode, c)
|
index := NewSpecIndexWithConfig(&rootNode, c)
|
||||||
assert.Len(t, index.GetReferenceIndexErrors(), 1)
|
assert.Len(t, index.GetReferenceIndexErrors(), 1)
|
||||||
assert.Equal(t, "component '#/paths/~1pet~1%$petId%7D/get/parameters' does not exist in the specification", index.GetReferenceIndexErrors()[0].Error())
|
assert.Equal(t, "component `#/paths/~1pet~1%$petId%7D/get/parameters` does not exist in the specification", index.GetReferenceIndexErrors()[0].Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSpecIndex_LocateRemoteDocsWithEscapedCharacters(t *testing.T) {
|
func TestSpecIndex_LocateRemoteDocsWithEscapedCharacters(t *testing.T) {
|
||||||
|
|||||||
@@ -121,6 +121,11 @@ func (r *Rolodex) GetRootIndex() *SpecIndex {
|
|||||||
return r.rootIndex
|
return r.rootIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetConfig returns the index configuration of the rolodex.
|
||||||
|
func (r *Rolodex) GetConfig() *SpecIndexConfig {
|
||||||
|
return r.indexConfig
|
||||||
|
}
|
||||||
|
|
||||||
// GetRootNode returns the root index of the rolodex (the entry point, the main document)
|
// GetRootNode returns the root index of the rolodex (the entry point, the main document)
|
||||||
func (r *Rolodex) GetRootNode() *yaml.Node {
|
func (r *Rolodex) GetRootNode() *yaml.Node {
|
||||||
return r.rootNode
|
return r.rootNode
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ func TestRolodex_NewRolodex(t *testing.T) {
|
|||||||
assert.Nil(t, rolo.GetRootIndex())
|
assert.Nil(t, rolo.GetRootIndex())
|
||||||
assert.Len(t, rolo.GetIndexes(), 0)
|
assert.Len(t, rolo.GetIndexes(), 0)
|
||||||
assert.Len(t, rolo.GetCaughtErrors(), 0)
|
assert.Len(t, rolo.GetCaughtErrors(), 0)
|
||||||
|
assert.NotNil(t, rolo.GetConfig())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRolodex_NoFS(t *testing.T) {
|
func TestRolodex_NoFS(t *testing.T) {
|
||||||
|
|||||||
@@ -613,6 +613,12 @@ func IsJSON(testString string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IsYAML will tell you if a string is YAML or not.
|
// IsYAML will tell you if a string is YAML or not.
|
||||||
|
var (
|
||||||
|
yamlKeyValuePattern = regexp.MustCompile(`(?m)^\s*[a-zA-Z0-9_-]+\s*:\s*.+$`)
|
||||||
|
yamlListPattern = regexp.MustCompile(`(?m)^\s*-\s+.+$`)
|
||||||
|
yamlHeaderPattern = regexp.MustCompile(`(?m)^---\s*$`)
|
||||||
|
)
|
||||||
|
|
||||||
func IsYAML(testString string) bool {
|
func IsYAML(testString string) bool {
|
||||||
if testString == "" {
|
if testString == "" {
|
||||||
return false
|
return false
|
||||||
@@ -620,13 +626,21 @@ func IsYAML(testString string) bool {
|
|||||||
if IsJSON(testString) {
|
if IsJSON(testString) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
var n interface{}
|
|
||||||
err := yaml.Unmarshal([]byte(testString), &n)
|
// Trim leading and trailing whitespace
|
||||||
if err != nil {
|
s := strings.TrimSpace(testString)
|
||||||
return false
|
|
||||||
|
// Fast checks for common YAML features
|
||||||
|
if strings.Contains(s, ": ") || strings.Contains(s, "- ") || strings.Contains(s, "\n- ") {
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
_, err = yaml.Marshal(n)
|
|
||||||
return err == nil
|
// Regular expressions for more robust detection
|
||||||
|
if yamlKeyValuePattern.MatchString(s) || yamlListPattern.MatchString(s) || yamlHeaderPattern.MatchString(s) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConvertYAMLtoJSON will do exactly what you think it will. It will deserialize YAML into serialized JSON.
|
// ConvertYAMLtoJSON will do exactly what you think it will. It will deserialize YAML into serialized JSON.
|
||||||
|
|||||||
@@ -672,10 +672,10 @@ func TestIsJSON(t *testing.T) {
|
|||||||
|
|
||||||
func TestIsYAML(t *testing.T) {
|
func TestIsYAML(t *testing.T) {
|
||||||
assert.True(t, IsYAML("hello:\n there:\n my-name: is quobix"))
|
assert.True(t, IsYAML("hello:\n there:\n my-name: is quobix"))
|
||||||
assert.True(t, IsYAML("potato shoes"))
|
assert.False(t, IsYAML("potato shoes"))
|
||||||
assert.False(t, IsYAML("{'hello':'there'}"))
|
assert.False(t, IsYAML("{'hello':'there'}"))
|
||||||
assert.False(t, IsYAML(""))
|
assert.False(t, IsYAML(""))
|
||||||
assert.False(t, IsYAML("8908: hello: yeah: \n12309812: :123"))
|
assert.True(t, IsYAML("8908: hello: yeah: \n12309812: :123"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConvertYAMLtoJSON(t *testing.T) {
|
func TestConvertYAMLtoJSON(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user