Quote keys during encoding when the key isn't bare (#291)
In case the key contains non-bare characters (out of `A-Za-z0-9_-`), the key needs to be quoted during encoding to be valid TOML.
This commit is contained in:
+28
-1
@@ -354,7 +354,8 @@ func (t *Tree) writeToOrdered(w io.Writer, indent, keyspace string, bytesCount i
|
|||||||
if v.commented {
|
if v.commented {
|
||||||
commented = "# "
|
commented = "# "
|
||||||
}
|
}
|
||||||
writtenBytesCount, err := writeStrings(w, indent, commented, k, " = ", repr, "\n")
|
quotedKey := quoteKeyIfNeeded(k)
|
||||||
|
writtenBytesCount, err := writeStrings(w, indent, commented, quotedKey, " = ", repr, "\n")
|
||||||
bytesCount += int64(writtenBytesCount)
|
bytesCount += int64(writtenBytesCount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return bytesCount, err
|
return bytesCount, err
|
||||||
@@ -365,6 +366,32 @@ func (t *Tree) writeToOrdered(w io.Writer, indent, keyspace string, bytesCount i
|
|||||||
return bytesCount, nil
|
return bytesCount, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// quote a key if it does not fit the bare key format (A-Za-z0-9_-)
|
||||||
|
// quoted keys use the same rules as strings
|
||||||
|
func quoteKeyIfNeeded(k string) string {
|
||||||
|
// when encoding a map with the 'quoteMapKeys' option enabled, the tree will contain
|
||||||
|
// keys that have already been quoted.
|
||||||
|
// not an ideal situation, but good enough of a stop gap.
|
||||||
|
if len(k) >= 2 && k[0] == '"' && k[len(k)-1] == '"' {
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
isBare := true
|
||||||
|
for _, r := range k {
|
||||||
|
if !isValidBareChar(r) {
|
||||||
|
isBare = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isBare {
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
return quoteKey(k)
|
||||||
|
}
|
||||||
|
|
||||||
|
func quoteKey(k string) string {
|
||||||
|
return "\"" + encodeTomlString(k) + "\""
|
||||||
|
}
|
||||||
|
|
||||||
func writeStrings(w io.Writer, s ...string) (int, error) {
|
func writeStrings(w io.Writer, s ...string) (int, error) {
|
||||||
var n int
|
var n int
|
||||||
for i := range s {
|
for i := range s {
|
||||||
|
|||||||
@@ -327,6 +327,30 @@ c = nan`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIssue290(t *testing.T) {
|
||||||
|
tomlString :=
|
||||||
|
`[table]
|
||||||
|
"127.0.0.1" = "value"
|
||||||
|
"127.0.0.1:8028" = "value"
|
||||||
|
"character encoding" = "value"
|
||||||
|
"ʎǝʞ" = "value"`
|
||||||
|
|
||||||
|
t1, err := Load(tomlString)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("load err:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := t1.ToTomlString()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("ToTomlString err:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = Load(s)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("reload err:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkTreeToTomlString(b *testing.B) {
|
func BenchmarkTreeToTomlString(b *testing.B) {
|
||||||
toml, err := Load(sampleHard)
|
toml, err := Load(sampleHard)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user