mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-06 04:20:11 +00:00
149 lines
4.3 KiB
Go
149 lines
4.3 KiB
Go
// 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)
|
|
}
|
|
}
|
|
}
|