Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8e8d2a6aad | |||
| 3f7178ffd6 | |||
| 9fd5922321 | |||
| 610cf85ed6 | |||
| 99f8a2a010 | |||
| 556d384d4c | |||
| eb7280e4a7 | |||
| 7ee1118b4b | |||
| a12e102214 | |||
| ad60b7e437 | |||
| 3503483c73 | |||
| d2d17bccec | |||
| 76a94674c9 | |||
| 80f8b7660b | |||
| 6f6ca41621 | |||
| c4efb7477c |
@@ -0,0 +1,29 @@
|
||||
export CGO_ENABLED=0
|
||||
go := go
|
||||
go.goos ?= $(shell echo `go version`|cut -f4 -d ' '|cut -d '/' -f1)
|
||||
go.goarch ?= $(shell echo `go version`|cut -f4 -d ' '|cut -d '/' -f2)
|
||||
|
||||
out.tools := tomll tomljson jsontoml
|
||||
out.dist := $(out.tools:=_$(go.goos)_$(go.goarch).tar.xz)
|
||||
sources := $(wildcard **/*.go)
|
||||
|
||||
|
||||
.PHONY:
|
||||
tools: $(out.tools)
|
||||
|
||||
$(out.tools): $(sources)
|
||||
GOOS=$(go.goos) GOARCH=$(go.goarch) $(go) build ./cmd/$@
|
||||
|
||||
.PHONY:
|
||||
dist: $(out.dist)
|
||||
|
||||
$(out.dist):%_$(go.goos)_$(go.goarch).tar.xz: %
|
||||
if [ "$(go.goos)" = "windows" ]; then \
|
||||
tar -cJf $@ $^.exe; \
|
||||
else \
|
||||
tar -cJf $@ $^; \
|
||||
fi
|
||||
|
||||
.PHONY:
|
||||
clean:
|
||||
rm -rf $(out.tools) $(out.dist)
|
||||
+85
-22
@@ -13,9 +13,9 @@ stages:
|
||||
vmImage: ubuntu-latest
|
||||
steps:
|
||||
- task: GoTool@0
|
||||
displayName: "Install Go 1.13"
|
||||
displayName: "Install Go 1.14"
|
||||
inputs:
|
||||
version: "1.13"
|
||||
version: "1.14"
|
||||
- script: echo "##vso[task.setvariable variable=PATH]${PATH}:/home/vsts/go/bin/"
|
||||
- script: mkdir -p ${HOME}/go/src/github.com/pelletier/go-toml
|
||||
- script: cp -R . ${HOME}/go/src/github.com/pelletier/go-toml
|
||||
@@ -36,9 +36,9 @@ stages:
|
||||
vmImage: ubuntu-latest
|
||||
steps:
|
||||
- task: GoTool@0
|
||||
displayName: "Install Go 1.13"
|
||||
displayName: "Install Go 1.14"
|
||||
inputs:
|
||||
version: "1.13"
|
||||
version: "1.14"
|
||||
- task: Go@0
|
||||
displayName: "go fmt ./..."
|
||||
inputs:
|
||||
@@ -51,9 +51,9 @@ stages:
|
||||
vmImage: ubuntu-latest
|
||||
steps:
|
||||
- task: GoTool@0
|
||||
displayName: "Install Go 1.13"
|
||||
displayName: "Install Go 1.14"
|
||||
inputs:
|
||||
version: "1.13"
|
||||
version: "1.14"
|
||||
- task: Go@0
|
||||
displayName: "Generate coverage"
|
||||
inputs:
|
||||
@@ -62,16 +62,18 @@ stages:
|
||||
- task: Bash@3
|
||||
inputs:
|
||||
targetType: 'inline'
|
||||
script: 'bash <(curl -s https://codecov.io/bash) -t $(CODECOV_TOKEN)'
|
||||
script: 'bash <(curl -s https://codecov.io/bash) -t ${CODECOV_TOKEN}'
|
||||
env:
|
||||
CODECOV_TOKEN: $(CODECOV_TOKEN)
|
||||
- job: benchmark
|
||||
displayName: "benchmark"
|
||||
pool:
|
||||
vmImage: ubuntu-latest
|
||||
steps:
|
||||
- task: GoTool@0
|
||||
displayName: "Install Go 1.13"
|
||||
displayName: "Install Go 1.14"
|
||||
inputs:
|
||||
version: "1.13"
|
||||
version: "1.14"
|
||||
- script: echo "##vso[task.setvariable variable=PATH]${PATH}:/home/vsts/go/bin/"
|
||||
- task: Bash@3
|
||||
inputs:
|
||||
@@ -84,9 +86,9 @@ stages:
|
||||
vmImage: ubuntu-latest
|
||||
steps:
|
||||
- task: GoTool@0
|
||||
displayName: "Install Go 1.13"
|
||||
displayName: "Install Go 1.14"
|
||||
inputs:
|
||||
version: "1.13"
|
||||
version: "1.14"
|
||||
- script: echo "##vso[task.setvariable variable=PATH]${PATH}:/home/vsts/go/bin/"
|
||||
- script: mkdir -p ${HOME}/go/src/github.com/pelletier/go-toml
|
||||
- script: cp -R . ${HOME}/go/src/github.com/pelletier/go-toml
|
||||
@@ -100,24 +102,24 @@ stages:
|
||||
displayName: "unit tests"
|
||||
strategy:
|
||||
matrix:
|
||||
linux 1.14:
|
||||
goVersion: '1.14'
|
||||
imageName: 'ubuntu-latest'
|
||||
mac 1.14:
|
||||
goVersion: '1.14'
|
||||
imageName: 'macOS-latest'
|
||||
windows 1.14:
|
||||
goVersion: '1.14'
|
||||
imageName: 'windows-latest'
|
||||
linux 1.13:
|
||||
goVersion: '1.13'
|
||||
imageName: 'ubuntu-latest'
|
||||
mac 1.13:
|
||||
goVersion: '1.13'
|
||||
imageName: 'macos-10.13'
|
||||
imageName: 'macOS-latest'
|
||||
windows 1.13:
|
||||
goVersion: '1.13'
|
||||
imageName: 'vs2017-win2016'
|
||||
linux 1.12:
|
||||
goVersion: '1.12'
|
||||
imageName: 'ubuntu-latest'
|
||||
mac 1.12:
|
||||
goVersion: '1.12'
|
||||
imageName: 'macos-10.13'
|
||||
windows 1.12:
|
||||
goVersion: '1.12'
|
||||
imageName: 'vs2017-win2016'
|
||||
imageName: 'windows-latest'
|
||||
pool:
|
||||
vmImage: $(imageName)
|
||||
steps:
|
||||
@@ -130,6 +132,67 @@ stages:
|
||||
inputs:
|
||||
command: 'test'
|
||||
arguments: './...'
|
||||
- stage: build_binaries
|
||||
displayName: "Build binaries"
|
||||
dependsOn: run_checks
|
||||
jobs:
|
||||
- job: build_binary
|
||||
displayName: "Build binary"
|
||||
strategy:
|
||||
matrix:
|
||||
linux_amd64:
|
||||
GOOS: linux
|
||||
GOARCH: amd64
|
||||
darwin_amd64:
|
||||
GOOS: darwin
|
||||
GOARCH: amd64
|
||||
windows_amd64:
|
||||
GOOS: windows
|
||||
GOARCH: amd64
|
||||
pool:
|
||||
vmImage: ubuntu-latest
|
||||
steps:
|
||||
- task: GoTool@0
|
||||
displayName: "Install Go"
|
||||
inputs:
|
||||
version: 1.14
|
||||
- task: Bash@3
|
||||
inputs:
|
||||
targetType: inline
|
||||
script: "make dist"
|
||||
env:
|
||||
go.goos: $(GOOS)
|
||||
go.goarch: $(GOARCH)
|
||||
- task: CopyFiles@2
|
||||
inputs:
|
||||
sourceFolder: '$(Build.SourcesDirectory)'
|
||||
contents: '*.tar.xz'
|
||||
TargetFolder: '$(Build.ArtifactStagingDirectory)'
|
||||
- task: PublishBuildArtifacts@1
|
||||
inputs:
|
||||
pathtoPublish: '$(Build.ArtifactStagingDirectory)'
|
||||
artifactName: binaries
|
||||
- stage: build_binaries_manifest
|
||||
displayName: "Build binaries manifest"
|
||||
dependsOn: build_binaries
|
||||
jobs:
|
||||
- job: build_manifest
|
||||
displayName: "Build binaries manifest"
|
||||
steps:
|
||||
- task: DownloadBuildArtifacts@0
|
||||
inputs:
|
||||
buildType: 'current'
|
||||
downloadType: 'single'
|
||||
artifactName: 'binaries'
|
||||
downloadPath: '$(Build.SourcesDirectory)'
|
||||
- task: Bash@3
|
||||
inputs:
|
||||
targetType: inline
|
||||
script: "cd binaries && sha256sum --binary *.tar.xz | tee $(Build.ArtifactStagingDirectory)/sha256sums.txt"
|
||||
- task: PublishBuildArtifacts@1
|
||||
inputs:
|
||||
pathtoPublish: '$(Build.ArtifactStagingDirectory)'
|
||||
artifactName: manifest
|
||||
|
||||
- stage: build_docker_image
|
||||
displayName: "Build Docker image"
|
||||
|
||||
@@ -5,5 +5,5 @@ go 1.12
|
||||
require (
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
gopkg.in/yaml.v2 v2.2.4
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
)
|
||||
|
||||
@@ -9,3 +9,9 @@ gopkg.in/yaml.v2 v2.2.3 h1:fvjTMHxHEw/mxHbtzPi3JCcKXQRAnQTBRo6YCJSVHKI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
||||
@@ -256,7 +256,7 @@ func (l *tomlLexer) lexLeftCurlyBrace() tomlLexStateFn {
|
||||
func (l *tomlLexer) lexRightCurlyBrace() tomlLexStateFn {
|
||||
l.next()
|
||||
l.emit(tokenRightCurlyBrace)
|
||||
return l.lexVoid
|
||||
return l.lexRvalue
|
||||
}
|
||||
|
||||
func (l *tomlLexer) lexDate() tomlLexStateFn {
|
||||
|
||||
+66
-8
@@ -302,7 +302,7 @@ func (e *Encoder) marshal(v interface{}) ([]byte, error) {
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
_, err = t.writeToOrdered(&buf, "", "", 0, e.arraysOneElementPerLine, e.order)
|
||||
_, err = t.writeToOrdered(&buf, "", "", 0, e.arraysOneElementPerLine, e.order, false)
|
||||
|
||||
return buf.Bytes(), err
|
||||
}
|
||||
@@ -320,10 +320,14 @@ func (e *Encoder) valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, er
|
||||
tval := e.nextTree()
|
||||
switch mtype.Kind() {
|
||||
case reflect.Struct:
|
||||
switch mval.Interface().(type) {
|
||||
case Tree:
|
||||
reflect.ValueOf(tval).Elem().Set(mval)
|
||||
default:
|
||||
for i := 0; i < mtype.NumField(); i++ {
|
||||
mtypef, mvalf := mtype.Field(i), mval.Field(i)
|
||||
opts := tomlOptions(mtypef, e.annotation)
|
||||
if opts.include && (!opts.omitempty || !isZero(mvalf)) {
|
||||
if opts.include && ((mtypef.Type.Kind() != reflect.Interface && !opts.omitempty) || !isZero(mvalf)) {
|
||||
val, err := e.valueToToml(mtypef.Type, mvalf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -336,6 +340,7 @@ func (e *Encoder) valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, er
|
||||
}, val)
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Map:
|
||||
keys := mval.MapKeys()
|
||||
if e.order == OrderPreserve && len(keys) > 0 {
|
||||
@@ -358,12 +363,15 @@ func (e *Encoder) valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, er
|
||||
}
|
||||
for _, key := range keys {
|
||||
mvalf := mval.MapIndex(key)
|
||||
if (mtype.Elem().Kind() == reflect.Ptr || mtype.Elem().Kind() == reflect.Interface) && mvalf.IsNil() {
|
||||
continue
|
||||
}
|
||||
val, err := e.valueToToml(mtype.Elem(), mvalf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if e.quoteMapKeys {
|
||||
keyStr, err := tomlValueStringRepresentation(key.String(), "", e.arraysOneElementPerLine)
|
||||
keyStr, err := tomlValueStringRepresentation(key.String(), "", "", e.arraysOneElementPerLine)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -391,6 +399,9 @@ func (e *Encoder) valueToTreeSlice(mtype reflect.Type, mval reflect.Value) ([]*T
|
||||
|
||||
// Convert given marshal slice to slice of toml values
|
||||
func (e *Encoder) valueToOtherSlice(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
|
||||
if mtype.Elem().Kind() == reflect.Interface {
|
||||
return nil, fmt.Errorf("marshal can't handle []interface{}")
|
||||
}
|
||||
tval := make([]interface{}, mval.Len(), mval.Len())
|
||||
for i := 0; i < mval.Len(); i++ {
|
||||
val, err := e.valueToToml(mtype.Elem(), mval.Index(i))
|
||||
@@ -408,6 +419,9 @@ func (e *Encoder) valueToToml(mtype reflect.Type, mval reflect.Value) (interface
|
||||
if mtype.Kind() == reflect.Ptr {
|
||||
return e.valueToToml(mtype.Elem(), mval.Elem())
|
||||
}
|
||||
if mtype.Kind() == reflect.Interface {
|
||||
return e.valueToToml(mval.Elem().Type(), mval.Elem())
|
||||
}
|
||||
switch {
|
||||
case isCustomMarshaler(mtype):
|
||||
return callCustomMarshaler(mval)
|
||||
@@ -561,11 +575,17 @@ func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree, mval1 *reflect.V
|
||||
mval = reflect.New(mtype).Elem()
|
||||
}
|
||||
|
||||
switch mval.Interface().(type) {
|
||||
case Tree:
|
||||
mval.Set(reflect.ValueOf(tval).Elem())
|
||||
default:
|
||||
for i := 0; i < mtype.NumField(); i++ {
|
||||
mtypef := mtype.Field(i)
|
||||
an := annotation{tag: d.tagName}
|
||||
opts := tomlOptions(mtypef, an)
|
||||
if opts.include {
|
||||
if !opts.include {
|
||||
continue
|
||||
}
|
||||
baseKey := opts.name
|
||||
keysToTry := []string{
|
||||
baseKey,
|
||||
@@ -575,6 +595,7 @@ func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree, mval1 *reflect.V
|
||||
}
|
||||
|
||||
found := false
|
||||
if tval != nil {
|
||||
for _, key := range keysToTry {
|
||||
exists := tval.Has(key)
|
||||
if !exists {
|
||||
@@ -590,6 +611,7 @@ func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree, mval1 *reflect.V
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found && opts.defaultValue != "" {
|
||||
mvalf := mval.Field(i)
|
||||
@@ -624,9 +646,13 @@ func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree, mval1 *reflect.V
|
||||
mval.Field(i).Set(reflect.ValueOf(val))
|
||||
}
|
||||
|
||||
// save the old behavior above and try to check anonymous structs
|
||||
if !found && opts.defaultValue == "" && mtypef.Anonymous && mtypef.Type.Kind() == reflect.Struct {
|
||||
v, err := d.valueFromTree(mtypef.Type, tval, nil)
|
||||
// save the old behavior above and try to check structs
|
||||
if !found && opts.defaultValue == "" && mtypef.Type.Kind() == reflect.Struct {
|
||||
tmpTval := tval
|
||||
if !mtypef.Anonymous {
|
||||
tmpTval = nil
|
||||
}
|
||||
v, err := d.valueFromTree(mtypef.Type, tmpTval, nil)
|
||||
if err != nil {
|
||||
return v, err
|
||||
}
|
||||
@@ -692,16 +718,41 @@ func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}, mval1 *ref
|
||||
if isTree(mtype) {
|
||||
return d.valueFromTree(mtype, t, mval11)
|
||||
}
|
||||
|
||||
if mtype.Kind() == reflect.Interface {
|
||||
if mval1 == nil || mval1.IsNil() {
|
||||
return d.valueFromTree(reflect.TypeOf(map[string]interface{}{}), t, nil)
|
||||
} else {
|
||||
return d.valueFromToml(mval1.Elem().Type(), t, nil)
|
||||
}
|
||||
}
|
||||
|
||||
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a tree", tval, tval)
|
||||
case []*Tree:
|
||||
if isTreeSequence(mtype) {
|
||||
return d.valueFromTreeSlice(mtype, t)
|
||||
}
|
||||
if mtype.Kind() == reflect.Interface {
|
||||
if mval1 == nil || mval1.IsNil() {
|
||||
return d.valueFromTreeSlice(reflect.TypeOf([]map[string]interface{}{}), t)
|
||||
} else {
|
||||
ival := mval1.Elem()
|
||||
return d.valueFromToml(mval1.Elem().Type(), t, &ival)
|
||||
}
|
||||
}
|
||||
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to trees", tval, tval)
|
||||
case []interface{}:
|
||||
if isOtherSequence(mtype) {
|
||||
return d.valueFromOtherSlice(mtype, t)
|
||||
}
|
||||
if mtype.Kind() == reflect.Interface {
|
||||
if mval1 == nil || mval1.IsNil() {
|
||||
return d.valueFromOtherSlice(reflect.TypeOf([]interface{}{}), t)
|
||||
} else {
|
||||
ival := mval1.Elem()
|
||||
return d.valueFromToml(mval1.Elem().Type(), t, &ival)
|
||||
}
|
||||
}
|
||||
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a slice", tval, tval)
|
||||
default:
|
||||
switch mtype.Kind() {
|
||||
@@ -786,6 +837,13 @@ func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}, mval1 *ref
|
||||
}
|
||||
|
||||
return val.Convert(mtype), nil
|
||||
case reflect.Interface:
|
||||
if mval1 == nil || mval1.IsNil() {
|
||||
return reflect.ValueOf(tval), nil
|
||||
} else {
|
||||
ival := mval1.Elem()
|
||||
return d.valueFromToml(mval1.Elem().Type(), t, &ival)
|
||||
}
|
||||
default:
|
||||
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v(%v)", tval, tval, mtype, mtype.Kind())
|
||||
}
|
||||
@@ -795,7 +853,7 @@ func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}, mval1 *ref
|
||||
func (d *Decoder) unwrapPointer(mtype reflect.Type, tval interface{}, mval1 *reflect.Value) (reflect.Value, error) {
|
||||
var melem *reflect.Value
|
||||
|
||||
if mval1 != nil && !mval1.IsNil() && mtype.Elem().Kind() == reflect.Struct {
|
||||
if mval1 != nil && !mval1.IsNil() && (mtype.Elem().Kind() == reflect.Struct || mtype.Elem().Kind() == reflect.Interface) {
|
||||
elem := mval1.Elem()
|
||||
melem = &elem
|
||||
}
|
||||
|
||||
+632
@@ -157,6 +157,44 @@ var mashalOrderPreserveMapToml = []byte(`title = "TOML Marshal Testing"
|
||||
j9 = "10"
|
||||
`)
|
||||
|
||||
type Conf struct {
|
||||
Name string
|
||||
Age int
|
||||
Inter interface{}
|
||||
}
|
||||
|
||||
type NestedStruct struct {
|
||||
FirstName string
|
||||
LastName string
|
||||
Age int
|
||||
}
|
||||
|
||||
var doc = []byte(`Name = "rui"
|
||||
Age = 18
|
||||
|
||||
[Inter]
|
||||
FirstName = "wang"
|
||||
LastName = "jl"
|
||||
Age = 100`)
|
||||
|
||||
func TestInterface(t *testing.T) {
|
||||
var config Conf
|
||||
config.Inter = &NestedStruct{}
|
||||
err := Unmarshal(doc, &config)
|
||||
expected := Conf{
|
||||
Name: "rui",
|
||||
Age: 18,
|
||||
Inter: &NestedStruct{
|
||||
FirstName: "wang",
|
||||
LastName: "jl",
|
||||
Age: 100,
|
||||
},
|
||||
}
|
||||
if err != nil || !reflect.DeepEqual(config, expected) {
|
||||
t.Errorf("Bad unmarshal: expected %v, got %v", expected, config)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBasicMarshal(t *testing.T) {
|
||||
result, err := Marshal(basicTestData)
|
||||
if err != nil {
|
||||
@@ -913,6 +951,213 @@ func TestMarshalComment(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalMultilineCommented(t *testing.T) {
|
||||
expectedToml := []byte(`# MultilineArray = [
|
||||
# 100,
|
||||
# 200,
|
||||
# 300,
|
||||
# ]
|
||||
# MultilineNestedArray = [
|
||||
# [
|
||||
# "a",
|
||||
# "b",
|
||||
# "c",
|
||||
# ],
|
||||
# [
|
||||
# "d",
|
||||
# "e",
|
||||
# "f",
|
||||
# ],
|
||||
# ]
|
||||
# MultilineString = """
|
||||
# I
|
||||
# am
|
||||
# Allen"""
|
||||
NonCommented = "Not commented line"
|
||||
`)
|
||||
type StructWithMultiline struct {
|
||||
NonCommented string
|
||||
MultilineString string `commented:"true" multiline:"true"`
|
||||
MultilineArray []int `commented:"true"`
|
||||
MultilineNestedArray [][]string `commented:"true"`
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
enc := NewEncoder(&buf)
|
||||
if err := enc.ArraysWithOneElementPerLine(true).Encode(StructWithMultiline{
|
||||
NonCommented: "Not commented line",
|
||||
MultilineString: "I\nam\nAllen",
|
||||
MultilineArray: []int{100, 200, 300},
|
||||
MultilineNestedArray: [][]string{
|
||||
{"a", "b", "c"},
|
||||
{"d", "e", "f"},
|
||||
},
|
||||
}); err == nil {
|
||||
result := buf.Bytes()
|
||||
if !bytes.Equal(result, expectedToml) {
|
||||
t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expectedToml, result)
|
||||
}
|
||||
} else {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalNonPrimitiveTypeCommented(t *testing.T) {
|
||||
expectedToml := []byte(`
|
||||
# [CommentedMapField]
|
||||
|
||||
# [CommentedMapField.CommentedMapField1]
|
||||
# SingleLineString = "This line should be commented out"
|
||||
|
||||
# [CommentedMapField.CommentedMapField2]
|
||||
# SingleLineString = "This line should be commented out"
|
||||
|
||||
# [CommentedStructField]
|
||||
|
||||
# [CommentedStructField.CommentedStructField]
|
||||
# MultilineArray = [
|
||||
# 1,
|
||||
# 2,
|
||||
# ]
|
||||
# MultilineNestedArray = [
|
||||
# [
|
||||
# 10,
|
||||
# 20,
|
||||
# ],
|
||||
# [
|
||||
# 100,
|
||||
# 200,
|
||||
# ],
|
||||
# ]
|
||||
# MultilineString = """
|
||||
# This line
|
||||
# should be
|
||||
# commented out"""
|
||||
|
||||
# [CommentedStructField.NotCommentedStructField]
|
||||
# MultilineArray = [
|
||||
# 1,
|
||||
# 2,
|
||||
# ]
|
||||
# MultilineNestedArray = [
|
||||
# [
|
||||
# 10,
|
||||
# 20,
|
||||
# ],
|
||||
# [
|
||||
# 100,
|
||||
# 200,
|
||||
# ],
|
||||
# ]
|
||||
# MultilineString = """
|
||||
# This line
|
||||
# should be
|
||||
# commented out"""
|
||||
|
||||
[NotCommentedStructField]
|
||||
|
||||
# [NotCommentedStructField.CommentedStructField]
|
||||
# MultilineArray = [
|
||||
# 1,
|
||||
# 2,
|
||||
# ]
|
||||
# MultilineNestedArray = [
|
||||
# [
|
||||
# 10,
|
||||
# 20,
|
||||
# ],
|
||||
# [
|
||||
# 100,
|
||||
# 200,
|
||||
# ],
|
||||
# ]
|
||||
# MultilineString = """
|
||||
# This line
|
||||
# should be
|
||||
# commented out"""
|
||||
|
||||
[NotCommentedStructField.NotCommentedStructField]
|
||||
MultilineArray = [
|
||||
3,
|
||||
4,
|
||||
]
|
||||
MultilineNestedArray = [
|
||||
[
|
||||
30,
|
||||
40,
|
||||
],
|
||||
[
|
||||
300,
|
||||
400,
|
||||
],
|
||||
]
|
||||
MultilineString = """
|
||||
This line
|
||||
should NOT be
|
||||
commented out"""
|
||||
`)
|
||||
type InnerStruct struct {
|
||||
MultilineString string `multiline:"true"`
|
||||
MultilineArray []int
|
||||
MultilineNestedArray [][]int
|
||||
}
|
||||
type MiddleStruct struct {
|
||||
NotCommentedStructField InnerStruct
|
||||
CommentedStructField InnerStruct `commented:"true"`
|
||||
}
|
||||
type OuterStruct struct {
|
||||
CommentedStructField MiddleStruct `commented:"true"`
|
||||
NotCommentedStructField MiddleStruct
|
||||
CommentedMapField map[string]struct{ SingleLineString string } `commented:"true"`
|
||||
}
|
||||
|
||||
commentedTestStruct := OuterStruct{
|
||||
CommentedStructField: MiddleStruct{
|
||||
NotCommentedStructField: InnerStruct{
|
||||
MultilineString: "This line\nshould be\ncommented out",
|
||||
MultilineArray: []int{1, 2},
|
||||
MultilineNestedArray: [][]int{{10, 20}, {100, 200}},
|
||||
},
|
||||
CommentedStructField: InnerStruct{
|
||||
MultilineString: "This line\nshould be\ncommented out",
|
||||
MultilineArray: []int{1, 2},
|
||||
MultilineNestedArray: [][]int{{10, 20}, {100, 200}},
|
||||
},
|
||||
},
|
||||
NotCommentedStructField: MiddleStruct{
|
||||
NotCommentedStructField: InnerStruct{
|
||||
MultilineString: "This line\nshould NOT be\ncommented out",
|
||||
MultilineArray: []int{3, 4},
|
||||
MultilineNestedArray: [][]int{{30, 40}, {300, 400}},
|
||||
},
|
||||
CommentedStructField: InnerStruct{
|
||||
MultilineString: "This line\nshould be\ncommented out",
|
||||
MultilineArray: []int{1, 2},
|
||||
MultilineNestedArray: [][]int{{10, 20}, {100, 200}},
|
||||
},
|
||||
},
|
||||
CommentedMapField: map[string]struct{ SingleLineString string }{
|
||||
"CommentedMapField1": {
|
||||
SingleLineString: "This line should be commented out",
|
||||
},
|
||||
"CommentedMapField2": {
|
||||
SingleLineString: "This line should be commented out",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
enc := NewEncoder(&buf)
|
||||
if err := enc.ArraysWithOneElementPerLine(true).Encode(commentedTestStruct); err == nil {
|
||||
result := buf.Bytes()
|
||||
if !bytes.Equal(result, expectedToml) {
|
||||
t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expectedToml, result)
|
||||
}
|
||||
} else {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
type mapsTestStruct struct {
|
||||
Simple map[string]string
|
||||
Paths map[string]string
|
||||
@@ -1199,6 +1444,54 @@ func TestMarshalCustomMultiline(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalEmbedTree(t *testing.T) {
|
||||
expected := []byte(`OuterField1 = "Out"
|
||||
OuterField2 = 1024
|
||||
|
||||
[TreeField]
|
||||
InnerField1 = "In"
|
||||
InnerField2 = 2048
|
||||
|
||||
[TreeField.EmbedStruct]
|
||||
EmbedField = "Embed"
|
||||
`)
|
||||
type InnerStruct struct {
|
||||
InnerField1 string
|
||||
InnerField2 int
|
||||
EmbedStruct struct{
|
||||
EmbedField string
|
||||
}
|
||||
}
|
||||
|
||||
type OuterStruct struct {
|
||||
OuterField1 string
|
||||
OuterField2 int
|
||||
TreeField *Tree
|
||||
}
|
||||
|
||||
tree, err := Load(`
|
||||
InnerField1 = "In"
|
||||
InnerField2 = 2048
|
||||
|
||||
[EmbedStruct]
|
||||
EmbedField = "Embed"
|
||||
`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
out := OuterStruct{
|
||||
"Out",
|
||||
1024,
|
||||
tree,
|
||||
}
|
||||
actual, _ := Marshal(out)
|
||||
|
||||
if !bytes.Equal(actual, expected){
|
||||
t.Errorf("Bad marshal: expected %s, got %s", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
var testDocBasicToml = []byte(`
|
||||
[document]
|
||||
bool_val = true
|
||||
@@ -1483,12 +1776,20 @@ func TestUnmarshalCamelCaseKey(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUnmarshalDefault(t *testing.T) {
|
||||
type EmbeddedStruct struct {
|
||||
StringField string `default:"c"`
|
||||
}
|
||||
|
||||
var doc struct {
|
||||
StringField string `default:"a"`
|
||||
BoolField bool `default:"true"`
|
||||
IntField int `default:"1"`
|
||||
Int64Field int64 `default:"2"`
|
||||
Float64Field float64 `default:"3.1"`
|
||||
NonEmbeddedStruct struct {
|
||||
StringField string `default:"b"`
|
||||
}
|
||||
EmbeddedStruct
|
||||
}
|
||||
|
||||
err := Unmarshal([]byte(``), &doc)
|
||||
@@ -1510,6 +1811,12 @@ func TestUnmarshalDefault(t *testing.T) {
|
||||
if doc.Float64Field != 3.1 {
|
||||
t.Errorf("Float64Field should be 3.1, not %f", doc.Float64Field)
|
||||
}
|
||||
if doc.NonEmbeddedStruct.StringField != "b" {
|
||||
t.Errorf("StringField should be \"b\", not %s", doc.NonEmbeddedStruct.StringField)
|
||||
}
|
||||
if doc.EmbeddedStruct.StringField != "c" {
|
||||
t.Errorf("StringField should be \"c\", not %s", doc.EmbeddedStruct.StringField)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalDefaultFailureBool(t *testing.T) {
|
||||
@@ -2140,3 +2447,328 @@ func TestMarshalLocalTime(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// test case for issue #339
|
||||
func TestUnmarshalSameInnerField(t *testing.T) {
|
||||
type InterStruct2 struct {
|
||||
Test string
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
type Inter2 struct {
|
||||
Name string
|
||||
Age int
|
||||
InterStruct2 InterStruct2
|
||||
}
|
||||
type Server struct {
|
||||
Name string `toml:"name"`
|
||||
Inter2 Inter2 `toml:"inter2"`
|
||||
}
|
||||
|
||||
var server Server
|
||||
|
||||
if err := Unmarshal([]byte(`name = "123"
|
||||
[inter2]
|
||||
name = "inter2"
|
||||
age = 222`), &server); err == nil {
|
||||
expected := Server{
|
||||
Name: "123",
|
||||
Inter2: Inter2{
|
||||
Name: "inter2",
|
||||
Age: 222,
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(server, expected) {
|
||||
t.Errorf("Bad unmarshal: expected %v, got %v", expected, server)
|
||||
}
|
||||
} else {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalInterface(t *testing.T) {
|
||||
type InnerStruct struct {
|
||||
InnerField string
|
||||
}
|
||||
|
||||
type OuterStruct struct {
|
||||
PrimitiveField interface{}
|
||||
ArrayField interface{}
|
||||
StructArrayField interface{}
|
||||
MapField map[string]interface{}
|
||||
StructField interface{}
|
||||
PointerField interface{}
|
||||
NilField interface{}
|
||||
InterfacePointerField *interface{}
|
||||
}
|
||||
|
||||
type ShouldNotSupportStruct struct {
|
||||
InterfaceArray []interface{}
|
||||
}
|
||||
|
||||
expected := []byte(`ArrayField = [1,2,3]
|
||||
InterfacePointerField = "hello world"
|
||||
PrimitiveField = "string"
|
||||
|
||||
[MapField]
|
||||
key1 = "value1"
|
||||
key2 = false
|
||||
|
||||
[MapField.key3]
|
||||
InnerField = "value3"
|
||||
|
||||
[PointerField]
|
||||
InnerField = "yyy"
|
||||
|
||||
[[StructArrayField]]
|
||||
InnerField = "s1"
|
||||
|
||||
[[StructArrayField]]
|
||||
InnerField = "s2"
|
||||
|
||||
[StructField]
|
||||
InnerField = "xxx"
|
||||
`)
|
||||
|
||||
var h interface{} = "hello world"
|
||||
if result, err := Marshal(OuterStruct{
|
||||
"string",
|
||||
[]int{1, 2, 3},
|
||||
[]InnerStruct{{"s1"}, {"s2"}},
|
||||
map[string]interface{}{
|
||||
"key1": "value1",
|
||||
"key2": false,
|
||||
"key3": InnerStruct{"value3"},
|
||||
"nil value": nil,
|
||||
},
|
||||
InnerStruct{
|
||||
"xxx",
|
||||
},
|
||||
&InnerStruct{
|
||||
"yyy",
|
||||
},
|
||||
nil,
|
||||
&h,
|
||||
}); err == nil {
|
||||
if !bytes.Equal(result, expected) {
|
||||
t.Errorf("Bad marshal: expected\n----\n%s\n----\ngot\n----\n%s\n----\n", expected, result)
|
||||
}
|
||||
} else {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// according to the toml standard, data types of array may not be mixed
|
||||
if _, err := Marshal(ShouldNotSupportStruct{[]interface{}{1, "a", true}}); err == nil {
|
||||
t.Errorf("Should not support []interface{} marshaling")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalToNilInterface(t *testing.T) {
|
||||
toml := []byte(`
|
||||
PrimitiveField = "Hello"
|
||||
ArrayField = [1,2,3]
|
||||
InterfacePointerField = "World"
|
||||
|
||||
[StructField]
|
||||
Field1 = 123
|
||||
Field2 = "Field2"
|
||||
|
||||
[MapField]
|
||||
MapField1 = [4,5,6]
|
||||
MapField2 = {A = "A"}
|
||||
MapField3 = false
|
||||
|
||||
[[StructArrayField]]
|
||||
Name = "Allen"
|
||||
Age = 20
|
||||
|
||||
[[StructArrayField]]
|
||||
Name = "Jack"
|
||||
Age = 23
|
||||
`)
|
||||
|
||||
type OuterStruct struct {
|
||||
PrimitiveField interface{}
|
||||
ArrayField interface{}
|
||||
StructArrayField interface{}
|
||||
MapField map[string]interface{}
|
||||
StructField interface{}
|
||||
NilField interface{}
|
||||
InterfacePointerField *interface{}
|
||||
}
|
||||
|
||||
var s interface{} = "World"
|
||||
expected := OuterStruct{
|
||||
PrimitiveField: "Hello",
|
||||
ArrayField: []interface{}{int64(1), int64(2), int64(3)},
|
||||
StructField: map[string]interface{}{
|
||||
"Field1": int64(123),
|
||||
"Field2": "Field2",
|
||||
},
|
||||
MapField: map[string]interface{}{
|
||||
"MapField1": []interface{}{int64(4), int64(5), int64(6)},
|
||||
"MapField2": map[string]interface{}{
|
||||
"A": "A",
|
||||
},
|
||||
"MapField3": false,
|
||||
},
|
||||
NilField: nil,
|
||||
InterfacePointerField: &s,
|
||||
StructArrayField: []map[string]interface{}{
|
||||
{
|
||||
"Name": "Allen",
|
||||
"Age": int64(20),
|
||||
},
|
||||
{
|
||||
"Name": "Jack",
|
||||
"Age": int64(23),
|
||||
},
|
||||
},
|
||||
}
|
||||
actual := OuterStruct{}
|
||||
if err := Unmarshal(toml, &actual); err == nil {
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual)
|
||||
}
|
||||
} else {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalToNonNilInterface(t *testing.T) {
|
||||
toml := []byte(`
|
||||
PrimitiveField = "Allen"
|
||||
ArrayField = [1,2,3]
|
||||
|
||||
[StructField]
|
||||
InnerField = "After1"
|
||||
|
||||
[PointerField]
|
||||
InnerField = "After2"
|
||||
|
||||
[InterfacePointerField]
|
||||
InnerField = "After"
|
||||
|
||||
[MapField]
|
||||
MapField1 = [4,5,6]
|
||||
MapField2 = {A = "A"}
|
||||
MapField3 = false
|
||||
|
||||
[[StructArrayField]]
|
||||
InnerField = "After3"
|
||||
|
||||
[[StructArrayField]]
|
||||
InnerField = "After4"
|
||||
`)
|
||||
type InnerStruct struct {
|
||||
InnerField interface{}
|
||||
}
|
||||
|
||||
type OuterStruct struct {
|
||||
PrimitiveField interface{}
|
||||
ArrayField interface{}
|
||||
StructArrayField interface{}
|
||||
MapField map[string]interface{}
|
||||
StructField interface{}
|
||||
PointerField interface{}
|
||||
NilField interface{}
|
||||
InterfacePointerField *interface{}
|
||||
}
|
||||
|
||||
var s interface{} = InnerStruct{"After"}
|
||||
expected := OuterStruct{
|
||||
PrimitiveField: "Allen",
|
||||
ArrayField: []int{1, 2, 3},
|
||||
StructField: InnerStruct{InnerField: "After1"},
|
||||
MapField: map[string]interface{}{
|
||||
"MapField1": []interface{}{int64(4), int64(5), int64(6)},
|
||||
"MapField2": map[string]interface{}{
|
||||
"A": "A",
|
||||
},
|
||||
"MapField3": false,
|
||||
},
|
||||
PointerField: &InnerStruct{InnerField: "After2"},
|
||||
NilField: nil,
|
||||
InterfacePointerField: &s,
|
||||
StructArrayField: []InnerStruct{
|
||||
{InnerField: "After3"},
|
||||
{InnerField: "After4"},
|
||||
},
|
||||
}
|
||||
actual := OuterStruct{
|
||||
PrimitiveField: "aaa",
|
||||
ArrayField: []int{100, 200, 300, 400},
|
||||
StructField: InnerStruct{InnerField: "Before1"},
|
||||
MapField: map[string]interface{}{
|
||||
"MapField1": []int{4, 5, 6},
|
||||
"MapField2": map[string]string{
|
||||
"B": "BBB",
|
||||
},
|
||||
"MapField3": true,
|
||||
},
|
||||
PointerField: &InnerStruct{InnerField: "Before2"},
|
||||
NilField: nil,
|
||||
InterfacePointerField: &s,
|
||||
StructArrayField: []InnerStruct{
|
||||
{InnerField: "Before3"},
|
||||
{InnerField: "Before4"},
|
||||
},
|
||||
}
|
||||
if err := Unmarshal(toml, &actual); err == nil {
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual)
|
||||
}
|
||||
} else {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalEmbedTree(t *testing.T) {
|
||||
toml := []byte(`
|
||||
OuterField1 = "Out"
|
||||
OuterField2 = 1024
|
||||
|
||||
[TreeField]
|
||||
InnerField1 = "In"
|
||||
InnerField2 = 2048
|
||||
|
||||
[TreeField.EmbedStruct]
|
||||
EmbedField = "Embed"
|
||||
|
||||
`)
|
||||
type InnerStruct struct {
|
||||
InnerField1 string
|
||||
InnerField2 int
|
||||
EmbedStruct struct{
|
||||
EmbedField string
|
||||
}
|
||||
}
|
||||
|
||||
type OuterStruct struct {
|
||||
OuterField1 string
|
||||
OuterField2 int
|
||||
TreeField *Tree
|
||||
}
|
||||
|
||||
out := OuterStruct{}
|
||||
actual := InnerStruct{}
|
||||
expected := InnerStruct{
|
||||
"In",
|
||||
2048,
|
||||
struct{
|
||||
EmbedField string
|
||||
}{
|
||||
EmbedField:"Embed",
|
||||
},
|
||||
}
|
||||
if err := Unmarshal(toml, &out); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := out.TreeField.Unmarshal(&actual); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(actual, expected){
|
||||
t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
+34
-1
@@ -581,6 +581,39 @@ func TestDoubleInlineGroup(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestNestedInlineGroup(t *testing.T) {
|
||||
tree, err := Load("out = {block0 = {x = 99, y = 100}, block1 = {p = \"999\", q = \"1000\"}}")
|
||||
assertTree(t, tree, err, map[string]interface{}{
|
||||
"out": map[string]interface{}{
|
||||
"block0": map[string]interface{}{
|
||||
"x": int64(99),
|
||||
"y": int64(100),
|
||||
},
|
||||
"block1": map[string]interface{}{
|
||||
"p": "999",
|
||||
"q": "1000",
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestArrayInNestedInlineGroup(t *testing.T) {
|
||||
tree, err := Load(`image = {name = "xxx", palette = {id = 100, colors = ["red", "blue", "green"]}}`)
|
||||
assertTree(t, tree, err, map[string]interface{}{
|
||||
"image": map[string]interface{}{
|
||||
"name": "xxx",
|
||||
"palette": map[string]interface{}{
|
||||
"id": int64(100),
|
||||
"colors": []string{
|
||||
"red",
|
||||
"blue",
|
||||
"green",
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestExampleInlineGroup(t *testing.T) {
|
||||
tree, err := Load(`name = { first = "Tom", last = "Preston-Werner" }
|
||||
point = { x = 1, y = 2 }`)
|
||||
@@ -864,7 +897,7 @@ func TestTomlValueStringRepresentation(t *testing.T) {
|
||||
"[\"gamma\",\"delta\"]"},
|
||||
{nil, ""},
|
||||
} {
|
||||
result, err := tomlValueStringRepresentation(item.Value, "", false)
|
||||
result, err := tomlValueStringRepresentation(item.Value, "", "", false)
|
||||
if err != nil {
|
||||
t.Errorf("Test %d - unexpected error: %s", idx, err)
|
||||
}
|
||||
|
||||
@@ -222,8 +222,12 @@ func (t *Tree) SetPathWithOptions(keys []string, opts SetOptions, value interfac
|
||||
switch v := value.(type) {
|
||||
case *Tree:
|
||||
v.comment = opts.Comment
|
||||
v.commented = opts.Commented
|
||||
toInsert = value
|
||||
case []*Tree:
|
||||
for i := range v {
|
||||
v[i].commented = opts.Commented
|
||||
}
|
||||
toInsert = value
|
||||
case *tomlValue:
|
||||
v.comment = opts.Comment
|
||||
|
||||
+27
-21
@@ -28,9 +28,10 @@ type sortNode struct {
|
||||
// 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
|
||||
|
||||
b.WriteString(commented)
|
||||
for _, rr := range value {
|
||||
switch rr {
|
||||
case '\b':
|
||||
@@ -38,7 +39,7 @@ func encodeMultilineTomlString(value string) string {
|
||||
case '\t':
|
||||
b.WriteString("\t")
|
||||
case '\n':
|
||||
b.WriteString("\n")
|
||||
b.WriteString("\n" + commented)
|
||||
case '\f':
|
||||
b.WriteString(`\f`)
|
||||
case '\r':
|
||||
@@ -91,7 +92,7 @@ func encodeTomlString(value string) string {
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func tomlValueStringRepresentation(v interface{}, indent string, arraysOneElementPerLine bool) (string, error) {
|
||||
func tomlValueStringRepresentation(v interface{}, commented string, indent string, 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 +124,12 @@ func tomlValueStringRepresentation(v interface{}, indent string, arraysOneElemen
|
||||
return strings.ToLower(strconv.FormatFloat(value, 'f', -1, bits)), nil
|
||||
case string:
|
||||
if tv.multiline {
|
||||
return "\"\"\"\n" + encodeMultilineTomlString(value) + "\"\"\"", nil
|
||||
return "\"\"\"\n" + encodeMultilineTomlString(value, commented) + "\"\"\"", nil
|
||||
}
|
||||
return "\"" + encodeTomlString(value) + "\"", nil
|
||||
case []byte:
|
||||
b, _ := v.([]byte)
|
||||
return tomlValueStringRepresentation(string(b), indent, arraysOneElementPerLine)
|
||||
return tomlValueStringRepresentation(string(b), commented, indent, arraysOneElementPerLine)
|
||||
case bool:
|
||||
if value {
|
||||
return "true", nil
|
||||
@@ -152,7 +153,7 @@ func tomlValueStringRepresentation(v interface{}, indent string, arraysOneElemen
|
||||
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, arraysOneElementPerLine)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -166,12 +167,12 @@ func tomlValueStringRepresentation(v interface{}, indent string, arraysOneElemen
|
||||
|
||||
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
|
||||
}
|
||||
@@ -270,10 +271,10 @@ func sortAlphabetical(t *Tree) (vals []sortNode) {
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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, parentCommented bool) (int64, error) {
|
||||
var orderedVals []sortNode
|
||||
|
||||
switch ord {
|
||||
@@ -293,10 +294,6 @@ func (t *Tree) writeToOrdered(w io.Writer, indent, keyspace string, bytesCount i
|
||||
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 +314,33 @@ func (t *Tree) writeToOrdered(w io.Writer, indent, keyspace string, bytesCount i
|
||||
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+" ", combinedKey, bytesCount, arraysOneElementPerLine, ord, 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+" ", combinedKey, bytesCount, arraysOneElementPerLine, ord, parentCommented || t.commented || subTree.commented)
|
||||
if err != nil {
|
||||
return bytesCount, err
|
||||
}
|
||||
@@ -347,7 +353,11 @@ func (t *Tree) writeToOrdered(w io.Writer, indent, keyspace string, bytesCount i
|
||||
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, arraysOneElementPerLine)
|
||||
if err != nil {
|
||||
return bytesCount, err
|
||||
}
|
||||
@@ -365,10 +375,6 @@ func (t *Tree) writeToOrdered(w io.Writer, indent, keyspace string, bytesCount i
|
||||
}
|
||||
}
|
||||
|
||||
var commented string
|
||||
if v.commented {
|
||||
commented = "# "
|
||||
}
|
||||
quotedKey := quoteKeyIfNeeded(k)
|
||||
writtenBytesCount, err := writeStrings(w, indent, commented, quotedKey, " = ", repr, "\n")
|
||||
bytesCount += int64(writtenBytesCount)
|
||||
|
||||
Reference in New Issue
Block a user