New Upstream Release - golang-github-go-openapi-swag
Ready changes
Summary
Merged new upstream version: 0.22.3 (was: 0.21.1).
Resulting package
Built on 2023-06-08T06:57 (took 4m20s)
The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:
apt install -t fresh-releases golang-github-go-openapi-swag-dev
Lintian Result
Diff
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index f243a50..4c99b3e 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -1,11 +1,26 @@
-name: Go
+name: Verify
on: [push, pull_request]
jobs:
+ lint:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [ ubuntu-latest, macos-latest, windows-latest ]
+ fail-fast: false
+
+ steps:
+ - uses: actions/checkout@v2
+ - uses: golangci/golangci-lint-action@v2
+ with:
+ args: --timeout=5m
+
build:
runs-on: ${{ matrix.os }}
+ needs: [lint]
+
strategy:
matrix:
# No Windows this time. Some tests expect Unix-style paths.
@@ -18,30 +33,16 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v2
with:
- go-version: 1.17
+ go-version: 1.19
+ cache: true
- - name: Setup gotestsum
- uses: autero1/action-gotestsum@v1.0.0
- with:
- gotestsum_version: 1.7.0
+ - name: Install Tools
+ run: go install gotest.tools/gotestsum@latest
- name: Test
- run: gotestsum --format short-verbose -- -race -timeout=20m -coverprofile=coverage_txt -covermode=atomic ./...
+ run: gotestsum -- -race -timeout=20m -coverprofile=coverage_txt -covermode=atomic ./...
- - uses: codecov/codecov-action@v2
+ - uses: codecov/codecov-action@v3
with:
files: coverage_txt
- lint:
- runs-on: ${{ matrix.os }}
-
- strategy:
- matrix:
- os: [ ubuntu-latest, macos-latest, windows-latest ]
- fail-fast: false
-
- steps:
- - uses: actions/checkout@v2
- - uses: golangci/golangci-lint-action@v2
- with:
- args: --timeout=5m
diff --git a/.golangci.yml b/.golangci.yml
index 2a4a71f..bf503e4 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -48,3 +48,7 @@ linters:
- goimports
- tenv
- golint
+ - exhaustruct
+ - nilnil
+ - nonamedreturns
+ - nosnakecase
diff --git a/debian/changelog b/debian/changelog
index 57e208a..0389247 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+golang-github-go-openapi-swag (1:0.22.3-1) UNRELEASED; urgency=low
+
+ * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk> Thu, 08 Jun 2023 06:53:36 -0000
+
golang-github-go-openapi-swag (1:0.21.1-1) unstable; urgency=medium
* Team upload.
diff --git a/doc.go b/doc.go
index 8d2c8c5..55094cb 100644
--- a/doc.go
+++ b/doc.go
@@ -17,16 +17,15 @@ Package swag contains a bunch of helper functions for go-openapi and go-swagger
You may also use it standalone for your projects.
- * convert between value and pointers for builtin types
- * convert from string to builtin types (wraps strconv)
- * fast json concatenation
- * search in path
- * load from file or http
- * name mangling
-
+ - convert between value and pointers for builtin types
+ - convert from string to builtin types (wraps strconv)
+ - fast json concatenation
+ - search in path
+ - load from file or http
+ - name mangling
This repo has only few dependencies outside of the standard library:
- * YAML utilities depend on gopkg.in/yaml.v2
+ - YAML utilities depend on gopkg.in/yaml.v2
*/
package swag
diff --git a/go.mod b/go.mod
index fb29b65..60144c0 100644
--- a/go.mod
+++ b/go.mod
@@ -1,18 +1,21 @@
module github.com/go-openapi/swag
+require (
+ github.com/mailru/easyjson v0.7.7
+ github.com/stretchr/testify v1.8.0
+ gopkg.in/yaml.v3 v3.0.1
+)
+
require (
github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/josharian/intern v1.0.0 // indirect
github.com/kr/text v0.2.0 // indirect
- github.com/mailru/easyjson v0.7.6
- github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
- github.com/stretchr/testify v1.6.1
- gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
- gopkg.in/yaml.v2 v2.4.0
- gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
+ github.com/pmezard/go-difflib v1.0.0 // indirect
+ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
)
-replace github.com/golang/lint => golang.org/x/lint v0.0.0-20190409202823-959b441ac422
+// replace github.com/golang/lint => golang.org/x/lint v0.0.0-20190409202823-959b441ac422
-replace sourcegraph.com/sourcegraph/go-diff => github.com/sourcegraph/go-diff v0.5.1
+// replace sourcegraph.com/sourcegraph/go-diff => github.com/sourcegraph/go-diff v0.5.1
-go 1.11
+go 1.18
diff --git a/go.sum b/go.sum
index a45da80..76683c4 100644
--- a/go.sum
+++ b/go.sum
@@ -4,26 +4,24 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
+github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
-github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
-github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
-github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
-github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
-gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
-gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
-gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/loading.go b/loading.go
index 9a60409..00038c3 100644
--- a/loading.go
+++ b/loading.go
@@ -16,10 +16,11 @@ package swag
import (
"fmt"
- "io/ioutil"
+ "io"
"log"
"net/http"
"net/url"
+ "os"
"path/filepath"
"runtime"
"strings"
@@ -40,13 +41,13 @@ var LoadHTTPCustomHeaders = map[string]string{}
// LoadFromFileOrHTTP loads the bytes from a file or a remote http server based on the path passed in
func LoadFromFileOrHTTP(path string) ([]byte, error) {
- return LoadStrategy(path, ioutil.ReadFile, loadHTTPBytes(LoadHTTPTimeout))(path)
+ return LoadStrategy(path, os.ReadFile, loadHTTPBytes(LoadHTTPTimeout))(path)
}
// LoadFromFileOrHTTPWithTimeout loads the bytes from a file or a remote http server based on the path passed in
// timeout arg allows for per request overriding of the request timeout
func LoadFromFileOrHTTPWithTimeout(path string, timeout time.Duration) ([]byte, error) {
- return LoadStrategy(path, ioutil.ReadFile, loadHTTPBytes(timeout))(path)
+ return LoadStrategy(path, os.ReadFile, loadHTTPBytes(timeout))(path)
}
// LoadStrategy returns a loader function for a given path or uri
@@ -86,7 +87,7 @@ func LoadStrategy(path string, local, remote func(string) ([]byte, error)) func(
func loadHTTPBytes(timeout time.Duration) func(path string) ([]byte, error) {
return func(path string) ([]byte, error) {
client := &http.Client{Timeout: timeout}
- req, err := http.NewRequest("GET", path, nil) // nolint: noctx
+ req, err := http.NewRequest(http.MethodGet, path, nil) //nolint:noctx
if err != nil {
return nil, err
}
@@ -115,6 +116,6 @@ func loadHTTPBytes(timeout time.Duration) func(path string) ([]byte, error) {
return nil, fmt.Errorf("could not access document at %q [%s] ", path, resp.Status)
}
- return ioutil.ReadAll(resp.Body)
+ return io.ReadAll(resp.Body)
}
}
diff --git a/path_test.go b/path_test.go
index fb0548c..e439918 100644
--- a/path_test.go
+++ b/path_test.go
@@ -15,7 +15,6 @@
package swag
import (
- "io/ioutil"
"os"
"path"
"path/filepath"
@@ -29,11 +28,11 @@ func makeDirStructure(tgt string) (string, string, error) {
if tgt == "" {
tgt = "pkgpaths"
}
- td, err := ioutil.TempDir("", tgt)
+ td, err := os.MkdirTemp("", tgt)
if err != nil {
return "", "", err
}
- td2, err := ioutil.TempDir("", tgt+"-2")
+ td2, err := os.MkdirTemp("", tgt+"-2")
if err != nil {
return "", "", err
}
@@ -97,7 +96,7 @@ func TestFindPackage(t *testing.T) {
assert.Empty(t, pkg)
}
-// nolint: unparam
+//nolint:unparam
func assertPath(t testing.TB, expected, actual string) bool {
fp, err := filepath.EvalSymlinks(expected)
if assert.NoError(t, err) {
diff --git a/util.go b/util.go
index 193702f..f78ab68 100644
--- a/util.go
+++ b/util.go
@@ -99,10 +99,11 @@ const (
)
// JoinByFormat joins a string array by a known format (e.g. swagger's collectionFormat attribute):
-// ssv: space separated value
-// tsv: tab separated value
-// pipes: pipe (|) separated value
-// csv: comma separated value (default)
+//
+// ssv: space separated value
+// tsv: tab separated value
+// pipes: pipe (|) separated value
+// csv: comma separated value (default)
func JoinByFormat(data []string, format string) []string {
if len(data) == 0 {
return data
@@ -124,11 +125,11 @@ func JoinByFormat(data []string, format string) []string {
}
// SplitByFormat splits a string by a known format:
-// ssv: space separated value
-// tsv: tab separated value
-// pipes: pipe (|) separated value
-// csv: comma separated value (default)
//
+// ssv: space separated value
+// tsv: tab separated value
+// pipes: pipe (|) separated value
+// csv: comma separated value (default)
func SplitByFormat(data, format string) []string {
if data == "" {
return nil
diff --git a/yaml.go b/yaml.go
index ec96914..f09ee60 100644
--- a/yaml.go
+++ b/yaml.go
@@ -22,7 +22,7 @@ import (
"github.com/mailru/easyjson/jlexer"
"github.com/mailru/easyjson/jwriter"
- yaml "gopkg.in/yaml.v2"
+ yaml "gopkg.in/yaml.v3"
)
// YAMLMatcher matches yaml
@@ -43,16 +43,126 @@ func YAMLToJSON(data interface{}) (json.RawMessage, error) {
// BytesToYAMLDoc converts a byte slice into a YAML document
func BytesToYAMLDoc(data []byte) (interface{}, error) {
- var canary map[interface{}]interface{} // validate this is an object and not a different type
- if err := yaml.Unmarshal(data, &canary); err != nil {
+ var document yaml.Node // preserve order that is present in the document
+ if err := yaml.Unmarshal(data, &document); err != nil {
return nil, err
}
+ if document.Kind != yaml.DocumentNode || len(document.Content) != 1 || document.Content[0].Kind != yaml.MappingNode {
+ return nil, fmt.Errorf("only YAML documents that are objects are supported")
+ }
+ return &document, nil
+}
- var document yaml.MapSlice // preserve order that is present in the document
- if err := yaml.Unmarshal(data, &document); err != nil {
- return nil, err
+func yamlNode(root *yaml.Node) (interface{}, error) {
+ switch root.Kind {
+ case yaml.DocumentNode:
+ return yamlDocument(root)
+ case yaml.SequenceNode:
+ return yamlSequence(root)
+ case yaml.MappingNode:
+ return yamlMapping(root)
+ case yaml.ScalarNode:
+ return yamlScalar(root)
+ case yaml.AliasNode:
+ return yamlNode(root.Alias)
+ default:
+ return nil, fmt.Errorf("unsupported YAML node type: %v", root.Kind)
+ }
+}
+
+func yamlDocument(node *yaml.Node) (interface{}, error) {
+ if len(node.Content) != 1 {
+ return nil, fmt.Errorf("unexpected YAML Document node content length: %d", len(node.Content))
+ }
+ return yamlNode(node.Content[0])
+}
+
+func yamlMapping(node *yaml.Node) (interface{}, error) {
+ m := make(JSONMapSlice, len(node.Content)/2)
+
+ var j int
+ for i := 0; i < len(node.Content); i += 2 {
+ var nmi JSONMapItem
+ k, err := yamlStringScalarC(node.Content[i])
+ if err != nil {
+ return nil, fmt.Errorf("unable to decode YAML map key: %w", err)
+ }
+ nmi.Key = k
+ v, err := yamlNode(node.Content[i+1])
+ if err != nil {
+ return nil, fmt.Errorf("unable to process YAML map value for key %q: %w", k, err)
+ }
+ nmi.Value = v
+ m[j] = nmi
+ j++
+ }
+ return m, nil
+}
+
+func yamlSequence(node *yaml.Node) (interface{}, error) {
+ s := make([]interface{}, 0)
+
+ for i := 0; i < len(node.Content); i++ {
+
+ v, err := yamlNode(node.Content[i])
+ if err != nil {
+ return nil, fmt.Errorf("unable to decode YAML sequence value: %w", err)
+ }
+ s = append(s, v)
+ }
+ return s, nil
+}
+
+const ( // See https://yaml.org/type/
+ yamlStringScalar = "tag:yaml.org,2002:str"
+ yamlIntScalar = "tag:yaml.org,2002:int"
+ yamlBoolScalar = "tag:yaml.org,2002:bool"
+ yamlFloatScalar = "tag:yaml.org,2002:float"
+ yamlTimestamp = "tag:yaml.org,2002:timestamp"
+ yamlNull = "tag:yaml.org,2002:null"
+)
+
+func yamlScalar(node *yaml.Node) (interface{}, error) {
+ switch node.LongTag() {
+ case yamlStringScalar:
+ return node.Value, nil
+ case yamlBoolScalar:
+ b, err := strconv.ParseBool(node.Value)
+ if err != nil {
+ return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting bool content: %w", node.Value, err)
+ }
+ return b, nil
+ case yamlIntScalar:
+ i, err := strconv.ParseInt(node.Value, 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting integer content: %w", node.Value, err)
+ }
+ return i, nil
+ case yamlFloatScalar:
+ f, err := strconv.ParseFloat(node.Value, 64)
+ if err != nil {
+ return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting float content: %w", node.Value, err)
+ }
+ return f, nil
+ case yamlTimestamp:
+ return node.Value, nil
+ case yamlNull:
+ return nil, nil
+ default:
+ return nil, fmt.Errorf("YAML tag %q is not supported", node.LongTag())
+ }
+}
+
+func yamlStringScalarC(node *yaml.Node) (string, error) {
+ if node.Kind != yaml.ScalarNode {
+ return "", fmt.Errorf("expecting a string scalar but got %q", node.Kind)
+ }
+ switch node.LongTag() {
+ case yamlStringScalar, yamlIntScalar, yamlFloatScalar:
+ return node.Value, nil
+ default:
+ return "", fmt.Errorf("YAML tag %q is not supported as map key", node.LongTag())
}
- return document, nil
}
// JSONMapSlice represent a JSON object, with the order of keys maintained
@@ -105,6 +215,113 @@ func (s *JSONMapSlice) UnmarshalEasyJSON(in *jlexer.Lexer) {
*s = result
}
+func (s JSONMapSlice) MarshalYAML() (interface{}, error) {
+ var n yaml.Node
+ n.Kind = yaml.DocumentNode
+ var nodes []*yaml.Node
+ for _, item := range s {
+ nn, err := json2yaml(item.Value)
+ if err != nil {
+ return nil, err
+ }
+ ns := []*yaml.Node{
+ {
+ Kind: yaml.ScalarNode,
+ Tag: yamlStringScalar,
+ Value: item.Key,
+ },
+ nn,
+ }
+ nodes = append(nodes, ns...)
+ }
+
+ n.Content = []*yaml.Node{
+ {
+ Kind: yaml.MappingNode,
+ Content: nodes,
+ },
+ }
+
+ return yaml.Marshal(&n)
+}
+
+func json2yaml(item interface{}) (*yaml.Node, error) {
+ switch val := item.(type) {
+ case JSONMapSlice:
+ var n yaml.Node
+ n.Kind = yaml.MappingNode
+ for i := range val {
+ childNode, err := json2yaml(&val[i].Value)
+ if err != nil {
+ return nil, err
+ }
+ n.Content = append(n.Content, &yaml.Node{
+ Kind: yaml.ScalarNode,
+ Tag: yamlStringScalar,
+ Value: val[i].Key,
+ }, childNode)
+ }
+ return &n, nil
+ case map[string]interface{}:
+ var n yaml.Node
+ n.Kind = yaml.MappingNode
+ for k, v := range val {
+ childNode, err := json2yaml(v)
+ if err != nil {
+ return nil, err
+ }
+ n.Content = append(n.Content, &yaml.Node{
+ Kind: yaml.ScalarNode,
+ Tag: yamlStringScalar,
+ Value: k,
+ }, childNode)
+ }
+ return &n, nil
+ case []interface{}:
+ var n yaml.Node
+ n.Kind = yaml.SequenceNode
+ for i := range val {
+ childNode, err := json2yaml(val[i])
+ if err != nil {
+ return nil, err
+ }
+ n.Content = append(n.Content, childNode)
+ }
+ return &n, nil
+ case string:
+ return &yaml.Node{
+ Kind: yaml.ScalarNode,
+ Tag: yamlStringScalar,
+ Value: val,
+ }, nil
+ case float64:
+ return &yaml.Node{
+ Kind: yaml.ScalarNode,
+ Tag: yamlFloatScalar,
+ Value: strconv.FormatFloat(val, 'f', -1, 64),
+ }, nil
+ case int64:
+ return &yaml.Node{
+ Kind: yaml.ScalarNode,
+ Tag: yamlIntScalar,
+ Value: strconv.FormatInt(val, 10),
+ }, nil
+ case uint64:
+ return &yaml.Node{
+ Kind: yaml.ScalarNode,
+ Tag: yamlIntScalar,
+ Value: strconv.FormatUint(val, 10),
+ }, nil
+ case bool:
+ return &yaml.Node{
+ Kind: yaml.ScalarNode,
+ Tag: yamlBoolScalar,
+ Value: strconv.FormatBool(val),
+ }, nil
+ }
+ return nil, nil
+}
+
// JSONMapItem represents the value of a key in a JSON object held by JSONMapSlice
type JSONMapItem struct {
Key string
@@ -173,23 +390,10 @@ func transformData(input interface{}) (out interface{}, err error) {
}
switch in := input.(type) {
- case yaml.MapSlice:
-
- o := make(JSONMapSlice, len(in))
- for i, mi := range in {
- var nmi JSONMapItem
- if nmi.Key, err = format(mi.Key); err != nil {
- return nil, err
- }
-
- v, ert := transformData(mi.Value)
- if ert != nil {
- return nil, ert
- }
- nmi.Value = v
- o[i] = nmi
- }
- return o, nil
+ case yaml.Node:
+ return yamlNode(&in)
+ case *yaml.Node:
+ return yamlNode(in)
case map[interface{}]interface{}:
o := make(JSONMapSlice, 0, len(in))
for ke, va := range in {
diff --git a/yaml_test.go b/yaml_test.go
index 7271005..5eb5f1a 100644
--- a/yaml_test.go
+++ b/yaml_test.go
@@ -20,17 +20,45 @@ import (
"testing"
"github.com/stretchr/testify/assert"
- yaml "gopkg.in/yaml.v2"
+ "github.com/stretchr/testify/require"
+ yaml "gopkg.in/yaml.v3"
)
-/* currently unused:
-type failJSONMarshal struct {
-}
+func TestJSONToYAML(t *testing.T) {
+ sd := `{"1":"the int key value","name":"a string value","y":"some value"}`
+ var data JSONMapSlice
+ require.NoError(t, json.Unmarshal([]byte(sd), &data))
+
+ y, err := data.MarshalYAML()
+ require.NoError(t, err)
+ const expected = `"1": the int key value
+name: a string value
+y: some value
+`
+ assert.Equal(t, expected, string(y.([]byte)))
+
+ nstd := `{"1":"the int key value","name":"a string value","y":"some value","tag":{"name":"tag name"}}`
+ const nestpected = `"1": the int key value
+name: a string value
+y: some value
+tag:
+ name: tag name
+`
+ var ndata JSONMapSlice
+ require.NoError(t, json.Unmarshal([]byte(nstd), &ndata))
+ ny, err := ndata.MarshalYAML()
+ require.NoError(t, err)
+ assert.Equal(t, nestpected, string(ny.([]byte)))
+
+ ydoc, err := BytesToYAMLDoc([]byte(fixtures2224))
+ require.NoError(t, err)
+ b, err := YAMLToJSON(ydoc)
+ require.NoError(t, err)
+
+ var bdata JSONMapSlice
+ require.NoError(t, json.Unmarshal(b, &bdata))
-func (f failJSONMarshal) MarshalJSON() ([]byte, error) {
- return nil, errors.New("expected")
}
-*/
func TestYAMLToJSON(t *testing.T) {
@@ -39,7 +67,7 @@ func TestYAMLToJSON(t *testing.T) {
name: a string value
'y': some value
`
- var data yaml.MapSlice
+ var data yaml.Node
_ = yaml.Unmarshal([]byte(sd), &data)
d, err := YAMLToJSON(data)
@@ -47,22 +75,65 @@ name: a string value
assert.Equal(t, `{"1":"the int key value","name":"a string value","y":"some value"}`, string(d))
}
- data = append(data, yaml.MapItem{Key: true, Value: "the bool value"})
+ ns := []*yaml.Node{
+ {
+ Kind: yaml.ScalarNode,
+ Value: "true",
+ Tag: "!!bool",
+ },
+ {
+ Kind: yaml.ScalarNode,
+ Value: "the bool value",
+ Tag: "!!str",
+ },
+ }
+ data.Content[0].Content = append(data.Content[0].Content, ns...)
d, err = YAMLToJSON(data)
assert.Error(t, err)
assert.Nil(t, d)
- data = data[:len(data)-1]
+ data.Content[0].Content = data.Content[0].Content[:len(data.Content[0].Content)-2]
- tag := yaml.MapSlice{{Key: "name", Value: "tag name"}}
- data = append(data, yaml.MapItem{Key: "tag", Value: tag})
+ tag := []*yaml.Node{
+ {
+ Kind: yaml.ScalarNode,
+ Value: "tag",
+ Tag: "!!str",
+ },
+ {
+ Kind: yaml.MappingNode,
+ Content: []*yaml.Node{
+ {
+ Kind: yaml.ScalarNode,
+ Value: "name",
+ Tag: "!!str",
+ },
+ {
+ Kind: yaml.ScalarNode,
+ Value: "tag name",
+ Tag: "!!str",
+ },
+ },
+ },
+ }
+ data.Content[0].Content = append(data.Content[0].Content, tag...)
d, err = YAMLToJSON(data)
assert.NoError(t, err)
assert.Equal(t, `{"1":"the int key value","name":"a string value","y":"some value","tag":{"name":"tag name"}}`, string(d))
- tag = yaml.MapSlice{{Key: true, Value: "bool tag name"}}
- data = append(data[:len(data)-1], yaml.MapItem{Key: "tag", Value: tag})
+ tag[1].Content = []*yaml.Node{
+ {
+ Kind: yaml.ScalarNode,
+ Value: "true",
+ Tag: "!!bool",
+ },
+ {
+ Kind: yaml.ScalarNode,
+ Value: "the bool tag name",
+ Tag: "!!str",
+ },
+ }
d, err = YAMLToJSON(data)
assert.Error(t, err)
@@ -104,7 +175,7 @@ func TestWithYKey(t *testing.T) {
doc, err := BytesToYAMLDoc([]byte(withYKey))
if assert.NoError(t, err) {
_, err := YAMLToJSON(doc)
- if assert.Error(t, err) {
+ if assert.NoError(t, err) {
doc, err := BytesToYAMLDoc([]byte(withQuotedYKey))
if assert.NoError(t, err) {
jsond, err := YAMLToJSON(doc)
@@ -131,21 +202,6 @@ func TestWithYKey(t *testing.T) {
}
func TestMapKeyTypes(t *testing.T) {
- d := yaml.MapSlice{
- yaml.MapItem{Key: 12345, Value: "int"},
- yaml.MapItem{Key: int8(1), Value: "int8"},
- yaml.MapItem{Key: int16(12345), Value: "int16"},
- yaml.MapItem{Key: int32(12345678), Value: "int32"},
- yaml.MapItem{Key: int64(12345678910), Value: "int64"},
- yaml.MapItem{Key: uint(12345), Value: "uint"},
- yaml.MapItem{Key: uint8(1), Value: "uint8"},
- yaml.MapItem{Key: uint16(12345), Value: "uint16"},
- yaml.MapItem{Key: uint32(12345678), Value: "uint32"},
- yaml.MapItem{Key: uint64(12345678910), Value: "uint64"},
- }
- _, err := YAMLToJSON(d)
- assert.NoError(t, err)
-
dm := map[interface{}]interface{}{
12345: "int",
int8(1): "int8",
@@ -158,10 +214,188 @@ func TestMapKeyTypes(t *testing.T) {
uint32(12345678): "uint32",
uint64(12345678910): "uint64",
}
- _, err = YAMLToJSON(dm)
+ _, err := YAMLToJSON(dm)
assert.NoError(t, err)
}
+const fixtures2224 = `definitions:
+ Time:
+ type: string
+ format: date-time
+ x-go-type:
+ import:
+ package: time
+ embedded: true
+ type: Time
+ x-nullable: true
+
+ TimeAsObject: # <- time.Time is actually a struct
+ type: string
+ format: date-time
+ x-go-type:
+ import:
+ package: time
+ hints:
+ kind: object
+ embedded: true
+ type: Time
+ x-nullable: true
+
+ Raw:
+ x-go-type:
+ import:
+ package: encoding/json
+ hints:
+ kind: primitive
+ embedded: true
+ type: RawMessage
+
+ Request:
+ x-go-type:
+ import:
+ package: net/http
+ hints:
+ kind: object
+ embedded: true
+ type: Request
+
+ RequestPointer:
+ x-go-type:
+ import:
+ package: net/http
+ hints:
+ kind: object
+ nullable: true
+ embedded: true
+ type: Request
+
+ OldStyleImport:
+ type: object
+ x-go-type:
+ import:
+ package: net/http
+ type: Request
+ hints:
+ noValidation: true
+
+ OldStyleRenamed:
+ type: object
+ x-go-type:
+ import:
+ package: net/http
+ type: Request
+ hints:
+ noValidation: true
+ x-go-name: OldRenamed
+
+ ObjectWithEmbedded:
+ type: object
+ properties:
+ a:
+ $ref: '#/definitions/Time'
+ b:
+ $ref: '#/definitions/Request'
+ c:
+ $ref: '#/definitions/TimeAsObject'
+ d:
+ $ref: '#/definitions/Raw'
+ e:
+ $ref: '#/definitions/JSONObject'
+ f:
+ $ref: '#/definitions/JSONMessage'
+ g:
+ $ref: '#/definitions/JSONObjectWithAlias'
+
+ ObjectWithExternals:
+ type: object
+ properties:
+ a:
+ $ref: '#/definitions/OldStyleImport'
+ b:
+ $ref: '#/definitions/OldStyleRenamed'
+
+ Base:
+ properties: &base
+ id:
+ type: integer
+ format: uint64
+ x-go-custom-tag: 'gorm:"primary_key"'
+ FBID:
+ type: integer
+ format: uint64
+ x-go-custom-tag: 'gorm:"index"'
+ created_at:
+ $ref: "#/definitions/Time"
+ updated_at:
+ $ref: "#/definitions/Time"
+ version:
+ type: integer
+ format: uint64
+
+ HotspotType:
+ type: string
+ enum:
+ - A
+ - B
+ - C
+
+ Hotspot:
+ type: object
+ allOf:
+ - properties: *base
+ - properties:
+ access_points:
+ type: array
+ items:
+ $ref: '#/definitions/AccessPoint'
+ type:
+ $ref: '#/definitions/HotspotType'
+ required:
+ - type
+
+ AccessPoint:
+ type: object
+ allOf:
+ - properties: *base
+ - properties:
+ mac_address:
+ type: string
+ x-go-custom-tag: 'gorm:"index;not null;unique"'
+ hotspot_id:
+ type: integer
+ format: uint64
+ hotspot:
+ $ref: '#/definitions/Hotspot'
+
+ JSONObject:
+ type: object
+ additionalProperties:
+ type: array
+ items:
+ $ref: '#/definitions/Raw'
+
+ JSONObjectWithAlias:
+ type: object
+ additionalProperties:
+ type: object
+ properties:
+ message:
+ $ref: '#/definitions/JSONMessage'
+
+ JSONMessage:
+ $ref: '#/definitions/Raw'
+
+ Incorrect:
+ x-go-type:
+ import:
+ package: net
+ hints:
+ kind: array
+ embedded: true
+ type: Buffers
+ x-nullable: true
+`
+
const withQuotedYKey = `consumes:
- application/json
definitions:
Debdiff
File lists identical (after any substitutions)
No differences were encountered in the control files