Skip to content

Commit

Permalink
pkg/encoding/toml: add new builtin package for encoding/toml
Browse files Browse the repository at this point in the history
With just Marshal and Unmarshal for now; validation APIs will follow,
as their semantics don't seem consistent between json and yaml.
Leave a TODO to come back to the validation APIs as well.

We add some txtar tests as well, driven by pkg/internal/builtintest.

Fixes #3344.

Signed-off-by: Daniel Martí <[email protected]>
Change-Id: I5cd4c01ab39daa4a208afcd8c3303f5f8d4ef512
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1201474
TryBot-Result: CUEcueckoo <[email protected]>
Reviewed-by: Roger Peppe <[email protected]>
  • Loading branch information
mvdan committed Sep 19, 2024
1 parent 9583e29 commit 2b56c50
Show file tree
Hide file tree
Showing 5 changed files with 276 additions and 0 deletions.
43 changes: 43 additions & 0 deletions pkg/encoding/toml/manual.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2024 The CUE Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package toml

import (
"bytes"
"strings"

"cuelang.org/go/cue"
"cuelang.org/go/cue/ast"
"cuelang.org/go/encoding/toml"
)

// Marshal returns the TOML encoding of v.
func Marshal(v cue.Value) (string, error) {
if err := v.Validate(cue.Concrete(true)); err != nil {
return "", err
}
var b strings.Builder
if err := toml.NewEncoder(&b).Encode(v); err != nil {
return "", err
}
return b.String(), nil
}

// Unmarshal parses the TOML to a CUE expression.
func Unmarshal(data []byte) (ast.Expr, error) {
return toml.NewDecoder("", bytes.NewReader(data)).Decode()
}

// TODO(mvdan): add Validate too, but which semantics? encoding/json and encoding/yaml do not seem to agree.
42 changes: 42 additions & 0 deletions pkg/encoding/toml/pkg.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

165 changes: 165 additions & 0 deletions pkg/encoding/toml/testdata/marshal.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
-- in.cue --
import "encoding/toml"

marshal: {
_input: {
rootKey: r1: "foo"
rootKeys: {
r1: "foo"
r2: "bar"
r3: "baz"
}
rootKeysDots: {
a1: "foo"
b1: b2: "bar"
c1: c2: c3: "baz"
}
subtables: {
tables: [
{table1: "foo"},
{table2: "bar"},
{subtable: {sub1: "baz"}}
]
}
complexKeys: "123-456": " foo bar ": "value"
defaults: key: string | *"default"

failIncomplete: key: string | "nondefault"
failRequired: key!: "foo"
}
for name, value in _input {
output: (name): toml.Marshal(value)
}
}

unmarshal: {
_input: {
rootKeysDots: """
a1 = "A"
b1.b2 = "B"
c1.c2.c3 = "C"
"""
subtables: """
[[tables]]
table1 = 'foo'
[[tables]]
table2 = 'bar'
[[tables]]
[tables.subtable]
sub1 = 'baz'
"""
complexKeys: """
[123-456]
' foo bar ' = 'value'
"""
defaultEmpty: string | *""

failIncomplete: string | ""
failBadSyntax: """
= "no key name"
"""
failDuplicate: """
foo = "same key"
foo = "same key"
"""
}
for name, value in _input {
output: (name): toml.Unmarshal(value)
}
}

-- out/toml --
Errors:
unmarshal.output.failBadSyntax: error in call to encoding/toml.Unmarshal: invalid character at start of key: =:
./in.cue:66:19
1:1
unmarshal.output.failDuplicate: error in call to encoding/toml.Unmarshal: duplicate key: foo:
./in.cue:66:19
2:1

Result:
import "encoding/toml"

marshal: {
output: {
rootKey: """
r1 = 'foo'

"""
rootKeys: """
r1 = 'foo'
r2 = 'bar'
r3 = 'baz'

"""
rootKeysDots: """
a1 = 'foo'

[b1]
b2 = 'bar'

[c1]
[c1.c2]
c3 = 'baz'

"""
subtables: """
[[tables]]
table1 = 'foo'

[[tables]]
table2 = 'bar'

[[tables]]
[tables.subtable]
sub1 = 'baz'

"""
complexKeys: """
[123-456]
' foo bar ' = 'value'

"""
defaults: """
key = 'default'

"""
failIncomplete: toml.Marshal(value)
failRequired: toml.Marshal(value)
}
}
unmarshal: {
output: {
rootKeysDots: {
a1: "A"
b1: {
b2: "B"
}
c1: {
c2: {
c3: "C"
}
}
}
subtables: {
tables: [{
table1: "foo"
}, {
table2: "bar"
}, {
subtable: {
sub1: "baz"
}
}]
}
complexKeys: {
"123-456": {
" foo bar ": "value"
}
}
defaultEmpty: {}
failIncomplete: toml.Unmarshal(value)
failBadSyntax: _|_ // unmarshal.output.failBadSyntax: error in call to encoding/toml.Unmarshal: invalid character at start of key: =
failDuplicate: _|_ // unmarshal.output.failDuplicate: error in call to encoding/toml.Unmarshal: duplicate key: foo
}
}
25 changes: 25 additions & 0 deletions pkg/encoding/toml/toml_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2024 CUE Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package toml_test

import (
"testing"

"cuelang.org/go/pkg/internal/builtintest"
)

func TestBuiltin(t *testing.T) {
builtintest.Run("toml", t)
}
1 change: 1 addition & 0 deletions pkg/register.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 2b56c50

Please sign in to comment.