go-yaml/ast/ast.go

1726 lines
39 KiB
Go
Raw Normal View History

2019-10-16 18:21:01 +09:00
package ast
import (
"fmt"
"io"
2019-10-16 18:21:01 +09:00
"math"
"strconv"
"strings"
"github.com/goccy/go-yaml/token"
2020-05-28 21:39:06 +09:00
"golang.org/x/xerrors"
)
var (
ErrInvalidTokenType = xerrors.New("invalid token type")
ErrInvalidAnchorName = xerrors.New("invalid anchor name")
ErrInvalidAliasName = xerrors.New("invalid alias name")
2019-10-16 18:21:01 +09:00
)
2019-10-21 03:33:41 +09:00
// NodeType type identifier of node
type NodeType int
const (
2019-10-21 03:49:01 +09:00
// UnknownNodeType type identifier for default
2019-10-21 03:33:41 +09:00
UnknownNodeType NodeType = iota
2019-10-21 03:49:01 +09:00
// DocumentType type identifier for document node
2019-10-21 03:33:41 +09:00
DocumentType
2019-10-21 03:49:01 +09:00
// NullType type identifier for null node
2019-10-21 03:33:41 +09:00
NullType
2019-10-21 03:49:01 +09:00
// BoolType type identifier for boolean node
2019-10-21 03:33:41 +09:00
BoolType
2019-10-21 03:49:01 +09:00
// IntegerType type identifier for integer node
2019-10-21 03:33:41 +09:00
IntegerType
2019-10-21 03:49:01 +09:00
// FloatType type identifier for float node
2019-10-21 03:33:41 +09:00
FloatType
2019-10-21 03:49:01 +09:00
// InfinityType type identifier for infinity node
2019-10-21 03:33:41 +09:00
InfinityType
2019-10-21 03:49:01 +09:00
// NanType type identifier for nan node
2019-10-21 03:33:41 +09:00
NanType
2019-10-21 03:49:01 +09:00
// StringType type identifier for string node
2019-10-21 03:33:41 +09:00
StringType
2019-10-21 03:49:01 +09:00
// MergeKeyType type identifier for merge key node
2019-10-21 03:33:41 +09:00
MergeKeyType
2019-10-21 03:49:01 +09:00
// LiteralType type identifier for literal node
2019-10-21 03:33:41 +09:00
LiteralType
// MappingType type identifier for mapping node
MappingType
2020-07-02 17:21:31 +09:00
// MappingKeyType type identifier for mapping key node
MappingKeyType
2019-10-21 03:49:01 +09:00
// MappingValueType type identifier for mapping value node
2019-10-21 03:33:41 +09:00
MappingValueType
2019-10-21 03:49:01 +09:00
// SequenceType type identifier for sequence node
2019-10-21 03:33:41 +09:00
SequenceType
2019-10-21 03:49:01 +09:00
// AnchorType type identifier for anchor node
2019-10-21 03:33:41 +09:00
AnchorType
2019-10-21 03:49:01 +09:00
// AliasType type identifier for alias node
2019-10-21 03:33:41 +09:00
AliasType
2019-10-21 03:49:01 +09:00
// DirectiveType type identifier for directive node
2019-10-21 03:33:41 +09:00
DirectiveType
2019-10-21 03:49:01 +09:00
// TagType type identifier for tag node
2019-10-21 03:33:41 +09:00
TagType
2020-05-28 21:39:06 +09:00
// CommentType type identifier for comment node
CommentType
2019-10-21 03:33:41 +09:00
)
2019-10-24 23:51:50 +09:00
// String node type identifier to text
func (t NodeType) String() string {
switch t {
case UnknownNodeType:
return "UnknownNode"
case DocumentType:
return "Document"
case NullType:
return "Null"
case BoolType:
return "Bool"
case IntegerType:
return "Integer"
case FloatType:
return "Float"
case InfinityType:
return "Infinity"
case NanType:
return "Nan"
case StringType:
return "String"
case MergeKeyType:
return "MergeKey"
case LiteralType:
return "Literal"
case MappingType:
return "Mapping"
2020-07-02 17:21:31 +09:00
case MappingKeyType:
return "MappingKey"
2019-10-24 23:51:50 +09:00
case MappingValueType:
return "MappingValue"
case SequenceType:
return "Sequence"
case AnchorType:
return "Anchor"
case AliasType:
return "Alias"
case DirectiveType:
return "Directive"
case TagType:
return "Tag"
2020-05-28 21:39:06 +09:00
case CommentType:
return "Comment"
2019-10-24 23:51:50 +09:00
}
return ""
}
// String node type identifier to YAML Structure name
// based on https://yaml.org/spec/1.2/spec.html
func (t NodeType) YAMLName() string {
switch t {
case UnknownNodeType:
return "unknown"
case DocumentType:
return "document"
case NullType:
return "null"
case BoolType:
return "boolean"
case IntegerType:
return "int"
case FloatType:
return "float"
case InfinityType:
return "inf"
case NanType:
return "nan"
case StringType:
return "string"
case MergeKeyType:
return "merge key"
case LiteralType:
return "scalar"
case MappingType:
return "mapping"
case MappingKeyType:
return "key"
case MappingValueType:
return "value"
case SequenceType:
return "sequence"
case AnchorType:
return "anchor"
case AliasType:
return "alias"
case DirectiveType:
return "directive"
case TagType:
return "tag"
case CommentType:
return "comment"
}
return ""
}
2019-10-21 03:33:41 +09:00
// Node type of node
type Node interface {
io.Reader
2019-10-21 03:33:41 +09:00
// String node to text
String() string
// GetToken returns token instance
GetToken() *token.Token
// Type returns type of node
Type() NodeType
// AddColumn add column number to child nodes recursively
AddColumn(int)
2020-05-28 21:39:06 +09:00
// SetComment set comment token to node
SetComment(*token.Token) error
// Comment returns comment token instance
GetComment() *token.Token
2021-03-01 13:45:13 +09:00
// MarshalYAML
MarshalYAML() ([]byte, error)
// already read length
readLen() int
// append read length
addReadLen(int)
2021-01-29 17:27:48 +09:00
// clean read length
clearLen()
2019-10-21 03:33:41 +09:00
}
// ScalarNode type for scalar node
type ScalarNode interface {
Node
GetValue() interface{}
2019-11-05 17:02:55 +09:00
}
type BaseNode struct {
Comment *token.Token
read int
2019-11-05 17:02:55 +09:00
}
func (n *BaseNode) readLen() int {
return n.read
2019-11-05 17:02:55 +09:00
}
2021-01-29 17:27:48 +09:00
func (n *BaseNode) clearLen() {
n.read = 0
}
func (n *BaseNode) addReadLen(len int) {
n.read += len
2019-10-16 18:21:01 +09:00
}
2020-05-28 21:39:06 +09:00
// GetComment returns comment token instance
func (n *BaseNode) GetComment() *token.Token {
return n.Comment
}
2020-05-28 21:39:06 +09:00
// SetComment set comment token
func (n *BaseNode) SetComment(tk *token.Token) error {
2020-05-28 21:39:06 +09:00
if tk.Type != token.CommentType {
return ErrInvalidTokenType
}
n.Comment = tk
2020-05-28 21:39:06 +09:00
return nil
}
func min(a, b int) int {
if a < b {
return a
2019-10-16 18:21:01 +09:00
}
return b
2019-10-16 18:21:01 +09:00
}
func readNode(p []byte, node Node) (int, error) {
s := node.String()
readLen := node.readLen()
remain := len(s) - readLen
if remain == 0 {
2021-01-29 17:27:48 +09:00
node.clearLen()
return 0, io.EOF
}
size := min(remain, len(p))
for idx, b := range s[readLen : readLen+size] {
p[idx] = byte(b)
}
node.addReadLen(size)
return size, nil
2019-10-16 18:21:01 +09:00
}
2019-10-21 03:33:41 +09:00
// Null create node for null value
func Null(tk *token.Token) Node {
return &NullNode{
BaseNode: &BaseNode{},
Token: tk,
2019-10-16 18:21:01 +09:00
}
2019-10-21 03:33:41 +09:00
}
// Bool create node for boolean value
func Bool(tk *token.Token) Node {
b, _ := strconv.ParseBool(tk.Value)
return &BoolNode{
BaseNode: &BaseNode{},
Token: tk,
Value: b,
2019-10-16 18:21:01 +09:00
}
2019-10-21 03:33:41 +09:00
}
// Integer create node for integer value
func Integer(tk *token.Token) Node {
value := removeUnderScoreFromNumber(tk.Value)
switch tk.Type {
case token.BinaryIntegerType:
// skip two characters because binary token starts with '0b'
skipCharacterNum := 2
negativePrefix := ""
if value[0] == '-' {
skipCharacterNum++
negativePrefix = "-"
}
2019-10-29 20:15:27 +09:00
if len(negativePrefix) > 0 {
i, _ := strconv.ParseInt(negativePrefix+value[skipCharacterNum:], 2, 64)
return &IntegerNode{
BaseNode: &BaseNode{},
Token: tk,
Value: i,
}
2019-10-29 20:15:27 +09:00
}
i, _ := strconv.ParseUint(negativePrefix+value[skipCharacterNum:], 2, 64)
return &IntegerNode{
BaseNode: &BaseNode{},
Token: tk,
Value: i,
}
case token.OctetIntegerType:
// octet token starts with '0o' or '-0o' or '0' or '-0'
skipCharacterNum := 1
negativePrefix := ""
if value[0] == '-' {
skipCharacterNum++
2021-02-02 15:53:34 +09:00
if len(value) > 2 && value[2] == 'o' {
skipCharacterNum++
}
negativePrefix = "-"
} else {
if value[1] == 'o' {
skipCharacterNum++
}
}
2019-10-29 20:15:27 +09:00
if len(negativePrefix) > 0 {
i, _ := strconv.ParseInt(negativePrefix+value[skipCharacterNum:], 8, 64)
return &IntegerNode{
BaseNode: &BaseNode{},
Token: tk,
Value: i,
}
2019-10-29 20:15:27 +09:00
}
i, _ := strconv.ParseUint(value[skipCharacterNum:], 8, 64)
return &IntegerNode{
BaseNode: &BaseNode{},
Token: tk,
Value: i,
}
case token.HexIntegerType:
// hex token starts with '0x' or '-0x'
skipCharacterNum := 2
negativePrefix := ""
if value[0] == '-' {
skipCharacterNum++
negativePrefix = "-"
}
2019-10-29 20:15:27 +09:00
if len(negativePrefix) > 0 {
i, _ := strconv.ParseInt(negativePrefix+value[skipCharacterNum:], 16, 64)
return &IntegerNode{
BaseNode: &BaseNode{},
Token: tk,
Value: i,
}
2019-10-29 20:15:27 +09:00
}
i, _ := strconv.ParseUint(value[skipCharacterNum:], 16, 64)
return &IntegerNode{
BaseNode: &BaseNode{},
Token: tk,
Value: i,
}
}
2019-10-29 20:15:27 +09:00
if value[0] == '-' || value[0] == '+' {
i, _ := strconv.ParseInt(value, 10, 64)
return &IntegerNode{
BaseNode: &BaseNode{},
Token: tk,
Value: i,
}
2019-10-16 18:21:01 +09:00
}
2019-10-29 20:15:27 +09:00
i, _ := strconv.ParseUint(value, 10, 64)
return &IntegerNode{
BaseNode: &BaseNode{},
Token: tk,
Value: i,
}
2019-10-21 03:33:41 +09:00
}
// Float create node for float value
func Float(tk *token.Token) Node {
f, _ := strconv.ParseFloat(removeUnderScoreFromNumber(tk.Value), 64)
2019-10-21 03:33:41 +09:00
return &FloatNode{
BaseNode: &BaseNode{},
Token: tk,
Value: f,
2019-10-16 18:21:01 +09:00
}
2019-10-21 03:33:41 +09:00
}
// Infinity create node for .inf or -.inf value
func Infinity(tk *token.Token) *InfinityNode {
2019-10-21 03:33:41 +09:00
node := &InfinityNode{
BaseNode: &BaseNode{},
Token: tk,
2019-10-16 18:21:01 +09:00
}
2019-10-21 03:33:41 +09:00
switch tk.Value {
2019-10-31 17:23:56 +09:00
case ".inf", ".Inf", ".INF":
2019-10-21 03:33:41 +09:00
node.Value = math.Inf(0)
2019-10-31 17:23:56 +09:00
case "-.inf", "-.Inf", "-.INF":
2019-10-21 03:33:41 +09:00
node.Value = math.Inf(-1)
2019-10-16 18:21:01 +09:00
}
2019-10-21 03:33:41 +09:00
return node
}
// Nan create node for .nan value
func Nan(tk *token.Token) *NanNode {
return &NanNode{
BaseNode: &BaseNode{},
Token: tk,
}
2019-10-21 03:33:41 +09:00
}
// String create node for string value
func String(tk *token.Token) *StringNode {
2019-10-21 03:33:41 +09:00
return &StringNode{
BaseNode: &BaseNode{},
Token: tk,
Value: tk.Value,
2019-10-16 18:21:01 +09:00
}
2019-10-21 03:33:41 +09:00
}
2020-05-28 21:39:06 +09:00
// Comment create node for comment
func Comment(tk *token.Token) *CommentNode {
return &CommentNode{
BaseNode: &BaseNode{Comment: tk},
}
2020-05-28 21:39:06 +09:00
}
2019-10-21 03:33:41 +09:00
// MergeKey create node for merge key ( << )
func MergeKey(tk *token.Token) *MergeKeyNode {
2019-10-21 03:33:41 +09:00
return &MergeKeyNode{
BaseNode: &BaseNode{},
Token: tk,
2019-10-16 18:21:01 +09:00
}
2019-10-21 03:33:41 +09:00
}
2019-10-16 18:21:01 +09:00
// Mapping create node for map
func Mapping(tk *token.Token, isFlowStyle bool, values ...*MappingValueNode) *MappingNode {
node := &MappingNode{
BaseNode: &BaseNode{},
2019-10-31 12:47:23 +09:00
Start: tk,
IsFlowStyle: isFlowStyle,
Values: []*MappingValueNode{},
}
node.Values = append(node.Values, values...)
return node
}
// MappingValue create node for mapping value
func MappingValue(tk *token.Token, key Node, value Node) *MappingValueNode {
return &MappingValueNode{
BaseNode: &BaseNode{},
Start: tk,
Key: key,
Value: value,
}
2019-10-31 12:47:23 +09:00
}
2020-07-02 17:21:31 +09:00
// MappingKey create node for map key ( '?' ).
func MappingKey(tk *token.Token) *MappingKeyNode {
return &MappingKeyNode{
BaseNode: &BaseNode{},
Start: tk,
2020-07-02 17:21:31 +09:00
}
}
// Sequence create node for sequence
func Sequence(tk *token.Token, isFlowStyle bool) *SequenceNode {
return &SequenceNode{
BaseNode: &BaseNode{},
Start: tk,
IsFlowStyle: isFlowStyle,
Values: []Node{},
}
}
func Anchor(tk *token.Token) *AnchorNode {
return &AnchorNode{
BaseNode: &BaseNode{},
Start: tk,
}
}
func Alias(tk *token.Token) *AliasNode {
return &AliasNode{
BaseNode: &BaseNode{},
Start: tk,
}
}
func Document(tk *token.Token, body Node) *DocumentNode {
return &DocumentNode{
BaseNode: &BaseNode{},
Start: tk,
Body: body,
}
}
func Directive(tk *token.Token) *DirectiveNode {
return &DirectiveNode{
BaseNode: &BaseNode{},
Start: tk,
}
}
func Literal(tk *token.Token) *LiteralNode {
return &LiteralNode{
BaseNode: &BaseNode{},
Start: tk,
}
}
func Tag(tk *token.Token) *TagNode {
return &TagNode{
BaseNode: &BaseNode{},
Start: tk,
}
}
// File contains all documents in YAML file
type File struct {
Name string
Docs []*DocumentNode
}
// Read implements (io.Reader).Read
func (f *File) Read(p []byte) (int, error) {
for _, doc := range f.Docs {
n, err := doc.Read(p)
if err == io.EOF {
continue
}
return n, nil
}
return 0, io.EOF
}
// String all documents to text
func (f *File) String() string {
docs := []string{}
for _, doc := range f.Docs {
docs = append(docs, doc.String())
}
return strings.Join(docs, "\n")
}
// DocumentNode type of Document
type DocumentNode struct {
*BaseNode
Start *token.Token // position of DocumentHeader ( `---` )
End *token.Token // position of DocumentEnd ( `...` )
Body Node
}
// Read implements (io.Reader).Read
func (d *DocumentNode) Read(p []byte) (int, error) {
return readNode(p, d)
}
// Type returns DocumentNodeType
func (d *DocumentNode) Type() NodeType { return DocumentType }
// GetToken returns token instance
func (d *DocumentNode) GetToken() *token.Token {
return d.Body.GetToken()
}
// AddColumn add column number to child nodes recursively
func (d *DocumentNode) AddColumn(col int) {
if d.Body != nil {
d.Body.AddColumn(col)
}
}
// String document to text
func (d *DocumentNode) String() string {
doc := []string{}
if d.Start != nil {
doc = append(doc, d.Start.Value)
}
doc = append(doc, d.Body.String())
if d.End != nil {
doc = append(doc, d.End.Value)
}
return strings.Join(doc, "\n")
}
2021-03-01 13:45:13 +09:00
// MarshalYAML encodes to a YAML text
func (d *DocumentNode) MarshalYAML() ([]byte, error) {
return []byte(d.String()), nil
}
func removeUnderScoreFromNumber(num string) string {
return strings.ReplaceAll(num, "_", "")
}
2019-10-21 03:33:41 +09:00
// NullNode type of null node
2019-10-16 18:21:01 +09:00
type NullNode struct {
*BaseNode
2020-05-28 21:39:06 +09:00
Comment *token.Token // position of Comment ( `#comment` )
Token *token.Token
2019-10-16 18:21:01 +09:00
}
// Read implements (io.Reader).Read
func (n *NullNode) Read(p []byte) (int, error) {
return readNode(p, n)
}
2019-10-21 03:33:41 +09:00
// Type returns NullType
func (n *NullNode) Type() NodeType { return NullType }
// GetToken returns token instance
2019-10-16 18:21:01 +09:00
func (n *NullNode) GetToken() *token.Token {
return n.Token
}
// AddColumn add column number to child nodes recursively
func (n *NullNode) AddColumn(col int) {
n.Token.AddColumn(col)
}
2020-05-28 21:39:06 +09:00
// SetComment set comment token
func (n *NullNode) SetComment(tk *token.Token) error {
if tk.Type != token.CommentType {
return ErrInvalidTokenType
}
n.Comment = tk
return nil
}
2019-10-21 03:33:41 +09:00
// GetValue returns nil value
2019-10-16 18:21:01 +09:00
func (n *NullNode) GetValue() interface{} {
return nil
}
2019-10-21 03:33:41 +09:00
// String returns `null` text
2019-10-16 18:21:01 +09:00
func (n *NullNode) String() string {
return "null"
}
2021-03-01 13:45:13 +09:00
// MarshalYAML encodes to a YAML text
func (n *NullNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
2019-10-21 03:33:41 +09:00
// IntegerNode type of integer node
2019-10-16 18:21:01 +09:00
type IntegerNode struct {
*BaseNode
Token *token.Token
Value interface{} // int64 or uint64 value
}
// Read implements (io.Reader).Read
func (n *IntegerNode) Read(p []byte) (int, error) {
return readNode(p, n)
2019-10-16 18:21:01 +09:00
}
2019-10-21 03:33:41 +09:00
// Type returns IntegerType
func (n *IntegerNode) Type() NodeType { return IntegerType }
// GetToken returns token instance
2019-10-16 18:21:01 +09:00
func (n *IntegerNode) GetToken() *token.Token {
return n.Token
}
// AddColumn add column number to child nodes recursively
func (n *IntegerNode) AddColumn(col int) {
n.Token.AddColumn(col)
}
2019-10-21 03:33:41 +09:00
// GetValue returns int64 value
2019-10-16 18:21:01 +09:00
func (n *IntegerNode) GetValue() interface{} {
return n.Value
}
2019-10-21 03:33:41 +09:00
// String int64 to text
2019-10-16 18:21:01 +09:00
func (n *IntegerNode) String() string {
return n.Token.Value
}
2021-03-01 13:45:13 +09:00
// MarshalYAML encodes to a YAML text
func (n *IntegerNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
2019-10-21 03:33:41 +09:00
// FloatNode type of float node
2019-10-16 18:21:01 +09:00
type FloatNode struct {
*BaseNode
2019-10-16 18:21:01 +09:00
Token *token.Token
Precision int
Value float64
}
// Read implements (io.Reader).Read
func (n *FloatNode) Read(p []byte) (int, error) {
return readNode(p, n)
}
2019-10-21 03:33:41 +09:00
// Type returns FloatType
func (n *FloatNode) Type() NodeType { return FloatType }
// GetToken returns token instance
2019-10-16 18:21:01 +09:00
func (n *FloatNode) GetToken() *token.Token {
return n.Token
}
// AddColumn add column number to child nodes recursively
func (n *FloatNode) AddColumn(col int) {
n.Token.AddColumn(col)
}
2019-10-21 03:33:41 +09:00
// GetValue returns float64 value
2019-10-16 18:21:01 +09:00
func (n *FloatNode) GetValue() interface{} {
return n.Value
}
2019-10-21 03:33:41 +09:00
// String float64 to text
2019-10-16 18:21:01 +09:00
func (n *FloatNode) String() string {
return n.Token.Value
}
2021-03-01 13:45:13 +09:00
// MarshalYAML encodes to a YAML text
func (n *FloatNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
2019-10-21 03:33:41 +09:00
// StringNode type of string node
2019-10-16 18:21:01 +09:00
type StringNode struct {
*BaseNode
Token *token.Token
Value string
}
// Read implements (io.Reader).Read
func (n *StringNode) Read(p []byte) (int, error) {
return readNode(p, n)
2019-10-16 18:21:01 +09:00
}
2019-10-21 03:33:41 +09:00
// Type returns StringType
func (n *StringNode) Type() NodeType { return StringType }
// GetToken returns token instance
2019-10-16 18:21:01 +09:00
func (n *StringNode) GetToken() *token.Token {
return n.Token
}
// AddColumn add column number to child nodes recursively
func (n *StringNode) AddColumn(col int) {
n.Token.AddColumn(col)
}
2019-10-21 03:33:41 +09:00
// GetValue returns string value
2019-10-16 18:21:01 +09:00
func (n *StringNode) GetValue() interface{} {
return n.Value
}
// String string value to text with quote or literal header if required
2019-10-16 18:21:01 +09:00
func (n *StringNode) String() string {
switch n.Token.Type {
case token.SingleQuoteType:
return fmt.Sprintf(`'%s'`, n.Value)
case token.DoubleQuoteType:
2020-06-16 15:24:59 +09:00
return strconv.Quote(n.Value)
2019-10-16 18:21:01 +09:00
}
lbc := token.DetectLineBreakCharacter(n.Value)
if strings.Contains(n.Value, lbc) {
2020-02-17 22:12:08 +09:00
// This block assumes that the line breaks in this inside scalar content and the Outside scalar content are the same.
// It works mostly, but inconsistencies occur if line break characters are mixed.
header := token.LiteralBlockHeader(n.Value)
space := strings.Repeat(" ", n.Token.Position.Column-1)
values := []string{}
for _, v := range strings.Split(n.Value, lbc) {
values = append(values, fmt.Sprintf("%s %s", space, v))
}
block := strings.TrimSuffix(strings.TrimSuffix(strings.Join(values, lbc), fmt.Sprintf("%s %s", lbc, space)), fmt.Sprintf(" %s", space))
return fmt.Sprintf("%s%s%s", header, lbc, block)
} else if len(n.Value) > 0 && (n.Value[0] == '{' || n.Value[0] == '[') {
return fmt.Sprintf(`'%s'`, n.Value)
}
2019-10-16 18:21:01 +09:00
return n.Value
}
2021-03-01 13:45:13 +09:00
// MarshalYAML encodes to a YAML text
func (n *StringNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
2019-10-21 03:33:41 +09:00
// LiteralNode type of literal node
2019-10-16 18:21:01 +09:00
type LiteralNode struct {
*BaseNode
Start *token.Token
Value *StringNode
}
// Read implements (io.Reader).Read
func (n *LiteralNode) Read(p []byte) (int, error) {
return readNode(p, n)
2019-10-16 18:21:01 +09:00
}
2019-10-21 03:33:41 +09:00
// Type returns LiteralType
func (n *LiteralNode) Type() NodeType { return LiteralType }
// GetToken returns token instance
2019-10-16 18:21:01 +09:00
func (n *LiteralNode) GetToken() *token.Token {
return n.Start
}
// AddColumn add column number to child nodes recursively
func (n *LiteralNode) AddColumn(col int) {
n.Start.AddColumn(col)
if n.Value != nil {
n.Value.AddColumn(col)
}
}
2019-10-21 03:33:41 +09:00
// GetValue returns string value
2019-10-16 18:21:01 +09:00
func (n *LiteralNode) GetValue() interface{} {
return n.String()
2019-10-16 18:21:01 +09:00
}
2019-10-21 03:33:41 +09:00
// String literal to text
2019-10-16 18:21:01 +09:00
func (n *LiteralNode) String() string {
2019-11-07 23:45:39 +09:00
origin := n.Value.GetToken().Origin
return fmt.Sprintf("%s\n%s", n.Start.Value, strings.TrimRight(strings.TrimRight(origin, " "), "\n"))
2019-10-16 18:21:01 +09:00
}
2021-03-01 13:45:13 +09:00
// MarshalYAML encodes to a YAML text
func (n *LiteralNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
2019-10-21 03:33:41 +09:00
// MergeKeyNode type of merge key node
2019-10-16 18:21:01 +09:00
type MergeKeyNode struct {
*BaseNode
Token *token.Token
}
// Read implements (io.Reader).Read
func (n *MergeKeyNode) Read(p []byte) (int, error) {
return readNode(p, n)
2019-10-16 18:21:01 +09:00
}
2019-10-21 03:33:41 +09:00
// Type returns MergeKeyType
func (n *MergeKeyNode) Type() NodeType { return MergeKeyType }
// GetToken returns token instance
2019-10-16 18:21:01 +09:00
func (n *MergeKeyNode) GetToken() *token.Token {
return n.Token
}
2019-10-21 03:33:41 +09:00
// GetValue returns '<<' value
2019-10-16 18:21:01 +09:00
func (n *MergeKeyNode) GetValue() interface{} {
return n.Token.Value
}
2019-10-21 03:33:41 +09:00
// String returns '<<' value
2019-10-16 18:21:01 +09:00
func (n *MergeKeyNode) String() string {
return n.Token.Value
}
2020-03-02 23:07:02 +09:00
// AddColumn add column number to child nodes recursively
func (n *MergeKeyNode) AddColumn(col int) {
n.Token.AddColumn(col)
}
2021-03-01 13:45:13 +09:00
// MarshalYAML encodes to a YAML text
func (n *MergeKeyNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
2019-10-21 03:33:41 +09:00
// BoolNode type of boolean node
2019-10-16 18:21:01 +09:00
type BoolNode struct {
*BaseNode
Token *token.Token
Value bool
}
// Read implements (io.Reader).Read
func (n *BoolNode) Read(p []byte) (int, error) {
return readNode(p, n)
2019-10-16 18:21:01 +09:00
}
2019-10-21 03:33:41 +09:00
// Type returns BoolType
func (n *BoolNode) Type() NodeType { return BoolType }
// GetToken returns token instance
2019-10-16 18:21:01 +09:00
func (n *BoolNode) GetToken() *token.Token {
return n.Token
}
// AddColumn add column number to child nodes recursively
func (n *BoolNode) AddColumn(col int) {
n.Token.AddColumn(col)
}
2019-10-21 03:33:41 +09:00
// GetValue returns boolean value
2019-10-16 18:21:01 +09:00
func (n *BoolNode) GetValue() interface{} {
return n.Value
}
2019-10-21 03:33:41 +09:00
// String boolean to text
2019-10-16 18:21:01 +09:00
func (n *BoolNode) String() string {
return n.Token.Value
}
2021-03-01 13:45:13 +09:00
// MarshalYAML encodes to a YAML text
func (n *BoolNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
2019-10-21 03:33:41 +09:00
// InfinityNode type of infinity node
2019-10-16 18:21:01 +09:00
type InfinityNode struct {
*BaseNode
Token *token.Token
Value float64
}
// Read implements (io.Reader).Read
func (n *InfinityNode) Read(p []byte) (int, error) {
return readNode(p, n)
2019-10-16 18:21:01 +09:00
}
2019-10-21 03:33:41 +09:00
// Type returns InfinityType
func (n *InfinityNode) Type() NodeType { return InfinityType }
// GetToken returns token instance
2019-10-16 18:21:01 +09:00
func (n *InfinityNode) GetToken() *token.Token {
return n.Token
}
// AddColumn add column number to child nodes recursively
func (n *InfinityNode) AddColumn(col int) {
n.Token.AddColumn(col)
}
2019-10-21 03:33:41 +09:00
// GetValue returns math.Inf(0) or math.Inf(-1)
2019-10-16 18:21:01 +09:00
func (n *InfinityNode) GetValue() interface{} {
return n.Value
}
2019-10-21 03:33:41 +09:00
// String infinity to text
2019-10-16 18:21:01 +09:00
func (n *InfinityNode) String() string {
return n.Token.Value
}
2021-03-01 13:45:13 +09:00
// MarshalYAML encodes to a YAML text
func (n *InfinityNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
2019-10-21 03:33:41 +09:00
// NanNode type of nan node
2019-10-16 18:21:01 +09:00
type NanNode struct {
*BaseNode
Token *token.Token
}
// Read implements (io.Reader).Read
func (n *NanNode) Read(p []byte) (int, error) {
return readNode(p, n)
2019-10-16 18:21:01 +09:00
}
2019-10-21 03:33:41 +09:00
// Type returns NanType
func (n *NanNode) Type() NodeType { return NanType }
// GetToken returns token instance
2019-10-16 18:21:01 +09:00
func (n *NanNode) GetToken() *token.Token {
return n.Token
}
// AddColumn add column number to child nodes recursively
func (n *NanNode) AddColumn(col int) {
n.Token.AddColumn(col)
}
2019-10-21 03:33:41 +09:00
// GetValue returns math.NaN()
2019-10-16 18:21:01 +09:00
func (n *NanNode) GetValue() interface{} {
return math.NaN()
}
2019-10-21 03:33:41 +09:00
// String returns .nan
2019-10-16 18:21:01 +09:00
func (n *NanNode) String() string {
return n.Token.Value
}
2021-03-01 13:45:13 +09:00
// MarshalYAML encodes to a YAML text
func (n *NanNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
// MapNode interface of MappingValueNode / MappingNode
2019-10-24 23:52:43 +09:00
type MapNode interface {
MapRange() *MapNodeIter
}
// MapNodeIter is an iterator for ranging over a MapNode
type MapNodeIter struct {
values []*MappingValueNode
idx int
}
const (
startRangeIndex = -1
)
// Next advances the map iterator and reports whether there is another entry.
// It returns false when the iterator is exhausted.
func (m *MapNodeIter) Next() bool {
m.idx++
next := m.idx < len(m.values)
return next
}
// Key returns the key of the iterator's current map node entry.
func (m *MapNodeIter) Key() Node {
return m.values[m.idx].Key
}
// Value returns the value of the iterator's current map node entry.
func (m *MapNodeIter) Value() Node {
return m.values[m.idx].Value
}
// MappingNode type of mapping node
type MappingNode struct {
*BaseNode
Start *token.Token
End *token.Token
IsFlowStyle bool
Values []*MappingValueNode
2019-10-16 18:21:01 +09:00
}
2020-07-16 15:10:36 +09:00
func (n *MappingNode) startPos() *token.Position {
if len(n.Values) == 0 {
return n.Start.Position
}
return n.Values[0].Key.GetToken().Position
}
2020-07-16 14:18:26 +09:00
// Merge merge key/value of map.
func (n *MappingNode) Merge(target *MappingNode) {
keyToMapValueMap := map[string]*MappingValueNode{}
for _, value := range n.Values {
key := value.Key.String()
keyToMapValueMap[key] = value
}
2020-07-16 15:10:36 +09:00
column := n.startPos().Column - target.startPos().Column
2020-07-16 14:18:26 +09:00
target.AddColumn(column)
for _, value := range target.Values {
mapValue, exists := keyToMapValueMap[value.Key.String()]
if exists {
mapValue.Value = value.Value
} else {
n.Values = append(n.Values, value)
}
}
}
2020-11-13 11:53:41 +09:00
// SetIsFlowStyle set value to IsFlowStyle field recursively.
func (n *MappingNode) SetIsFlowStyle(isFlow bool) {
n.IsFlowStyle = isFlow
for _, value := range n.Values {
value.SetIsFlowStyle(isFlow)
}
}
// Read implements (io.Reader).Read
func (n *MappingNode) Read(p []byte) (int, error) {
return readNode(p, n)
}
// Type returns MappingType
func (n *MappingNode) Type() NodeType { return MappingType }
2019-10-21 03:33:41 +09:00
// GetToken returns token instance
func (n *MappingNode) GetToken() *token.Token {
2019-10-16 18:21:01 +09:00
return n.Start
}
// AddColumn add column number to child nodes recursively
func (n *MappingNode) AddColumn(col int) {
n.Start.AddColumn(col)
n.End.AddColumn(col)
for _, value := range n.Values {
value.AddColumn(col)
}
}
func (n *MappingNode) flowStyleString() string {
if len(n.Values) == 0 {
return "{}"
}
2019-10-16 18:21:01 +09:00
values := []string{}
for _, value := range n.Values {
values = append(values, strings.TrimLeft(value.String(), " "))
}
return fmt.Sprintf("{%s}", strings.Join(values, ", "))
}
func (n *MappingNode) blockStyleString() string {
if len(n.Values) == 0 {
return "{}"
}
2019-10-16 18:21:01 +09:00
values := []string{}
for _, value := range n.Values {
values = append(values, value.String())
}
return strings.Join(values, "\n")
}
// String mapping values to text
func (n *MappingNode) String() string {
if n.IsFlowStyle || len(n.Values) == 0 {
return n.flowStyleString()
}
return n.blockStyleString()
}
2019-10-24 23:52:43 +09:00
// MapRange implements MapNode protocol
func (n *MappingNode) MapRange() *MapNodeIter {
2019-10-24 23:52:43 +09:00
return &MapNodeIter{
idx: startRangeIndex,
values: n.Values,
2019-10-24 23:52:43 +09:00
}
}
2021-03-01 13:45:13 +09:00
// MarshalYAML encodes to a YAML text
func (n *MappingNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
2020-07-02 17:21:31 +09:00
// MappingKeyNode type of tag node
type MappingKeyNode struct {
*BaseNode
Start *token.Token
Value Node
}
// Read implements (io.Reader).Read
func (n *MappingKeyNode) Read(p []byte) (int, error) {
return readNode(p, n)
2020-07-02 17:21:31 +09:00
}
// Type returns MappingKeyType
func (n *MappingKeyNode) Type() NodeType { return MappingKeyType }
// GetToken returns token instance
func (n *MappingKeyNode) GetToken() *token.Token {
return n.Start
}
// AddColumn add column number to child nodes recursively
func (n *MappingKeyNode) AddColumn(col int) {
n.Start.AddColumn(col)
if n.Value != nil {
n.Value.AddColumn(col)
}
}
// String tag to text
func (n *MappingKeyNode) String() string {
return fmt.Sprintf("%s %s", n.Start.Value, n.Value.String())
}
2021-03-01 13:45:13 +09:00
// MarshalYAML encodes to a YAML text
func (n *MappingKeyNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
2019-10-21 03:33:41 +09:00
// MappingValueNode type of mapping value
2019-10-16 18:21:01 +09:00
type MappingValueNode struct {
*BaseNode
Start *token.Token
Key Node
Value Node
}
2020-07-16 14:18:26 +09:00
// Replace replace value node.
func (n *MappingValueNode) Replace(value Node) error {
column := n.Value.GetToken().Position.Column - value.GetToken().Position.Column
value.AddColumn(column)
n.Value = value
return nil
}
// Read implements (io.Reader).Read
func (n *MappingValueNode) Read(p []byte) (int, error) {
return readNode(p, n)
2019-10-16 18:21:01 +09:00
}
2019-10-21 03:33:41 +09:00
// Type returns MappingValueType
func (n *MappingValueNode) Type() NodeType { return MappingValueType }
// GetToken returns token instance
2019-10-16 18:21:01 +09:00
func (n *MappingValueNode) GetToken() *token.Token {
return n.Start
}
// AddColumn add column number to child nodes recursively
func (n *MappingValueNode) AddColumn(col int) {
n.Start.AddColumn(col)
if n.Key != nil {
n.Key.AddColumn(col)
}
if n.Value != nil {
n.Value.AddColumn(col)
}
}
2020-11-13 11:53:41 +09:00
// SetIsFlowStyle set value to IsFlowStyle field recursively.
func (n *MappingValueNode) SetIsFlowStyle(isFlow bool) {
switch value := n.Value.(type) {
case *MappingNode:
value.SetIsFlowStyle(isFlow)
case *MappingValueNode:
value.SetIsFlowStyle(isFlow)
case *SequenceNode:
value.SetIsFlowStyle(isFlow)
}
}
2019-10-21 03:33:41 +09:00
// String mapping value to text
2019-10-16 18:21:01 +09:00
func (n *MappingValueNode) String() string {
space := strings.Repeat(" ", n.Key.GetToken().Position.Column-1)
keyIndentLevel := n.Key.GetToken().Position.IndentLevel
valueIndentLevel := n.Value.GetToken().Position.IndentLevel
if _, ok := n.Value.(ScalarNode); ok {
return fmt.Sprintf("%s%s: %s", space, n.Key.String(), n.Value.String())
} else if keyIndentLevel < valueIndentLevel {
return fmt.Sprintf("%s%s:\n%s", space, n.Key.String(), n.Value.String())
2020-03-09 22:53:26 +09:00
} else if m, ok := n.Value.(*MappingNode); ok && (m.IsFlowStyle || len(m.Values) == 0) {
return fmt.Sprintf("%s%s: %s", space, n.Key.String(), n.Value.String())
2020-03-09 22:53:26 +09:00
} else if s, ok := n.Value.(*SequenceNode); ok && (s.IsFlowStyle || len(s.Values) == 0) {
2020-03-09 21:58:05 +09:00
return fmt.Sprintf("%s%s: %s", space, n.Key.String(), n.Value.String())
2019-10-16 18:21:01 +09:00
} else if _, ok := n.Value.(*AnchorNode); ok {
return fmt.Sprintf("%s%s: %s", space, n.Key.String(), n.Value.String())
} else if _, ok := n.Value.(*AliasNode); ok {
return fmt.Sprintf("%s%s: %s", space, n.Key.String(), n.Value.String())
}
return fmt.Sprintf("%s%s:\n%s", space, n.Key.String(), n.Value.String())
}
2019-10-24 23:52:43 +09:00
// MapRange implements MapNode protocol
func (n *MappingValueNode) MapRange() *MapNodeIter {
return &MapNodeIter{
idx: startRangeIndex,
values: []*MappingValueNode{n},
}
}
2021-03-01 13:45:13 +09:00
// MarshalYAML encodes to a YAML text
func (n *MappingValueNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
// ArrayNode interface of SequenceNode
2019-10-24 23:52:43 +09:00
type ArrayNode interface {
ArrayRange() *ArrayNodeIter
}
// ArrayNodeIter is an iterator for ranging over a ArrayNode
type ArrayNodeIter struct {
values []Node
idx int
}
// Next advances the array iterator and reports whether there is another entry.
// It returns false when the iterator is exhausted.
func (m *ArrayNodeIter) Next() bool {
m.idx++
next := m.idx < len(m.values)
return next
}
// Value returns the value of the iterator's current array entry.
func (m *ArrayNodeIter) Value() Node {
return m.values[m.idx]
}
// Len returns length of array
func (m *ArrayNodeIter) Len() int {
return len(m.values)
}
// SequenceNode type of sequence node
type SequenceNode struct {
*BaseNode
Start *token.Token
End *token.Token
IsFlowStyle bool
Values []Node
2019-10-16 18:21:01 +09:00
}
2020-07-16 14:18:26 +09:00
// Replace replace value node.
func (n *SequenceNode) Replace(idx int, value Node) error {
if len(n.Values) <= idx {
return xerrors.Errorf(
"invalid index for sequence: sequence length is %d, but specified %d index",
len(n.Values), idx,
)
}
column := n.Values[idx].GetToken().Position.Column - value.GetToken().Position.Column
value.AddColumn(column)
n.Values[idx] = value
return nil
}
// Merge merge sequence value.
func (n *SequenceNode) Merge(target *SequenceNode) {
column := n.Start.Position.Column - target.Start.Position.Column
target.AddColumn(column)
for _, value := range target.Values {
n.Values = append(n.Values, value)
}
}
2020-11-13 11:53:41 +09:00
// SetIsFlowStyle set value to IsFlowStyle field recursively.
func (n *SequenceNode) SetIsFlowStyle(isFlow bool) {
n.IsFlowStyle = isFlow
for _, value := range n.Values {
switch value := value.(type) {
case *MappingNode:
value.SetIsFlowStyle(isFlow)
case *MappingValueNode:
value.SetIsFlowStyle(isFlow)
case *SequenceNode:
value.SetIsFlowStyle(isFlow)
}
}
}
// Read implements (io.Reader).Read
func (n *SequenceNode) Read(p []byte) (int, error) {
return readNode(p, n)
}
// Type returns SequenceType
func (n *SequenceNode) Type() NodeType { return SequenceType }
2019-10-21 03:33:41 +09:00
// GetToken returns token instance
func (n *SequenceNode) GetToken() *token.Token {
2019-10-16 18:21:01 +09:00
return n.Start
}
// AddColumn add column number to child nodes recursively
func (n *SequenceNode) AddColumn(col int) {
n.Start.AddColumn(col)
n.End.AddColumn(col)
for _, value := range n.Values {
value.AddColumn(col)
}
}
func (n *SequenceNode) flowStyleString() string {
2019-10-16 18:21:01 +09:00
values := []string{}
for _, value := range n.Values {
values = append(values, value.String())
}
return fmt.Sprintf("[%s]", strings.Join(values, ", "))
}
func (n *SequenceNode) blockStyleString() string {
2019-10-16 18:21:01 +09:00
space := strings.Repeat(" ", n.Start.Position.Column-1)
values := []string{}
for _, value := range n.Values {
valueStr := value.String()
splittedValues := strings.Split(valueStr, "\n")
trimmedFirstValue := strings.TrimLeft(splittedValues[0], " ")
diffLength := len(splittedValues[0]) - len(trimmedFirstValue)
newValues := []string{trimmedFirstValue}
for i := 1; i < len(splittedValues); i++ {
if len(splittedValues[i]) <= diffLength {
// this line is \n or white space only
newValues = append(newValues, "")
continue
}
2019-10-16 18:21:01 +09:00
trimmed := splittedValues[i][diffLength:]
newValues = append(newValues, fmt.Sprintf("%s %s", space, trimmed))
}
newValue := strings.Join(newValues, "\n")
values = append(values, fmt.Sprintf("%s- %s", space, newValue))
}
return strings.Join(values, "\n")
}
// String sequence to text
func (n *SequenceNode) String() string {
2020-03-09 21:58:05 +09:00
if n.IsFlowStyle || len(n.Values) == 0 {
return n.flowStyleString()
}
return n.blockStyleString()
}
2019-10-24 23:52:43 +09:00
// ArrayRange implements ArrayNode protocol
func (n *SequenceNode) ArrayRange() *ArrayNodeIter {
return &ArrayNodeIter{
idx: startRangeIndex,
values: n.Values,
}
}
2021-03-01 13:45:13 +09:00
// MarshalYAML encodes to a YAML text
func (n *SequenceNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
2019-10-21 03:33:41 +09:00
// AnchorNode type of anchor node
2019-10-16 18:21:01 +09:00
type AnchorNode struct {
*BaseNode
Start *token.Token
Name Node
Value Node
}
func (n *AnchorNode) SetName(name string) error {
if n.Name == nil {
return ErrInvalidAnchorName
}
s, ok := n.Name.(*StringNode)
if !ok {
return ErrInvalidAnchorName
}
s.Value = name
return nil
}
// Read implements (io.Reader).Read
func (n *AnchorNode) Read(p []byte) (int, error) {
return readNode(p, n)
2019-10-16 18:21:01 +09:00
}
2019-10-21 03:33:41 +09:00
// Type returns AnchorType
func (n *AnchorNode) Type() NodeType { return AnchorType }
// GetToken returns token instance
2019-10-16 18:21:01 +09:00
func (n *AnchorNode) GetToken() *token.Token {
return n.Start
}
// AddColumn add column number to child nodes recursively
func (n *AnchorNode) AddColumn(col int) {
n.Start.AddColumn(col)
if n.Name != nil {
n.Name.AddColumn(col)
}
if n.Value != nil {
n.Value.AddColumn(col)
}
}
2019-10-21 03:33:41 +09:00
// String anchor to text
2019-10-16 18:21:01 +09:00
func (n *AnchorNode) String() string {
2019-10-19 22:01:36 +09:00
value := n.Value.String()
if len(strings.Split(value, "\n")) > 1 {
return fmt.Sprintf("&%s\n%s", n.Name.String(), value)
} else if s, ok := n.Value.(*SequenceNode); ok && !s.IsFlowStyle {
2020-02-29 11:43:22 +09:00
return fmt.Sprintf("&%s\n%s", n.Name.String(), value)
} else if m, ok := n.Value.(*MappingNode); ok && !m.IsFlowStyle {
return fmt.Sprintf("&%s\n%s", n.Name.String(), value)
2019-10-19 22:01:36 +09:00
}
return fmt.Sprintf("&%s %s", n.Name.String(), value)
2019-10-16 18:21:01 +09:00
}
2021-03-01 13:45:13 +09:00
// MarshalYAML encodes to a YAML text
func (n *AnchorNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
2019-10-21 03:33:41 +09:00
// AliasNode type of alias node
2019-10-16 18:21:01 +09:00
type AliasNode struct {
*BaseNode
Start *token.Token
Value Node
}
func (n *AliasNode) SetName(name string) error {
if n.Value == nil {
return ErrInvalidAliasName
}
s, ok := n.Value.(*StringNode)
if !ok {
return ErrInvalidAliasName
}
s.Value = name
return nil
}
// Read implements (io.Reader).Read
func (n *AliasNode) Read(p []byte) (int, error) {
return readNode(p, n)
2019-10-16 18:21:01 +09:00
}
2019-10-21 03:33:41 +09:00
// Type returns AliasType
func (n *AliasNode) Type() NodeType { return AliasType }
// GetToken returns token instance
2019-10-16 18:21:01 +09:00
func (n *AliasNode) GetToken() *token.Token {
return n.Start
}
// AddColumn add column number to child nodes recursively
func (n *AliasNode) AddColumn(col int) {
n.Start.AddColumn(col)
if n.Value != nil {
n.Value.AddColumn(col)
}
}
2019-10-21 03:33:41 +09:00
// String alias to text
2019-10-16 18:21:01 +09:00
func (n *AliasNode) String() string {
return fmt.Sprintf("*%s", n.Value.String())
}
2021-03-01 13:45:13 +09:00
// MarshalYAML encodes to a YAML text
func (n *AliasNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
2019-10-21 03:33:41 +09:00
// DirectiveNode type of directive node
2019-10-16 18:21:01 +09:00
type DirectiveNode struct {
*BaseNode
Start *token.Token
Value Node
}
// Read implements (io.Reader).Read
func (n *DirectiveNode) Read(p []byte) (int, error) {
return readNode(p, n)
2019-10-16 18:21:01 +09:00
}
2019-10-21 03:33:41 +09:00
// Type returns DirectiveType
func (n *DirectiveNode) Type() NodeType { return DirectiveType }
// GetToken returns token instance
2019-10-16 18:21:01 +09:00
func (n *DirectiveNode) GetToken() *token.Token {
return n.Start
}
// AddColumn add column number to child nodes recursively
func (n *DirectiveNode) AddColumn(col int) {
if n.Value != nil {
n.Value.AddColumn(col)
}
}
2019-10-21 03:33:41 +09:00
// String directive to text
2019-10-16 18:21:01 +09:00
func (n *DirectiveNode) String() string {
return fmt.Sprintf("%s%s", n.Start.Value, n.Value.String())
}
2021-03-01 13:45:13 +09:00
// MarshalYAML encodes to a YAML text
func (n *DirectiveNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
2019-10-21 03:33:41 +09:00
// TagNode type of tag node
2019-10-16 18:21:01 +09:00
type TagNode struct {
*BaseNode
Start *token.Token
Value Node
}
// Read implements (io.Reader).Read
func (n *TagNode) Read(p []byte) (int, error) {
return readNode(p, n)
2019-10-16 18:21:01 +09:00
}
2019-10-21 03:33:41 +09:00
// Type returns TagType
func (n *TagNode) Type() NodeType { return TagType }
// GetToken returns token instance
2019-10-16 18:21:01 +09:00
func (n *TagNode) GetToken() *token.Token {
return n.Start
}
// AddColumn add column number to child nodes recursively
func (n *TagNode) AddColumn(col int) {
n.Start.AddColumn(col)
if n.Value != nil {
n.Value.AddColumn(col)
}
}
2019-10-21 03:33:41 +09:00
// String tag to text
2019-10-16 18:21:01 +09:00
func (n *TagNode) String() string {
return fmt.Sprintf("%s %s", n.Start.Value, n.Value.String())
}
2021-03-01 13:45:13 +09:00
// MarshalYAML encodes to a YAML text
func (n *TagNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
2020-05-28 21:39:06 +09:00
// CommentNode type of comment node
type CommentNode struct {
*BaseNode
}
// Read implements (io.Reader).Read
func (n *CommentNode) Read(p []byte) (int, error) {
return readNode(p, n)
2020-05-28 21:39:06 +09:00
}
// Type returns TagType
func (n *CommentNode) Type() NodeType { return CommentType }
// GetToken returns token instance
func (n *CommentNode) GetToken() *token.Token { return n.Comment }
// AddColumn add column number to child nodes recursively
func (n *CommentNode) AddColumn(col int) {
n.Comment.AddColumn(col)
}
// String comment to text
func (n *CommentNode) String() string {
return n.Comment.Value
}
2021-03-01 13:45:13 +09:00
// MarshalYAML encodes to a YAML text
func (n *CommentNode) MarshalYAML() ([]byte, error) {
return []byte(n.String()), nil
}
2019-10-21 12:53:30 +09:00
// Visitor has Visit method that is invokded for each node encountered by Walk.
2019-10-21 03:33:41 +09:00
// If the result visitor w is not nil, Walk visits each of the children of node with the visitor w,
// followed by a call of w.Visit(nil).
2019-10-16 18:21:01 +09:00
type Visitor interface {
Visit(Node) Visitor
}
2019-10-21 03:33:41 +09:00
// Walk traverses an AST in depth-first order: It starts by calling v.Visit(node); node must not be nil.
// If the visitor w returned by v.Visit(node) is not nil,
// Walk is invoked recursively with visitor w for each of the non-nil children of node,
// followed by a call of w.Visit(nil).
2019-10-16 18:21:01 +09:00
func Walk(v Visitor, node Node) {
if v = v.Visit(node); v == nil {
return
}
switch n := node.(type) {
case *CommentNode:
2019-10-16 18:21:01 +09:00
case *NullNode:
case *IntegerNode:
case *FloatNode:
case *StringNode:
case *MergeKeyNode:
case *BoolNode:
case *InfinityNode:
case *NanNode:
case *LiteralNode:
Walk(v, n.Value)
case *DirectiveNode:
Walk(v, n.Value)
2020-07-02 17:21:31 +09:00
case *TagNode:
Walk(v, n.Value)
2020-06-22 23:29:22 +09:00
case *DocumentNode:
Walk(v, n.Body)
case *MappingNode:
2019-10-16 18:21:01 +09:00
for _, value := range n.Values {
Walk(v, value)
}
2020-07-02 17:21:31 +09:00
case *MappingKeyNode:
Walk(v, n.Value)
2019-10-16 18:21:01 +09:00
case *MappingValueNode:
Walk(v, n.Key)
Walk(v, n.Value)
case *SequenceNode:
for _, value := range n.Values {
Walk(v, value)
}
case *AnchorNode:
Walk(v, n.Name)
Walk(v, n.Value)
case *AliasNode:
Walk(v, n.Value)
}
}
2020-06-22 23:29:22 +09:00
type filterWalker struct {
typ NodeType
results []Node
}
func (v *filterWalker) Visit(n Node) Visitor {
if v.typ == n.Type() {
v.results = append(v.results, n)
}
return v
}
// Filter returns a list of nodes that match the given type.
func Filter(typ NodeType, node Node) []Node {
walker := &filterWalker{typ: typ}
Walk(walker, node)
return walker.results
}
// FilterFile returns a list of nodes that match the given type.
func FilterFile(typ NodeType, file *File) []Node {
results := []Node{}
for _, doc := range file.Docs {
walker := &filterWalker{typ: typ}
Walk(walker, doc)
results = append(results, walker.results...)
}
return results
}
2020-07-16 14:18:26 +09:00
type ErrInvalidMergeType struct {
dst Node
src Node
}
func (e *ErrInvalidMergeType) Error() string {
return fmt.Sprintf("cannot merge %s into %s", e.src.Type(), e.dst.Type())
}
// Merge merge document, map, sequence node.
func Merge(dst Node, src Node) error {
if doc, ok := src.(*DocumentNode); ok {
src = doc.Body
}
err := &ErrInvalidMergeType{dst: dst, src: src}
switch dst.Type() {
case DocumentType:
node := dst.(*DocumentNode)
return Merge(node.Body, src)
case MappingType:
node := dst.(*MappingNode)
target, ok := src.(*MappingNode)
if !ok {
return err
}
node.Merge(target)
return nil
case SequenceType:
node := dst.(*SequenceNode)
target, ok := src.(*SequenceNode)
if !ok {
return err
}
node.Merge(target)
return nil
}
return err
}