Skip to content

Commit

Permalink
Yaml Value Node handling
Browse files Browse the repository at this point in the history
  • Loading branch information
iamshivamnanda committed Sep 13, 2024
1 parent 0596953 commit 47dcc3b
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 3 deletions.
53 changes: 51 additions & 2 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"math"
"reflect"
"strconv"
"strings"
"time"
)

Expand All @@ -38,6 +39,21 @@ type parser struct {
textless bool
}

// YAMLValue is a generic struct that holds both the typed value and the YAML Node
type YAMLValue[T any] struct {
Value T
Node *Node
}

// Helper function to check if a type is YAMLValue or YAMLValue[T]
func isYAMLValueType(t reflect.Type) bool {
if t.Kind() != reflect.Struct {
return false
}

return strings.Contains(t.String(), "YAMLValue")
}

func newParser(b []byte) *parser {
p := parser{}
if !yaml_parser_initialize(&p.parser) {
Expand Down Expand Up @@ -489,20 +505,53 @@ func (d *decoder) unmarshal(node *Node, out reflect.Value) (good bool) {
if d.aliasCount > 100 && d.decodeCount > 1000 && float64(d.aliasCount)/float64(d.decodeCount) > allowedAliasRatio(d.decodeCount) {
failf("document contains excessive aliasing")
}
if out.Type() == nodeType {
out.Set(reflect.ValueOf(node).Elem())

// Check if the out value is of YAMLValue type
if isYAMLValueType(out.Type()) {
valueField := out.FieldByName("Value")
nodeField := out.FieldByName("Node")

if !valueField.IsValid() || !nodeField.IsValid() {
failf("YAMLValue struct is missing Value or Node field")
}

// Create a new value to unmarshal into
innerValue := reflect.New(valueField.Type()).Elem()
good = d.unmarshal(node, innerValue)
if good {
// Set the Value and Node fields of YAMLValue
valueField.Set(innerValue)
nodeField.Set(reflect.ValueOf(node))
// Validate the inner value
errors := ValidateStruct(innerValue, node)
if len(errors) > 0 {
for _, e := range errors {
d.terrors = append(d.terrors, e.Error())
}
return false
}
}
return good
}

// Check if out type is *yaml.Node
if out.Type() == reflect.TypeOf(&Node{}) {
out.Set(reflect.ValueOf(node))
return true
}

switch node.Kind {
case DocumentNode:
return d.document(node, out)
case AliasNode:
return d.alias(node, out)
}

out, unmarshaled, good := d.prepare(node, out)
if unmarshaled {
return good
}

switch node.Kind {
case ScalarNode:
good = d.scalar(node, out)
Expand Down
7 changes: 6 additions & 1 deletion validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ var validators = make(map[string]Validator)

// validateStruct performs validation based on struct tags
func ValidateStruct(out reflect.Value, node *Node) []error {

var errors []error
t := out.Type()
if t.Kind() != reflect.Struct {
Expand Down Expand Up @@ -40,7 +41,11 @@ func ValidateStruct(out reflect.Value, node *Node) []error {
yamlTag = field.Name
}
if childNode, exists := fieldMap[yamlTag]; exists {
errors = append(errors, applyValidationRules(out.Field(i), tag, yamlTag, childNode)...)
fieldValue := out.Field(i)
if isYAMLValueType(field.Type) {
fieldValue = fieldValue.FieldByName("Value")
}
errors = append(errors, applyValidationRules(fieldValue, tag, yamlTag, childNode)...)
} else {
if tagContainsRequired(tag) {
errors = append(errors, CustomError{
Expand Down

0 comments on commit 47dcc3b

Please sign in to comment.