From 9f266ea9e77c4c7aab4cf02650570e7c7b3031a5 Mon Sep 17 00:00:00 2001 From: Tristan Colgate-McFarlane Date: Fri, 13 Mar 2020 10:20:51 +0000 Subject: [PATCH] Marshal YAML 1.1 bool-like to strings (#583) We adhere to the YAML 1.2 for input, but only parsing "on", "off", and friends, as strings rather than bools. When outputting however we will ensure that we quote these cases. Failure to do so forces makes the output ambiguous if it then to be parsed by a YAML 1.2 parser. --- encode.go | 17 ++++++++++++++++- encode_test.go | 6 ++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/encode.go b/encode.go index eee3667e..1f37271c 100644 --- a/encode.go +++ b/encode.go @@ -298,6 +298,21 @@ func isBase60Float(s string) (result bool) { // is bogus. In practice parsers do not enforce the "\.[0-9_]*" suffix. var base60float = regexp.MustCompile(`^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+(?:\.[0-9_]*)?$`) +// isOldBool returns whether s is bool notation as defined in YAML 1.1. +// +// We continue to force strings that YAML 1.1 would interpret as booleans to be +// rendered as quotes strings so that the marshalled output valid for YAML 1.1 +// parsing. +func isOldBool(s string) (result bool) { + switch s { + case "y", "Y", "yes", "Yes", "YES", "on", "On", "ON", + "n", "N", "no", "No", "NO", "off", "Off", "OFF": + return true + default: + return false + } +} + func (e *encoder) stringv(tag string, in reflect.Value) { var style yaml_scalar_style_t s := in.String() @@ -319,7 +334,7 @@ func (e *encoder) stringv(tag string, in reflect.Value) { // tag when encoded unquoted. If it doesn't, // there's no need to quote it. rtag, _ := resolve("", s) - canUsePlain = rtag == strTag && !isBase60Float(s) + canUsePlain = rtag == strTag && !(isBase60Float(s) || isOldBool(s)) } // Note: it's possible for user code to emit invalid YAML // if they explicitly specify a tag and a string containing diff --git a/encode_test.go b/encode_test.go index 0f01b76f..3f32393d 100644 --- a/encode_test.go +++ b/encode_test.go @@ -176,6 +176,12 @@ var marshalTests = []struct { }, { &struct{ A bool }{true}, "a: true\n", + }, { + &struct{ A string }{"true"}, + "a: \"true\"\n", + }, { + &struct{ A string }{"off"}, + "a: \"off\"\n", }, // Conditional flag