vendor/github.com/pelletier/go-toml/tomltree_write.go
changeset 256 6d9efbef00a9
parent 251 1c52a0eeb952
--- a/vendor/github.com/pelletier/go-toml/tomltree_write.go	Mon Jun 07 20:58:18 2021 +0200
+++ b/vendor/github.com/pelletier/go-toml/tomltree_write.go	Sun Jul 11 10:35:56 2021 +0200
@@ -28,23 +28,35 @@
 // Encodes a string to a TOML-compliant multi-line string value
 // This function is a clone of the existing encodeTomlString function, except that whitespace characters
 // are preserved. Quotation marks and backslashes are also not escaped.
-func encodeMultilineTomlString(value string) string {
+func encodeMultilineTomlString(value string, commented string) string {
 	var b bytes.Buffer
+	adjacentQuoteCount := 0
 
-	for _, rr := range value {
+	b.WriteString(commented)
+	for i, rr := range value {
+		if rr != '"' {
+			adjacentQuoteCount = 0
+		} else {
+			adjacentQuoteCount++
+		}
 		switch rr {
 		case '\b':
 			b.WriteString(`\b`)
 		case '\t':
 			b.WriteString("\t")
 		case '\n':
-			b.WriteString("\n")
+			b.WriteString("\n" + commented)
 		case '\f':
 			b.WriteString(`\f`)
 		case '\r':
 			b.WriteString("\r")
 		case '"':
-			b.WriteString(`"`)
+			if adjacentQuoteCount >= 3 || i == len(value)-1 {
+				adjacentQuoteCount = 0
+				b.WriteString(`\"`)
+			} else {
+				b.WriteString(`"`)
+			}
 		case '\\':
 			b.WriteString(`\`)
 		default:
@@ -91,7 +103,30 @@
 	return b.String()
 }
 
-func tomlValueStringRepresentation(v interface{}, indent string, arraysOneElementPerLine bool) (string, error) {
+func tomlTreeStringRepresentation(t *Tree, ord MarshalOrder) (string, error) {
+	var orderedVals []sortNode
+	switch ord {
+	case OrderPreserve:
+		orderedVals = sortByLines(t)
+	default:
+		orderedVals = sortAlphabetical(t)
+	}
+
+	var values []string
+	for _, node := range orderedVals {
+		k := node.key
+		v := t.values[k]
+
+		repr, err := tomlValueStringRepresentation(v, "", "", ord, false)
+		if err != nil {
+			return "", err
+		}
+		values = append(values, quoteKeyIfNeeded(k)+" = "+repr)
+	}
+	return "{ " + strings.Join(values, ", ") + " }", nil
+}
+
+func tomlValueStringRepresentation(v interface{}, commented string, indent string, ord MarshalOrder, arraysOneElementPerLine bool) (string, error) {
 	// this interface check is added to dereference the change made in the writeTo function.
 	// That change was made to allow this function to see formatting options.
 	tv, ok := v.(*tomlValue)
@@ -123,12 +158,20 @@
 		return strings.ToLower(strconv.FormatFloat(value, 'f', -1, bits)), nil
 	case string:
 		if tv.multiline {
-			return "\"\"\"\n" + encodeMultilineTomlString(value) + "\"\"\"", nil
+			if tv.literal {
+				b := strings.Builder{}
+				b.WriteString("'''\n")
+				b.Write([]byte(value))
+				b.WriteString("\n'''")
+				return b.String(), nil
+			} else {
+				return "\"\"\"\n" + encodeMultilineTomlString(value, commented) + "\"\"\"", nil
+			}
 		}
 		return "\"" + encodeTomlString(value) + "\"", nil
 	case []byte:
 		b, _ := v.([]byte)
-		return tomlValueStringRepresentation(string(b), indent, arraysOneElementPerLine)
+		return string(b), nil
 	case bool:
 		if value {
 			return "true", nil
@@ -142,6 +185,8 @@
 		return value.String(), nil
 	case LocalTime:
 		return value.String(), nil
+	case *Tree:
+		return tomlTreeStringRepresentation(value, ord)
 	case nil:
 		return "", nil
 	}
@@ -152,7 +197,7 @@
 		var values []string
 		for i := 0; i < rv.Len(); i++ {
 			item := rv.Index(i).Interface()
-			itemRepr, err := tomlValueStringRepresentation(item, indent, arraysOneElementPerLine)
+			itemRepr, err := tomlValueStringRepresentation(item, commented, indent, ord, arraysOneElementPerLine)
 			if err != nil {
 				return "", err
 			}
@@ -166,22 +211,24 @@
 
 			for _, value := range values {
 				stringBuffer.WriteString(valueIndent)
-				stringBuffer.WriteString(value)
+				stringBuffer.WriteString(commented + value)
 				stringBuffer.WriteString(`,`)
 				stringBuffer.WriteString("\n")
 			}
 
-			stringBuffer.WriteString(indent + "]")
+			stringBuffer.WriteString(indent + commented + "]")
 
 			return stringBuffer.String(), nil
 		}
-		return "[" + strings.Join(values, ",") + "]", nil
+		return "[" + strings.Join(values, ", ") + "]", nil
 	}
 	return "", fmt.Errorf("unsupported value type %T: %v", v, v)
 }
 
 func getTreeArrayLine(trees []*Tree) (line int) {
-	// get lowest line number that is not 0
+	// Prevent returning 0 for empty trees
+	line = int(^uint(0) >> 1)
+	// get lowest line number >= 0
 	for _, tv := range trees {
 		if tv.position.Line < line || line == 0 {
 			line = tv.position.Line
@@ -270,10 +317,10 @@
 }
 
 func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64, arraysOneElementPerLine bool) (int64, error) {
-	return t.writeToOrdered(w, indent, keyspace, bytesCount, arraysOneElementPerLine, OrderAlphabetical)
+	return t.writeToOrdered(w, indent, keyspace, bytesCount, arraysOneElementPerLine, OrderAlphabetical, "  ", false, false)
 }
 
-func (t *Tree) writeToOrdered(w io.Writer, indent, keyspace string, bytesCount int64, arraysOneElementPerLine bool, ord marshalOrder) (int64, error) {
+func (t *Tree) writeToOrdered(w io.Writer, indent, keyspace string, bytesCount int64, arraysOneElementPerLine bool, ord MarshalOrder, indentString string, compactComments, parentCommented bool) (int64, error) {
 	var orderedVals []sortNode
 
 	switch ord {
@@ -289,14 +336,10 @@
 			k := node.key
 			v := t.values[k]
 
-			combinedKey := k
+			combinedKey := quoteKeyIfNeeded(k)
 			if keyspace != "" {
 				combinedKey = keyspace + "." + combinedKey
 			}
-			var commented string
-			if t.commented {
-				commented = "# "
-			}
 
 			switch node := v.(type) {
 			// node has to be of those two types given how keys are sorted above
@@ -317,24 +360,33 @@
 						return bytesCount, errc
 					}
 				}
+
+				var commented string
+				if parentCommented || t.commented || tv.commented {
+					commented = "# "
+				}
 				writtenBytesCount, err := writeStrings(w, "\n", indent, commented, "[", combinedKey, "]\n")
 				bytesCount += int64(writtenBytesCount)
 				if err != nil {
 					return bytesCount, err
 				}
-				bytesCount, err = node.writeToOrdered(w, indent+"  ", combinedKey, bytesCount, arraysOneElementPerLine, ord)
+				bytesCount, err = node.writeToOrdered(w, indent+indentString, combinedKey, bytesCount, arraysOneElementPerLine, ord, indentString, compactComments, parentCommented || t.commented || tv.commented)
 				if err != nil {
 					return bytesCount, err
 				}
 			case []*Tree:
 				for _, subTree := range node {
+					var commented string
+					if parentCommented || t.commented || subTree.commented {
+						commented = "# "
+					}
 					writtenBytesCount, err := writeStrings(w, "\n", indent, commented, "[[", combinedKey, "]]\n")
 					bytesCount += int64(writtenBytesCount)
 					if err != nil {
 						return bytesCount, err
 					}
 
-					bytesCount, err = subTree.writeToOrdered(w, indent+"  ", combinedKey, bytesCount, arraysOneElementPerLine, ord)
+					bytesCount, err = subTree.writeToOrdered(w, indent+indentString, combinedKey, bytesCount, arraysOneElementPerLine, ord, indentString, compactComments, parentCommented || t.commented || subTree.commented)
 					if err != nil {
 						return bytesCount, err
 					}
@@ -347,7 +399,11 @@
 				return bytesCount, fmt.Errorf("invalid value type at %s: %T", k, t.values[k])
 			}
 
-			repr, err := tomlValueStringRepresentation(v, indent, arraysOneElementPerLine)
+			var commented string
+			if parentCommented || t.commented || v.commented {
+				commented = "# "
+			}
+			repr, err := tomlValueStringRepresentation(v, commented, indent, ord, arraysOneElementPerLine)
 			if err != nil {
 				return bytesCount, err
 			}
@@ -358,17 +414,20 @@
 				if strings.HasPrefix(comment, "#") {
 					start = ""
 				}
-				writtenBytesCountComment, errc := writeStrings(w, "\n", indent, start, comment, "\n")
+				if !compactComments {
+					writtenBytesCountComment, errc := writeStrings(w, "\n")
+					bytesCount += int64(writtenBytesCountComment)
+					if errc != nil {
+						return bytesCount, errc
+					}
+				}
+				writtenBytesCountComment, errc := writeStrings(w, indent, start, comment, "\n")
 				bytesCount += int64(writtenBytesCountComment)
 				if errc != nil {
 					return bytesCount, errc
 				}
 			}
 
-			var commented string
-			if v.commented {
-				commented = "# "
-			}
 			quotedKey := quoteKeyIfNeeded(k)
 			writtenBytesCount, err := writeStrings(w, indent, commented, quotedKey, " = ", repr, "\n")
 			bytesCount += int64(writtenBytesCount)
@@ -468,8 +527,26 @@
 		case *Tree:
 			result[k] = node.ToMap()
 		case *tomlValue:
-			result[k] = node.value
+			result[k] = tomlValueToGo(node.value)
 		}
 	}
 	return result
 }
+
+func tomlValueToGo(v interface{}) interface{} {
+	if tree, ok := v.(*Tree); ok {
+		return tree.ToMap()
+	}
+
+	rv := reflect.ValueOf(v)
+
+	if rv.Kind() != reflect.Slice {
+		return v
+	}
+	values := make([]interface{}, rv.Len())
+	for i := 0; i < rv.Len(); i++ {
+		item := rv.Index(i).Interface()
+		values[i] = tomlValueToGo(item)
+	}
+	return values
+}