k3s/vendor/sigs.k8s.io/kustomize/kyaml/yaml/compatibility.go

93 lines
2.6 KiB
Go
Raw Normal View History

// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package yaml
import (
"reflect"
"strings"
"github.com/go-openapi/spec"
y1_1 "gopkg.in/yaml.v2"
y1_2 "gopkg.in/yaml.v3"
)
// typeToTag maps OpenAPI schema types to yaml 1.2 tags
var typeToTag = map[string]string{
"string": NodeTagString,
"integer": NodeTagInt,
"boolean": NodeTagBool,
"number": NodeTagFloat,
}
// FormatNonStringStyle makes sure that values which parse as non-string values in yaml 1.1
// are correctly formatted given the Schema type.
func FormatNonStringStyle(node *Node, schema spec.Schema) {
if len(schema.Type) != 1 {
return
}
t := schema.Type[0]
if !IsYaml1_1NonString(node) {
return
}
switch {
case t == "string" && schema.Format != "int-or-string":
if (node.Style&DoubleQuotedStyle == 0) && (node.Style&SingleQuotedStyle == 0) {
// must quote values so they are parsed as strings
node.Style = DoubleQuotedStyle
}
case t == "boolean" || t == "integer" || t == "number":
if (node.Style&DoubleQuotedStyle != 0) || (node.Style&SingleQuotedStyle != 0) {
// must NOT quote the values so they aren't parsed as strings
node.Style = 0
}
default:
return
}
if tag, found := typeToTag[t]; found {
// make sure the right tag is set
node.Tag = tag
}
}
// IsYaml1_1NonString returns true if the value parses as a non-string value in yaml 1.1
// when unquoted.
//
// Note: yaml 1.2 uses different keywords than yaml 1.1. Example: yaml 1.2 interprets
// `field: on` and `field: "on"` as equivalent (both strings). However Yaml 1.1 interprets
// `field: on` as on being a bool and `field: "on"` as on being a string.
// If an input is read with `field: "on"`, and the style is changed from DoubleQuote to 0,
// it will change the type of the field from a string to a bool. For this reason, fields
// which are keywords in yaml 1.1 should never have their style changed, as it would break
// backwards compatibility with yaml 1.1 -- which is what is used by the Kubernetes apiserver.
func IsYaml1_1NonString(node *Node) bool {
if node.Kind != y1_2.ScalarNode {
// not a keyword
return false
}
return IsValueNonString(node.Value)
}
func IsValueNonString(value string) bool {
if value == "" {
return false
}
if strings.Contains(value, "\n") {
// multi-line strings will fail to unmarshal
return false
}
// check if the value will unmarshal into a non-string value using a yaml 1.1 parser
var i1 interface{}
if err := y1_1.Unmarshal([]byte(value), &i1); err != nil {
return false
}
if reflect.TypeOf(i1) != stringType {
return true
}
return false
}
var stringType = reflect.TypeOf("string")