bump(github.com/go-openapi/spec): 7abd5745472fff5eb3685386d5fb8bf38683154d

This commit is contained in:
Nikhita Raghunath 2017-09-19 11:25:48 +05:30
parent d08047c240
commit 9968c18a6c
51 changed files with 1597 additions and 574 deletions

13
Godeps/Godeps.json generated
View File

@ -1186,7 +1186,7 @@
},
{
"ImportPath": "github.com/go-openapi/loads",
"Rev": "18441dfa706d924a39a030ee2c3b1d8d81917b38"
"Rev": "a80dea3052f00e5f032e860dd7355cd0cc67e24d"
},
{
"ImportPath": "github.com/go-openapi/runtime",
@ -1194,7 +1194,7 @@
},
{
"ImportPath": "github.com/go-openapi/spec",
"Rev": "6aced65f8501fe1217321abf0749d354824ba2ff"
"Rev": "7abd5745472fff5eb3685386d5fb8bf38683154d"
},
{
"ImportPath": "github.com/go-openapi/strfmt",
@ -1202,7 +1202,7 @@
},
{
"ImportPath": "github.com/go-openapi/swag",
"Rev": "1d0bd113de87027671077d3c71eb3ac5d7dbba72"
"Rev": "f3f9494671f93fcff853e3c6e9e948b3eb71e590"
},
{
"ImportPath": "github.com/go-openapi/validate",
@ -1858,7 +1858,6 @@
},
{
"ImportPath": "github.com/inconshreveable/mousetrap",
"Comment": "v1.0",
"Rev": "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
},
{
@ -1971,15 +1970,15 @@
},
{
"ImportPath": "github.com/mailru/easyjson/buffer",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/mailru/easyjson/jlexer",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/mailru/easyjson/jwriter",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/matttproud/golang_protobuf_extensions/pbutil",

View File

@ -32,11 +32,11 @@
},
{
"ImportPath": "github.com/go-openapi/spec",
"Rev": "6aced65f8501fe1217321abf0749d354824ba2ff"
"Rev": "7abd5745472fff5eb3685386d5fb8bf38683154d"
},
{
"ImportPath": "github.com/go-openapi/swag",
"Rev": "1d0bd113de87027671077d3c71eb3ac5d7dbba72"
"Rev": "f3f9494671f93fcff853e3c6e9e948b3eb71e590"
},
{
"ImportPath": "github.com/gogo/protobuf/proto",
@ -56,15 +56,15 @@
},
{
"ImportPath": "github.com/mailru/easyjson/buffer",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/mailru/easyjson/jlexer",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/mailru/easyjson/jwriter",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/spf13/pflag",
@ -134,6 +134,10 @@
"ImportPath": "gopkg.in/inf.v0",
"Rev": "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4"
},
{
"ImportPath": "gopkg.in/yaml.v2",
"Rev": "53feefa2559fb8dfa8d81baad31be332c97d6c77"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/resource",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

View File

@ -132,7 +132,7 @@
},
{
"ImportPath": "github.com/go-openapi/loads",
"Rev": "18441dfa706d924a39a030ee2c3b1d8d81917b38"
"Rev": "a80dea3052f00e5f032e860dd7355cd0cc67e24d"
},
{
"ImportPath": "github.com/go-openapi/runtime",
@ -140,7 +140,7 @@
},
{
"ImportPath": "github.com/go-openapi/spec",
"Rev": "6aced65f8501fe1217321abf0749d354824ba2ff"
"Rev": "7abd5745472fff5eb3685386d5fb8bf38683154d"
},
{
"ImportPath": "github.com/go-openapi/strfmt",
@ -148,7 +148,7 @@
},
{
"ImportPath": "github.com/go-openapi/swag",
"Rev": "1d0bd113de87027671077d3c71eb3ac5d7dbba72"
"Rev": "f3f9494671f93fcff853e3c6e9e948b3eb71e590"
},
{
"ImportPath": "github.com/go-openapi/validate",
@ -264,15 +264,15 @@
},
{
"ImportPath": "github.com/mailru/easyjson/buffer",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/mailru/easyjson/jlexer",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/mailru/easyjson/jwriter",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/matttproud/golang_protobuf_extensions/pbutil",

View File

@ -56,11 +56,11 @@
},
{
"ImportPath": "github.com/go-openapi/spec",
"Rev": "6aced65f8501fe1217321abf0749d354824ba2ff"
"Rev": "7abd5745472fff5eb3685386d5fb8bf38683154d"
},
{
"ImportPath": "github.com/go-openapi/swag",
"Rev": "1d0bd113de87027671077d3c71eb3ac5d7dbba72"
"Rev": "f3f9494671f93fcff853e3c6e9e948b3eb71e590"
},
{
"ImportPath": "github.com/gogo/protobuf/proto",
@ -100,15 +100,15 @@
},
{
"ImportPath": "github.com/mailru/easyjson/buffer",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/mailru/easyjson/jlexer",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/mailru/easyjson/jwriter",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/mxk/go-flowrate/flowrate",

View File

@ -340,11 +340,11 @@
},
{
"ImportPath": "github.com/go-openapi/spec",
"Rev": "6aced65f8501fe1217321abf0749d354824ba2ff"
"Rev": "7abd5745472fff5eb3685386d5fb8bf38683154d"
},
{
"ImportPath": "github.com/go-openapi/swag",
"Rev": "1d0bd113de87027671077d3c71eb3ac5d7dbba72"
"Rev": "f3f9494671f93fcff853e3c6e9e948b3eb71e590"
},
{
"ImportPath": "github.com/gogo/protobuf/proto",
@ -488,15 +488,15 @@
},
{
"ImportPath": "github.com/mailru/easyjson/buffer",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/mailru/easyjson/jlexer",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/mailru/easyjson/jwriter",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/matttproud/golang_protobuf_extensions/pbutil",

View File

@ -112,11 +112,11 @@
},
{
"ImportPath": "github.com/go-openapi/spec",
"Rev": "6aced65f8501fe1217321abf0749d354824ba2ff"
"Rev": "7abd5745472fff5eb3685386d5fb8bf38683154d"
},
{
"ImportPath": "github.com/go-openapi/swag",
"Rev": "1d0bd113de87027671077d3c71eb3ac5d7dbba72"
"Rev": "f3f9494671f93fcff853e3c6e9e948b3eb71e590"
},
{
"ImportPath": "github.com/gogo/protobuf/proto",
@ -240,15 +240,15 @@
},
{
"ImportPath": "github.com/mailru/easyjson/buffer",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/mailru/easyjson/jlexer",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/mailru/easyjson/jwriter",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/peterbourgon/diskv",

View File

@ -32,11 +32,11 @@
},
{
"ImportPath": "github.com/go-openapi/spec",
"Rev": "6aced65f8501fe1217321abf0749d354824ba2ff"
"Rev": "7abd5745472fff5eb3685386d5fb8bf38683154d"
},
{
"ImportPath": "github.com/go-openapi/swag",
"Rev": "1d0bd113de87027671077d3c71eb3ac5d7dbba72"
"Rev": "f3f9494671f93fcff853e3c6e9e948b3eb71e590"
},
{
"ImportPath": "github.com/gogo/protobuf/gogoproto",
@ -144,15 +144,15 @@
},
{
"ImportPath": "github.com/mailru/easyjson/buffer",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/mailru/easyjson/jlexer",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/mailru/easyjson/jwriter",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/spf13/pflag",
@ -206,6 +206,10 @@
"ImportPath": "golang.org/x/text/width",
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
},
{
"ImportPath": "gopkg.in/yaml.v2",
"Rev": "53feefa2559fb8dfa8d81baad31be332c97d6c77"
},
{
"ImportPath": "k8s.io/gengo/args",
"Rev": "9e661e9308f078838e266cca1c673922088c0ea4"

View File

@ -128,11 +128,11 @@
},
{
"ImportPath": "github.com/go-openapi/spec",
"Rev": "6aced65f8501fe1217321abf0749d354824ba2ff"
"Rev": "7abd5745472fff5eb3685386d5fb8bf38683154d"
},
{
"ImportPath": "github.com/go-openapi/swag",
"Rev": "1d0bd113de87027671077d3c71eb3ac5d7dbba72"
"Rev": "f3f9494671f93fcff853e3c6e9e948b3eb71e590"
},
{
"ImportPath": "github.com/gogo/protobuf/proto",
@ -244,15 +244,15 @@
},
{
"ImportPath": "github.com/mailru/easyjson/buffer",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/mailru/easyjson/jlexer",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/mailru/easyjson/jwriter",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/matttproud/golang_protobuf_extensions/pbutil",

View File

@ -44,11 +44,11 @@
},
{
"ImportPath": "github.com/go-openapi/spec",
"Rev": "6aced65f8501fe1217321abf0749d354824ba2ff"
"Rev": "7abd5745472fff5eb3685386d5fb8bf38683154d"
},
{
"ImportPath": "github.com/go-openapi/swag",
"Rev": "1d0bd113de87027671077d3c71eb3ac5d7dbba72"
"Rev": "f3f9494671f93fcff853e3c6e9e948b3eb71e590"
},
{
"ImportPath": "github.com/gogo/protobuf/proto",
@ -120,15 +120,15 @@
},
{
"ImportPath": "github.com/mailru/easyjson/buffer",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/mailru/easyjson/jlexer",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/mailru/easyjson/jwriter",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/peterbourgon/diskv",

View File

@ -120,11 +120,11 @@
},
{
"ImportPath": "github.com/go-openapi/spec",
"Rev": "6aced65f8501fe1217321abf0749d354824ba2ff"
"Rev": "7abd5745472fff5eb3685386d5fb8bf38683154d"
},
{
"ImportPath": "github.com/go-openapi/swag",
"Rev": "1d0bd113de87027671077d3c71eb3ac5d7dbba72"
"Rev": "f3f9494671f93fcff853e3c6e9e948b3eb71e590"
},
{
"ImportPath": "github.com/gogo/protobuf/proto",
@ -236,15 +236,15 @@
},
{
"ImportPath": "github.com/mailru/easyjson/buffer",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/mailru/easyjson/jlexer",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/mailru/easyjson/jwriter",
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
"Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d"
},
{
"ImportPath": "github.com/matttproud/golang_protobuf_extensions/pbutil",

26
vendor/github.com/go-openapi/loads/.editorconfig generated vendored Normal file
View File

@ -0,0 +1,26 @@
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
# Set default charset
[*.{js,py,go,scala,rb,java,html,css,less,sass,md}]
charset = utf-8
# Tab indentation (no size specified)
[*.go]
indent_style = tab
[*.md]
trim_trailing_whitespace = false
# Matches the exact files either package.json or .travis.yml
[{package.json,.travis.yml}]
indent_style = space
indent_size = 2

View File

@ -1,13 +0,0 @@
approve_by_comment: true
approve_regex: '^(:shipit:|:\+1:|\+1|LGTM|lgtm|Approved)'
reject_regex: ^[Rr]ejected
reset_on_push: false
reviewers:
members:
- casualjim
- chancez
- frapposelli
- vburenin
- pytlesk4
name: pullapprove
required: 1

16
vendor/github.com/go-openapi/loads/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,16 @@
language: go
go:
- 1.8
install:
- go get -u github.com/stretchr/testify
- go get -u github.com/go-openapi/analysis
- go get -u github.com/go-openapi/spec
- go get -u github.com/go-openapi/swag
- go get -u gopkg.in/yaml.v2
script:
- ./hack/coverage
after_success:
- bash <(curl -s https://codecov.io/bash)
notifications:
slack:
secure: OxkPwVp35qBTUilgWC8xykSj+sGMcj0h8IIOKD+Rflx2schZVlFfdYdyVBM+s9OqeOfvtuvnR9v1Ye2rPKAvcjWdC4LpRGUsgmItZaI6Um8Aj6+K9udCw5qrtZVfOVmRu8LieH//XznWWKdOultUuniW0MLqw5+II87Gd00RWbCGi0hk0PykHe7uK+PDA2BEbqyZ2WKKYCvfB3j+0nrFOHScXqnh0V05l2E83J4+Sgy1fsPy+1WdX58ZlNBG333ibaC1FS79XvKSmTgKRkx3+YBo97u6ZtUmJa5WZjf2OdLG3KIckGWAv6R5xgxeU31N0Ng8L332w/Edpp2O/M2bZwdnKJ8hJQikXIAQbICbr+lTDzsoNzMdEIYcHpJ5hjPbiUl3Bmd+Jnsjf5McgAZDiWIfpCKZ29tPCEkVwRsOCqkyPRMNMzHHmoja495P5jR+ODS7+J8RFg5xgcnOgpP9D4Wlhztlf5WyZMpkLxTUD+bZq2SRf50HfHFXTkfq22zPl3d1eq0yrLwh/Z/fWKkfb6SyysROL8y6s8u3dpFX1YHSg0BR6i913h4aoZw9B2BG27cafLLTwKYsp2dFo1PWl4O6u9giFJIeqwloZHLKKrwh0cBFhB7RH0I58asxkZpCH6uWjJierahmHe7iS+E6i+9oCHkOZ59hmCYNimIs3hM=

View File

@ -1,4 +1,4 @@
# Loads OAI specs [![Build Status](https://ci.vmware.run/api/badges/go-openapi/loads/status.svg)](https://ci.vmware.run/go-openapi/loads) [![Coverage](https://coverage.vmware.run/badges/go-openapi/loads/coverage.svg)](https://coverage.vmware.run/go-openapi/loads) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
# Loads OAI specs [![Build Status](https://travis-ci.org/go-openapi/loads.svg?branch=master)](https://travis-ci.org/go-openapi/loads) [![codecov](https://codecov.io/gh/go-openapi/loads/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/loads) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/loads/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/loads?status.svg)](http://godoc.org/github.com/go-openapi/loads)

View File

@ -15,10 +15,13 @@
package loads
import (
"bytes"
"encoding/json"
"fmt"
"net/url"
"path/filepath"
"github.com/go-openapi/analysis"
"github.com/go-openapi/spec"
"github.com/go-openapi/swag"
@ -39,7 +42,17 @@ type DocLoader func(string) (json.RawMessage, error)
// DocMatcher represents a predicate to check if a loader matches
type DocMatcher func(string) bool
var loaders = &loader{Match: func(_ string) bool { return true }, Fn: JSONDoc}
var (
loaders *loader
defaultLoader *loader
)
func init() {
defaultLoader = &loader{Match: func(_ string) bool { return true }, Fn: JSONDoc}
loaders = defaultLoader
spec.PathLoader = loaders.Fn
AddLoader(swag.YAMLMatcher, swag.YAMLDoc)
}
// AddLoader for a document
func AddLoader(predicate DocMatcher, load DocLoader) {
@ -49,7 +62,7 @@ func AddLoader(predicate DocMatcher, load DocLoader) {
Fn: load,
Next: prev,
}
spec.PathLoader = loaders.Fn
}
type loader struct {
@ -73,6 +86,7 @@ type Document struct {
// specAnalyzer
Analyzer *analysis.Spec
spec *spec.Swagger
specFilePath string
origSpec *spec.Swagger
schema *spec.Schema
raw json.RawMessage
@ -84,23 +98,39 @@ func Spec(path string) (*Document, error) {
if err != nil {
return nil, err
}
var lastErr error
for l := loaders.Next; l != nil; l = l.Next {
if loaders.Match(specURL.Path) {
b, err2 := loaders.Fn(path)
if err2 != nil {
return nil, err2
lastErr = err2
continue
}
return Analyzed(b, "")
}
}
b, err := loaders.Fn(path)
doc, err := Analyzed(b, "")
if err != nil {
return nil, err
}
if doc != nil {
doc.specFilePath = path
}
return doc, nil
}
}
if lastErr != nil {
return nil, lastErr
}
b, err := defaultLoader.Fn(path)
if err != nil {
return nil, err
}
return Analyzed(b, "")
}
var swag20Schema = spec.MustLoadSwagger20Schema()
document, err := Analyzed(b, "")
if document != nil {
document.specFilePath = path
}
return document, err
}
// Analyzed creates a new analyzed spec document
func Analyzed(data json.RawMessage, version string) (*Document, error) {
@ -111,40 +141,66 @@ func Analyzed(data json.RawMessage, version string) (*Document, error) {
return nil, fmt.Errorf("spec version %q is not supported", version)
}
raw := data
trimmed := bytes.TrimSpace(data)
if len(trimmed) > 0 {
if trimmed[0] != '{' && trimmed[0] != '[' {
yml, err := swag.BytesToYAMLDoc(trimmed)
if err != nil {
return nil, fmt.Errorf("analyzed: %v", err)
}
d, err := swag.YAMLToJSON(yml)
if err != nil {
return nil, fmt.Errorf("analyzed: %v", err)
}
raw = d
}
}
swspec := new(spec.Swagger)
if err := json.Unmarshal(data, swspec); err != nil {
if err := json.Unmarshal(raw, swspec); err != nil {
return nil, err
}
origsqspec := new(spec.Swagger)
if err := json.Unmarshal(data, origsqspec); err != nil {
if err := json.Unmarshal(raw, origsqspec); err != nil {
return nil, err
}
d := &Document{
Analyzer: analysis.New(swspec),
schema: swag20Schema,
schema: spec.MustLoadSwagger20Schema(),
spec: swspec,
raw: data,
raw: raw,
origSpec: origsqspec,
}
return d, nil
}
// Expanded expands the ref fields in the spec document and returns a new spec document
func (d *Document) Expanded() (*Document, error) {
func (d *Document) Expanded(options ...*spec.ExpandOptions) (*Document, error) {
swspec := new(spec.Swagger)
if err := json.Unmarshal(d.raw, swspec); err != nil {
return nil, err
}
if err := spec.ExpandSpec(swspec); err != nil {
var expandOptions *spec.ExpandOptions
if len(options) > 0 {
expandOptions = options[1]
} else {
expandOptions = &spec.ExpandOptions{
RelativeBase: filepath.Dir(d.specFilePath),
}
}
if err := spec.ExpandSpec(swspec, expandOptions); err != nil {
return nil, err
}
dd := &Document{
Analyzer: analysis.New(swspec),
spec: swspec,
schema: swag20Schema,
schema: spec.MustLoadSwagger20Schema(),
raw: d.raw,
origSpec: d.origSpec,
}
@ -201,3 +257,8 @@ func (d *Document) Pristine() *Document {
dd, _ := Analyzed(d.Raw(), d.Version())
return dd
}
// SpecFilePath returns the file path of the spec if one is defined
func (d *Document) SpecFilePath() string {
return d.specFilePath
}

View File

@ -1 +0,0 @@
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.Epk8dDFH8U1RPYIPDpajZO26L5zFJ1wnQNGWxVHHo5cXrWF148kENoZzh35FT9cAxxPS_4CeVVpf59EgvCc8bem1puuj0gBZptn-lYa7iXZdI-ESN2Te7nF5VbZfwbnI62nEikYGyxz-ozL_IFuMl-qWek4iLerF8Z_xh0MZOJ_w8Nog7qb2WQov72d997TJv5ZKjWcRYPbnsAy1q60-Cqxq3a6enhcSPXqpK46nYSXGKfHvognWBJ_pxwkEqIBPN6hE4EfNtJjMf2LFKEdYy02nbHz78d-2YZ8wIUSJ-IWIwn3GTzObdGqRed20Qf3JtWTsOespmexDrLSeo3HW6A.7XaHW-Y1jjRAWt_W.S1Adut62RLOYZc-lN02M0MGczEucch3zIr4J1UPBPnZooWzntiE5UaUz0UdhjHVszQE5hTfG-yocKD1rDQGER6qrLtnJVrCm9J3n4lHglM-xOz1eZln1XKrWcAgZnAKaKSzuAa5scPG4iTHW6RwbWi_PWm04tBJ1yazdjaVo3uvuhflwvU9if7uMPMtscrDesbBVvpG89xmeudiFjX-wjsV5oGBIjz6ukEBAMKzNDMqikNoG4SnGenpxUpjUjMkDXxiC3BC8oL2_myeIfFeEOF066DqEN3CLkqBVO25zdpWAF4Ou2jKv--mgGEb_E1aMgiSoAVBnybene0TKn2IJ8rtkyRdmWlLIRKZdDT3v775C1FPK6-tYzS7NVg9nnuvpta5PhzYNkqI1Ie74Sl0I-RFClhsdx9dLDhoFEKCx2etC4UDX9jhj2u0Y2MrL76dRGE9kEV1hL1fh6HMvS4ZAAWw3Qce4skCjcL-2YyIOHzKjgLGkZsR5cTUQwCJyacVkdHUOUKFdDGZaUzWkFyeZ1oyrlG2d52svaplpU5-vCOVbWkqUN9rOALGPTC51Ur0L7DFx29aDImhaxZqTe2t9mcdqY7VLcO3JgUiD3JKsEet7s2EDeN44MqITv9KBS8wqJW4.sRv4ov0wB0IxTHw90kJy-A

View File

@ -1,35 +0,0 @@
clone:
path: github.com/go-openapi/spec
matrix:
GO_VERSION:
- "1.6"
build:
integration:
image: golang:$$GO_VERSION
pull: true
commands:
- go get -u github.com/stretchr/testify/assert
- go get -u gopkg.in/yaml.v2
- go get -u github.com/go-openapi/swag
- go get -u github.com/go-openapi/jsonpointer
- go get -u github.com/go-openapi/jsonreference
- go test -race
- go test -v -cover -coverprofile=coverage.out -covermode=count ./...
notify:
slack:
channel: bots
webhook_url: $$SLACK_URL
username: drone
publish:
coverage:
server: https://coverage.vmware.run
token: $$GITHUB_TOKEN
# threshold: 70
# must_increase: true
when:
matrix:
GO_VERSION: "1.6"

26
vendor/github.com/go-openapi/spec/.editorconfig generated vendored Normal file
View File

@ -0,0 +1,26 @@
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
# Set default charset
[*.{js,py,go,scala,rb,java,html,css,less,sass,md}]
charset = utf-8
# Tab indentation (no size specified)
[*.go]
indent_style = tab
[*.md]
trim_trailing_whitespace = false
# Matches the exact files either package.json or .travis.yml
[{package.json,.travis.yml}]
indent_style = space
indent_size = 2

View File

@ -1,13 +0,0 @@
approve_by_comment: true
approve_regex: '^(:shipit:|:\+1:|\+1|LGTM|lgtm|Approved)'
reject_regex: ^[Rr]ejected
reset_on_push: false
reviewers:
members:
- casualjim
- chancez
- frapposelli
- vburenin
- pytlesk4
name: pullapprove
required: 1

16
vendor/github.com/go-openapi/spec/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,16 @@
language: go
go:
- 1.7
install:
- go get -u github.com/stretchr/testify
- go get -u github.com/go-openapi/swag
- go get -u gopkg.in/yaml.v2
- go get -u github.com/go-openapi/jsonpointer
- go get -u github.com/go-openapi/jsonreference
script:
- go test -v -race -cover -coverprofile=coverage.txt -covermode=atomic ./...
after_success:
- bash <(curl -s https://codecov.io/bash)
notifications:
slack:
secure: QUWvCkBBK09GF7YtEvHHVt70JOkdlNBG0nIKu/5qc4/nW5HP8I2w0SEf/XR2je0eED1Qe3L/AfMCWwrEj+IUZc3l4v+ju8X8R3Lomhme0Eb0jd1MTMCuPcBT47YCj0M7RON7vXtbFfm1hFJ/jLe5+9FXz0hpXsR24PJc5ZIi/ogNwkaPqG4BmndzecpSh0vc2FJPZUD9LT0I09REY/vXR0oQAalLkW0asGD5taHZTUZq/kBpsNxaAFrLM23i4mUcf33M5fjLpvx5LRICrX/57XpBrDh2TooBU6Qj3CgoY0uPRYUmSNxbVx1czNzl2JtEpb5yjoxfVPQeg0BvQM00G8LJINISR+ohrjhkZmAqchDupAX+yFrxTtORa78CtnIL6z/aTNlgwwVD8kvL/1pFA/JWYmKDmz93mV/+6wubGzNSQCstzjkFA4/iZEKewKUoRIAi/fxyscP6L/rCpmY/4llZZvrnyTqVbt6URWpopUpH4rwYqreXAtJxJsfBJIeSmUIiDIOMGkCTvyTEW3fWGmGoqWtSHLoaWDyAIGb7azb+KvfpWtEcoPFWfSWU+LGee0A/YsUhBl7ADB9A0CJEuR8q4BPpKpfLwPKSiKSAXL7zDkyjExyhtgqbSl2jS+rKIHOZNL8JkCcTP2MKMVd563C5rC5FMKqu3S9m2b6380E=

View File

@ -1,4 +1,4 @@
# OAI object model [![Build Status](https://ci.vmware.run/api/badges/go-openapi/spec/status.svg)](https://ci.vmware.run/go-openapi/spec) [![Coverage](https://coverage.vmware.run/badges/go-openapi/spec/coverage.svg)](https://coverage.vmware.run/go-openapi/spec) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
# OAI object model [![Build Status](https://travis-ci.org/go-openapi/spec.svg?branch=master)](https://travis-ci.org/go-openapi/spec) [![codecov](https://codecov.io/gh/go-openapi/spec/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/spec) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/spec/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/spec?status.svg)](http://godoc.org/github.com/go-openapi/spec)

File diff suppressed because one or more lines are too long

View File

@ -17,7 +17,10 @@ package spec
import (
"encoding/json"
"fmt"
"log"
"net/url"
"os"
"path/filepath"
"reflect"
"strings"
"sync"
@ -26,6 +29,18 @@ import (
"github.com/go-openapi/swag"
)
var (
// Debug enables logging when SWAGGER_DEBUG env var is not empty
Debug = os.Getenv("SWAGGER_DEBUG") != ""
)
// ExpandOptions provides options for expand.
type ExpandOptions struct {
RelativeBase string
SkipSchemas bool
ContinueOnError bool
}
// ResolutionCache a cache for resolving urls
type ResolutionCache interface {
Get(string) (interface{}, bool)
@ -37,7 +52,11 @@ type simpleCache struct {
store map[string]interface{}
}
var resCache = initResolutionCache()
var resCache ResolutionCache
func init() {
resCache = initResolutionCache()
}
func initResolutionCache() ResolutionCache {
return &simpleCache{store: map[string]interface{}{
@ -47,8 +66,11 @@ func initResolutionCache() ResolutionCache {
}
func (s *simpleCache) Get(uri string) (interface{}, bool) {
debugLog("getting %q from resolution cache", uri)
s.lock.Lock()
v, ok := s.store[uri]
debugLog("got %q from resolution cache: %t", uri, ok)
s.lock.Unlock()
return v, ok
}
@ -59,9 +81,9 @@ func (s *simpleCache) Set(uri string, data interface{}) {
s.lock.Unlock()
}
// ResolveRef resolves a reference against a context root
func ResolveRef(root interface{}, ref *Ref) (*Schema, error) {
resolver, err := defaultSchemaLoader(root, nil, nil)
// ResolveRefWithBase resolves a reference against a context root with preservation of base path
func ResolveRefWithBase(root interface{}, ref *Ref, opts *ExpandOptions) (*Schema, error) {
resolver, err := defaultSchemaLoader(root, nil, opts, nil)
if err != nil {
return nil, err
}
@ -73,9 +95,19 @@ func ResolveRef(root interface{}, ref *Ref) (*Schema, error) {
return result, nil
}
// ResolveRef resolves a reference against a context root
func ResolveRef(root interface{}, ref *Ref) (*Schema, error) {
return ResolveRefWithBase(root, ref, nil)
}
// ResolveParameter resolves a paramter reference against a context root
func ResolveParameter(root interface{}, ref Ref) (*Parameter, error) {
resolver, err := defaultSchemaLoader(root, nil, nil)
return ResolveParameterWithBase(root, ref, nil)
}
// ResolveParameterWithBase resolves a paramter reference against a context root and base path
func ResolveParameterWithBase(root interface{}, ref Ref, opts *ExpandOptions) (*Parameter, error) {
resolver, err := defaultSchemaLoader(root, nil, opts, nil)
if err != nil {
return nil, err
}
@ -89,7 +121,12 @@ func ResolveParameter(root interface{}, ref Ref) (*Parameter, error) {
// ResolveResponse resolves response a reference against a context root
func ResolveResponse(root interface{}, ref Ref) (*Response, error) {
resolver, err := defaultSchemaLoader(root, nil, nil)
return ResolveResponseWithBase(root, ref, nil)
}
// ResolveResponseWithBase resolves response a reference against a context root and base path
func ResolveResponseWithBase(root interface{}, ref Ref, opts *ExpandOptions) (*Response, error) {
resolver, err := defaultSchemaLoader(root, nil, opts, nil)
if err != nil {
return nil, err
}
@ -101,23 +138,72 @@ func ResolveResponse(root interface{}, ref Ref) (*Response, error) {
return result, nil
}
// ResolveItems resolves header and parameter items reference against a context root and base path
func ResolveItems(root interface{}, ref Ref, opts *ExpandOptions) (*Items, error) {
resolver, err := defaultSchemaLoader(root, nil, opts, nil)
if err != nil {
return nil, err
}
result := new(Items)
if err := resolver.Resolve(&ref, result); err != nil {
return nil, err
}
return result, nil
}
// ResolvePathItem resolves response a path item against a context root and base path
func ResolvePathItem(root interface{}, ref Ref, opts *ExpandOptions) (*PathItem, error) {
resolver, err := defaultSchemaLoader(root, nil, opts, nil)
if err != nil {
return nil, err
}
result := new(PathItem)
if err := resolver.Resolve(&ref, result); err != nil {
return nil, err
}
return result, nil
}
type schemaLoader struct {
loadingRef *Ref
startingRef *Ref
currentRef *Ref
root interface{}
options *ExpandOptions
cache ResolutionCache
loadDoc func(string) (json.RawMessage, error)
}
var idPtr, _ = jsonpointer.New("/id")
var schemaPtr, _ = jsonpointer.New("/$schema")
var refPtr, _ = jsonpointer.New("/$ref")
func defaultSchemaLoader(root interface{}, ref *Ref, cache ResolutionCache) (*schemaLoader, error) {
// PathLoader function to use when loading remote refs
var PathLoader func(string) (json.RawMessage, error)
func init() {
PathLoader = func(path string) (json.RawMessage, error) {
data, err := swag.LoadFromFileOrHTTP(path)
if err != nil {
return nil, err
}
return json.RawMessage(data), nil
}
}
func defaultSchemaLoader(
root interface{},
ref *Ref,
expandOptions *ExpandOptions,
cache ResolutionCache) (*schemaLoader, error) {
if cache == nil {
cache = resCache
}
if expandOptions == nil {
expandOptions = &ExpandOptions{}
}
var ptr *jsonpointer.Pointer
if ref != nil {
@ -127,18 +213,16 @@ func defaultSchemaLoader(root interface{}, ref *Ref, cache ResolutionCache) (*sc
currentRef := nextRef(root, ref, ptr)
return &schemaLoader{
root: root,
loadingRef: ref,
startingRef: ref,
currentRef: currentRef,
root: root,
options: expandOptions,
cache: cache,
loadDoc: func(path string) (json.RawMessage, error) {
data, err := swag.LoadFromFileOrHTTP(path)
if err != nil {
return nil, err
}
return json.RawMessage(data), nil
debugLog("fetching document at %q", path)
return PathLoader(path)
},
currentRef: currentRef,
}, nil
}
@ -159,6 +243,7 @@ func nextRef(startingNode interface{}, startingRef *Ref, ptr *jsonpointer.Pointe
if startingRef == nil {
return nil
}
if ptr == nil {
return startingRef
}
@ -184,32 +269,111 @@ func nextRef(startingNode interface{}, startingRef *Ref, ptr *jsonpointer.Pointe
refRef, _, _ := refPtr.Get(node)
if refRef != nil {
rf, _ := NewRef(refRef.(string))
var rf Ref
switch value := refRef.(type) {
case string:
rf, _ = NewRef(value)
}
nw, err := ret.Inherits(rf)
if err != nil {
break
}
nwURL := nw.GetURL()
if nwURL.Scheme == "file" || (nwURL.Scheme == "" && nwURL.Host == "") {
nwpt := filepath.ToSlash(nwURL.Path)
if filepath.IsAbs(nwpt) {
_, err := os.Stat(nwpt)
if err != nil {
nwURL.Path = filepath.Join(".", nwpt)
}
}
}
ret = nw
}
}
return ret
}
func debugLog(msg string, args ...interface{}) {
if Debug {
log.Printf(msg, args...)
}
}
func normalizeFileRef(ref *Ref, relativeBase string) *Ref {
refURL := ref.GetURL()
debugLog("normalizing %s against %s (%s)", ref.String(), relativeBase, refURL.String())
if strings.HasPrefix(refURL.String(), "#") {
return ref
}
if refURL.Scheme == "file" || (refURL.Scheme == "" && refURL.Host == "") {
filePath := refURL.Path
debugLog("normalizing file path: %s", filePath)
if !filepath.IsAbs(filepath.FromSlash(filePath)) && len(relativeBase) != 0 {
debugLog("joining %s with %s", relativeBase, filePath)
if fi, err := os.Stat(filepath.FromSlash(relativeBase)); err == nil {
if !fi.IsDir() {
relativeBase = filepath.Dir(filepath.FromSlash(relativeBase))
}
}
filePath = filepath.Join(filepath.FromSlash(relativeBase), filepath.FromSlash(filePath))
}
if !filepath.IsAbs(filepath.FromSlash(filePath)) {
pwd, err := os.Getwd()
if err == nil {
debugLog("joining cwd %s with %s", pwd, filePath)
filePath = filepath.Join(pwd, filepath.FromSlash(filePath))
}
}
debugLog("cleaning %s", filePath)
filePath = filepath.Clean(filepath.FromSlash(filePath))
_, err := os.Stat(filepath.FromSlash(filePath))
if err == nil {
debugLog("rewriting url %s to scheme \"\" path %s", refURL.String(), filePath)
slp := filepath.FromSlash(filePath)
if filepath.IsAbs(slp) && filepath.Separator == '\\' && len(slp) > 1 && slp[1] == ':' && ('a' <= slp[0] && slp[0] <= 'z' || 'A' <= slp[0] && slp[0] <= 'Z') {
slp = slp[2:]
}
refURL.Scheme = ""
refURL.Path = filepath.ToSlash(slp)
debugLog("new url with joined filepath: %s", refURL.String())
*ref = MustCreateRef(refURL.String())
}
}
debugLog("refurl: %s", ref.GetURL().String())
return ref
}
func (r *schemaLoader) resolveRef(currentRef, ref *Ref, node, target interface{}) error {
tgt := reflect.ValueOf(target)
if tgt.Kind() != reflect.Ptr {
return fmt.Errorf("resolve ref: target needs to be a pointer")
}
oldRef := currentRef
if currentRef != nil {
debugLog("resolve ref current %s new %s", currentRef.String(), ref.String())
nextRef := nextRef(node, ref, currentRef.GetPointer())
if nextRef == nil || nextRef.GetURL() == nil {
return nil
}
var err error
currentRef, err = currentRef.Inherits(*nextRef(node, ref, currentRef.GetPointer()))
currentRef, err = currentRef.Inherits(*nextRef)
debugLog("resolved ref current %s", currentRef.String())
if err != nil {
return err
}
}
if currentRef == nil {
currentRef = ref
}
@ -245,9 +409,16 @@ func (r *schemaLoader) resolveRef(currentRef, ref *Ref, node, target interface{}
return nil
}
if refURL.Scheme != "" && refURL.Host != "" {
// most definitely take the red pill
data, _, _, err := r.load(refURL)
relativeBase := ""
if r.options != nil && r.options.RelativeBase != "" {
relativeBase = r.options.RelativeBase
}
normalizeFileRef(currentRef, relativeBase)
debugLog("current ref normalized file: %s", currentRef.String())
normalizeFileRef(ref, relativeBase)
debugLog("ref normalized file: %s", currentRef.String())
data, _, _, err := r.load(currentRef.GetURL())
if err != nil {
return err
}
@ -265,9 +436,29 @@ func (r *schemaLoader) resolveRef(currentRef, ref *Ref, node, target interface{}
var res interface{}
if currentRef.String() != "" {
res, _, err = currentRef.GetPointer().Get(data)
if err != nil {
if strings.HasPrefix(ref.String(), "#") {
if r.loadingRef != nil {
rr, er := r.loadingRef.Inherits(*ref)
if er != nil {
return er
}
refURL = rr.GetURL()
data, _, _, err = r.load(refURL)
if err != nil {
return err
}
} else {
data = r.root
}
}
res, _, err = ref.GetPointer().Get(data)
if err != nil {
return err
}
}
} else {
res = data
}
@ -276,11 +467,13 @@ func (r *schemaLoader) resolveRef(currentRef, ref *Ref, node, target interface{}
return err
}
}
r.currentRef = currentRef
return nil
}
func (r *schemaLoader) load(refURL *url.URL) (interface{}, url.URL, bool, error) {
debugLog("loading schema from url: %s", refURL)
toFetch := *refURL
toFetch.Fragment = ""
@ -299,44 +492,51 @@ func (r *schemaLoader) load(refURL *url.URL) (interface{}, url.URL, bool, error)
return data, toFetch, fromCache, nil
}
func (r *schemaLoader) Resolve(ref *Ref, target interface{}) error {
if err := r.resolveRef(r.currentRef, ref, r.root, target); err != nil {
return err
}
return nil
func (r *schemaLoader) Resolve(ref *Ref, target interface{}) error {
return r.resolveRef(r.currentRef, ref, r.root, target)
}
type specExpander struct {
spec *Swagger
resolver *schemaLoader
func (r *schemaLoader) reset() {
ref := r.startingRef
var ptr *jsonpointer.Pointer
if ref != nil {
ptr = ref.GetPointer()
}
r.currentRef = nextRef(r.root, ref, ptr)
}
// ExpandSpec expands the references in a swagger spec
func ExpandSpec(spec *Swagger) error {
resolver, err := defaultSchemaLoader(spec, nil, nil)
if err != nil {
func ExpandSpec(spec *Swagger, options *ExpandOptions) error {
resolver, err := defaultSchemaLoader(spec, nil, options, nil)
// Just in case this ever returns an error.
if shouldStopOnError(err, resolver.options) {
return err
}
for key, defintition := range spec.Definitions {
if options == nil || !options.SkipSchemas {
for key, definition := range spec.Definitions {
var def *Schema
var err error
if def, err = expandSchema(defintition, []string{"#/definitions/" + key}, resolver); err != nil {
if def, err = expandSchema(definition, []string{"#/definitions/" + key}, resolver); shouldStopOnError(err, resolver.options) {
return err
}
resolver.reset()
spec.Definitions[key] = *def
}
}
for key, parameter := range spec.Parameters {
if err := expandParameter(&parameter, resolver); err != nil {
if err := expandParameter(&parameter, resolver); shouldStopOnError(err, resolver.options) {
return err
}
spec.Parameters[key] = parameter
}
for key, response := range spec.Responses {
if err := expandResponse(&response, resolver); err != nil {
if err := expandResponse(&response, resolver); shouldStopOnError(err, resolver.options) {
return err
}
spec.Responses[key] = response
@ -344,7 +544,7 @@ func ExpandSpec(spec *Swagger) error {
if spec.Paths != nil {
for key, path := range spec.Paths.Paths {
if err := expandPathItem(&path, resolver); err != nil {
if err := expandPathItem(&path, resolver); shouldStopOnError(err, resolver.options) {
return err
}
spec.Paths.Paths[key] = path
@ -354,9 +554,25 @@ func ExpandSpec(spec *Swagger) error {
return nil
}
func shouldStopOnError(err error, opts *ExpandOptions) bool {
if err != nil && !opts.ContinueOnError {
return true
}
if err != nil {
log.Println(err)
}
return false
}
// ExpandSchema expands the refs in the schema object
func ExpandSchema(schema *Schema, root interface{}, cache ResolutionCache) error {
return ExpandSchemaWithBasePath(schema, root, cache, nil)
}
// ExpandSchemaWithBasePath expands the refs in the schema object, base path configured through expand options
func ExpandSchemaWithBasePath(schema *Schema, root interface{}, cache ResolutionCache, opts *ExpandOptions) error {
if schema == nil {
return nil
}
@ -367,18 +583,17 @@ func ExpandSchema(schema *Schema, root interface{}, cache ResolutionCache) error
nrr, _ := NewRef(schema.ID)
var rrr *Ref
if nrr.String() != "" {
switch root.(type) {
switch rt := root.(type) {
case *Schema:
rid, _ := NewRef(root.(*Schema).ID)
rid, _ := NewRef(rt.ID)
rrr, _ = rid.Inherits(nrr)
case *Swagger:
rid, _ := NewRef(root.(*Swagger).ID)
rid, _ := NewRef(rt.ID)
rrr, _ = rid.Inherits(nrr)
}
}
resolver, err := defaultSchemaLoader(root, rrr, cache)
resolver, err := defaultSchemaLoader(root, rrr, opts, cache)
if err != nil {
return err
}
@ -389,7 +604,7 @@ func ExpandSchema(schema *Schema, root interface{}, cache ResolutionCache) error
}
var s *Schema
if s, err = expandSchema(*schema, refs, resolver); err != nil {
return nil
return err
}
*schema = *s
return nil
@ -399,9 +614,17 @@ func expandItems(target Schema, parentRefs []string, resolver *schemaLoader) (*S
if target.Items != nil {
if target.Items.Schema != nil {
t, err := expandSchema(*target.Items.Schema, parentRefs, resolver)
if err != nil {
if target.Items.Schema.ID == "" {
target.Items.Schema.ID = target.ID
if err != nil {
t, err = expandSchema(*target.Items.Schema, parentRefs, resolver)
if err != nil {
return nil, err
}
}
}
}
*target.Items.Schema = *t
}
for i := range target.Items.Schemas {
@ -415,137 +638,173 @@ func expandItems(target Schema, parentRefs []string, resolver *schemaLoader) (*S
return &target, nil
}
func expandSchema(target Schema, parentRefs []string, resolver *schemaLoader) (schema *Schema, err error) {
defer func() {
schema = &target
}()
func expandSchema(target Schema, parentRefs []string, resolver *schemaLoader) (*Schema, error) {
if target.Ref.String() == "" && target.Ref.IsRoot() {
target = *resolver.root.(*Schema)
return
debugLog("skipping expand schema for no ref and root: %v", resolver.root)
return resolver.root.(*Schema), nil
}
// t is the new expanded schema
var t *Schema
for target.Ref.String() != "" {
// var newTarget Schema
pRefs := strings.Join(parentRefs, ",")
pRefs += ","
if strings.Contains(pRefs, target.Ref.String()+",") {
err = nil
return
if swag.ContainsStringsCI(parentRefs, target.Ref.String()) {
return &target, nil
}
if err = resolver.Resolve(&target.Ref, &t); err != nil {
return
if err := resolver.Resolve(&target.Ref, &t); shouldStopOnError(err, resolver.options) {
return &target, err
}
if swag.ContainsStringsCI(parentRefs, target.Ref.String()) {
debugLog("ref already exists in parent")
return &target, nil
}
parentRefs = append(parentRefs, target.Ref.String())
if t != nil {
target = *t
}
}
if t, err = expandItems(target, parentRefs, resolver); err != nil {
return
t, err := expandItems(target, parentRefs, resolver)
if shouldStopOnError(err, resolver.options) {
return &target, err
}
if t != nil {
target = *t
}
for i := range target.AllOf {
if t, err = expandSchema(target.AllOf[i], parentRefs, resolver); err != nil {
return
t, err := expandSchema(target.AllOf[i], parentRefs, resolver)
if shouldStopOnError(err, resolver.options) {
return &target, err
}
if t != nil {
target.AllOf[i] = *t
}
}
for i := range target.AnyOf {
if t, err = expandSchema(target.AnyOf[i], parentRefs, resolver); err != nil {
return
t, err := expandSchema(target.AnyOf[i], parentRefs, resolver)
if shouldStopOnError(err, resolver.options) {
return &target, err
}
target.AnyOf[i] = *t
}
for i := range target.OneOf {
if t, err = expandSchema(target.OneOf[i], parentRefs, resolver); err != nil {
return
t, err := expandSchema(target.OneOf[i], parentRefs, resolver)
if shouldStopOnError(err, resolver.options) {
return &target, err
}
if t != nil {
target.OneOf[i] = *t
}
if target.Not != nil {
if t, err = expandSchema(*target.Not, parentRefs, resolver); err != nil {
return
}
if target.Not != nil {
t, err := expandSchema(*target.Not, parentRefs, resolver)
if shouldStopOnError(err, resolver.options) {
return &target, err
}
if t != nil {
*target.Not = *t
}
for k, _ := range target.Properties {
if t, err = expandSchema(target.Properties[k], parentRefs, resolver); err != nil {
return
}
for k := range target.Properties {
t, err := expandSchema(target.Properties[k], parentRefs, resolver)
if shouldStopOnError(err, resolver.options) {
return &target, err
}
if t != nil {
target.Properties[k] = *t
}
if target.AdditionalProperties != nil && target.AdditionalProperties.Schema != nil {
if t, err = expandSchema(*target.AdditionalProperties.Schema, parentRefs, resolver); err != nil {
return
}
if target.AdditionalProperties != nil && target.AdditionalProperties.Schema != nil {
t, err := expandSchema(*target.AdditionalProperties.Schema, parentRefs, resolver)
if shouldStopOnError(err, resolver.options) {
return &target, err
}
if t != nil {
*target.AdditionalProperties.Schema = *t
}
for k, _ := range target.PatternProperties {
if t, err = expandSchema(target.PatternProperties[k], parentRefs, resolver); err != nil {
return
}
for k := range target.PatternProperties {
t, err := expandSchema(target.PatternProperties[k], parentRefs, resolver)
if shouldStopOnError(err, resolver.options) {
return &target, err
}
if t != nil {
target.PatternProperties[k] = *t
}
for k, _ := range target.Dependencies {
if target.Dependencies[k].Schema != nil {
if t, err = expandSchema(*target.Dependencies[k].Schema, parentRefs, resolver); err != nil {
return
}
for k := range target.Dependencies {
if target.Dependencies[k].Schema != nil {
t, err := expandSchema(*target.Dependencies[k].Schema, parentRefs, resolver)
if shouldStopOnError(err, resolver.options) {
return &target, err
}
if t != nil {
*target.Dependencies[k].Schema = *t
}
}
if target.AdditionalItems != nil && target.AdditionalItems.Schema != nil {
if t, err = expandSchema(*target.AdditionalItems.Schema, parentRefs, resolver); err != nil {
return
}
if target.AdditionalItems != nil && target.AdditionalItems.Schema != nil {
t, err := expandSchema(*target.AdditionalItems.Schema, parentRefs, resolver)
if shouldStopOnError(err, resolver.options) {
return &target, err
}
if t != nil {
*target.AdditionalItems.Schema = *t
}
for k, _ := range target.Definitions {
if t, err = expandSchema(target.Definitions[k], parentRefs, resolver); err != nil {
return
}
for k := range target.Definitions {
t, err := expandSchema(target.Definitions[k], parentRefs, resolver)
if shouldStopOnError(err, resolver.options) {
return &target, err
}
if t != nil {
target.Definitions[k] = *t
}
return
}
return &target, nil
}
func expandPathItem(pathItem *PathItem, resolver *schemaLoader) error {
if pathItem == nil {
return nil
}
if pathItem.Ref.String() != "" {
if err := resolver.Resolve(&pathItem.Ref, &pathItem); err != nil {
return err
}
resolver.reset()
pathItem.Ref = Ref{}
}
for idx := range pathItem.Parameters {
if err := expandParameter(&(pathItem.Parameters[idx]), resolver); err != nil {
if err := expandParameter(&(pathItem.Parameters[idx]), resolver); shouldStopOnError(err, resolver.options) {
return err
}
}
if err := expandOperation(pathItem.Get, resolver); err != nil {
if err := expandOperation(pathItem.Get, resolver); shouldStopOnError(err, resolver.options) {
return err
}
if err := expandOperation(pathItem.Head, resolver); err != nil {
if err := expandOperation(pathItem.Head, resolver); shouldStopOnError(err, resolver.options) {
return err
}
if err := expandOperation(pathItem.Options, resolver); err != nil {
if err := expandOperation(pathItem.Options, resolver); shouldStopOnError(err, resolver.options) {
return err
}
if err := expandOperation(pathItem.Put, resolver); err != nil {
if err := expandOperation(pathItem.Put, resolver); shouldStopOnError(err, resolver.options) {
return err
}
if err := expandOperation(pathItem.Post, resolver); err != nil {
if err := expandOperation(pathItem.Post, resolver); shouldStopOnError(err, resolver.options) {
return err
}
if err := expandOperation(pathItem.Patch, resolver); err != nil {
if err := expandOperation(pathItem.Patch, resolver); shouldStopOnError(err, resolver.options) {
return err
}
if err := expandOperation(pathItem.Delete, resolver); err != nil {
if err := expandOperation(pathItem.Delete, resolver); shouldStopOnError(err, resolver.options) {
return err
}
return nil
@ -555,8 +814,9 @@ func expandOperation(op *Operation, resolver *schemaLoader) error {
if op == nil {
return nil
}
for i, param := range op.Parameters {
if err := expandParameter(&param, resolver); err != nil {
if err := expandParameter(&param, resolver); shouldStopOnError(err, resolver.options) {
return err
}
op.Parameters[i] = param
@ -564,11 +824,11 @@ func expandOperation(op *Operation, resolver *schemaLoader) error {
if op.Responses != nil {
responses := op.Responses
if err := expandResponse(responses.Default, resolver); err != nil {
if err := expandResponse(responses.Default, resolver); shouldStopOnError(err, resolver.options) {
return err
}
for code, response := range responses.StatusCodeResponses {
if err := expandResponse(&response, resolver); err != nil {
if err := expandResponse(&response, resolver); shouldStopOnError(err, resolver.options) {
return err
}
responses.StatusCodeResponses[code] = response
@ -582,23 +842,30 @@ func expandResponse(response *Response, resolver *schemaLoader) error {
return nil
}
var parentRefs []string
if response.Ref.String() != "" {
if err := resolver.Resolve(&response.Ref, response); err != nil {
parentRefs = append(parentRefs, response.Ref.String())
if err := resolver.Resolve(&response.Ref, response); shouldStopOnError(err, resolver.options) {
return err
}
resolver.reset()
response.Ref = Ref{}
}
if response.Schema != nil {
parentRefs := []string{response.Schema.Ref.String()}
if err := resolver.Resolve(&response.Schema.Ref, &response.Schema); err != nil {
if !resolver.options.SkipSchemas && response.Schema != nil {
parentRefs = append(parentRefs, response.Schema.Ref.String())
debugLog("response ref: %s", response.Schema.Ref)
if err := resolver.Resolve(&response.Schema.Ref, &response.Schema); shouldStopOnError(err, resolver.options) {
return err
}
if s, err := expandSchema(*response.Schema, parentRefs, resolver); err != nil {
s, err := expandSchema(*response.Schema, parentRefs, resolver)
if shouldStopOnError(err, resolver.options) {
return err
} else {
}
resolver.reset()
*response.Schema = *s
}
}
return nil
}
@ -606,21 +873,28 @@ func expandParameter(parameter *Parameter, resolver *schemaLoader) error {
if parameter == nil {
return nil
}
var parentRefs []string
if parameter.Ref.String() != "" {
if err := resolver.Resolve(&parameter.Ref, parameter); err != nil {
parentRefs = append(parentRefs, parameter.Ref.String())
if err := resolver.Resolve(&parameter.Ref, parameter); shouldStopOnError(err, resolver.options) {
return err
}
resolver.reset()
parameter.Ref = Ref{}
}
if parameter.Schema != nil {
parentRefs := []string{parameter.Schema.Ref.String()}
if err := resolver.Resolve(&parameter.Schema.Ref, &parameter.Schema); err != nil {
if !resolver.options.SkipSchemas && parameter.Schema != nil {
parentRefs = append(parentRefs, parameter.Schema.Ref.String())
if err := resolver.Resolve(&parameter.Schema.Ref, &parameter.Schema); shouldStopOnError(err, resolver.options) {
return err
}
if s, err := expandSchema(*parameter.Schema, parentRefs, resolver); err != nil {
s, err := expandSchema(*parameter.Schema, parentRefs, resolver)
if shouldStopOnError(err, resolver.options) {
return err
} else {
}
resolver.reset()
*parameter.Schema = *s
}
}
return nil
}

View File

@ -16,7 +16,9 @@ package spec
import (
"encoding/json"
"strings"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
)
@ -30,6 +32,7 @@ type HeaderProps struct {
type Header struct {
CommonValidations
SimpleSchema
VendorExtensible
HeaderProps
}
@ -158,8 +161,35 @@ func (h *Header) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &h.SimpleSchema); err != nil {
return err
}
if err := json.Unmarshal(data, &h.VendorExtensible); err != nil {
return err
}
if err := json.Unmarshal(data, &h.HeaderProps); err != nil {
return err
}
return nil
}
// JSONLookup look up a value by the json property name
func (p Header) JSONLookup(token string) (interface{}, error) {
if ex, ok := p.Extensions[token]; ok {
return &ex, nil
}
r, _, err := jsonpointer.GetForToken(p.CommonValidations, token)
if err != nil && !strings.HasPrefix(err.Error(), "object has no field") {
return nil, err
}
if r != nil {
return r, nil
}
r, _, err = jsonpointer.GetForToken(p.SimpleSchema, token)
if err != nil && !strings.HasPrefix(err.Error(), "object has no field") {
return nil, err
}
if r != nil {
return r, nil
}
r, _, err = jsonpointer.GetForToken(p.HeaderProps, token)
return r, err
}

View File

@ -16,7 +16,9 @@ package spec
import (
"encoding/json"
"strings"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
)
@ -60,11 +62,12 @@ type CommonValidations struct {
// Items a limited subset of JSON-Schema's items object.
// It is used by parameter definitions that are not located in "body".
//
// For more information: http://goo.gl/8us55a#items-object-
// For more information: http://goo.gl/8us55a#items-object
type Items struct {
Refable
CommonValidations
SimpleSchema
VendorExtensible
}
// NewItems creates a new instance of items
@ -197,3 +200,20 @@ func (i Items) MarshalJSON() ([]byte, error) {
}
return swag.ConcatJSON(b3, b1, b2), nil
}
// JSONLookup look up a value by the json property name
func (p Items) JSONLookup(token string) (interface{}, error) {
if token == "$ref" {
return &p.Ref, nil
}
r, _, err := jsonpointer.GetForToken(p.CommonValidations, token)
if err != nil && !strings.HasPrefix(err.Error(), "object has no field") {
return nil, err
}
if r != nil {
return r, nil
}
r, _, err = jsonpointer.GetForToken(p.SimpleSchema, token)
return r, err
}

View File

@ -16,6 +16,7 @@ package spec
import (
"encoding/json"
"strings"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
@ -100,15 +101,16 @@ func (p Parameter) JSONLookup(token string) (interface{}, error) {
if token == "$ref" {
return &p.Ref, nil
}
r, _, err := jsonpointer.GetForToken(p.CommonValidations, token)
if err != nil {
if err != nil && !strings.HasPrefix(err.Error(), "object has no field") {
return nil, err
}
if r != nil {
return r, nil
}
r, _, err = jsonpointer.GetForToken(p.SimpleSchema, token)
if err != nil {
if err != nil && !strings.HasPrefix(err.Error(), "object has no field") {
return nil, err
}
if r != nil {

View File

@ -55,7 +55,7 @@ func (r *Ref) RemoteURI() string {
}
// IsValidURI returns true when the url the ref points to can be found
func (r *Ref) IsValidURI() bool {
func (r *Ref) IsValidURI(basepaths ...string) bool {
if r.String() == "" {
return true
}
@ -81,14 +81,18 @@ func (r *Ref) IsValidURI() bool {
// check for local file
pth := v
if r.HasURLPathOnly {
p, e := filepath.Abs(pth)
base := "."
if len(basepaths) > 0 {
base = filepath.Dir(filepath.Join(basepaths...))
}
p, e := filepath.Abs(filepath.ToSlash(filepath.Join(base, pth)))
if e != nil {
return false
}
pth = p
}
fi, err := os.Stat(pth)
fi, err := os.Stat(filepath.ToSlash(pth))
if err != nil {
return false
}
@ -116,25 +120,18 @@ func NewRef(refURI string) (Ref, error) {
return Ref{Ref: ref}, nil
}
// MustCreateRef creates a ref object but
// MustCreateRef creates a ref object but panics when refURI is invalid.
// Use the NewRef method for a version that returns an error.
func MustCreateRef(refURI string) Ref {
return Ref{Ref: jsonreference.MustCreateRef(refURI)}
}
// // NewResolvedRef creates a resolved ref
// func NewResolvedRef(refURI string, data interface{}) Ref {
// return Ref{
// Ref: jsonreference.MustCreateRef(refURI),
// Resolved: data,
// }
// }
// MarshalJSON marshals this ref into a JSON object
func (r Ref) MarshalJSON() ([]byte, error) {
str := r.String()
if str == "" {
if r.IsRoot() {
return []byte(`{"$ref":"#"}`), nil
return []byte(`{"$ref":""}`), nil
}
return []byte("{}"), nil
}

View File

@ -17,6 +17,7 @@ package spec
import (
"encoding/json"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
)
@ -34,6 +35,19 @@ type ResponseProps struct {
type Response struct {
Refable
ResponseProps
VendorExtensible
}
// JSONLookup look up a value by the json property name
func (p Response) JSONLookup(token string) (interface{}, error) {
if ex, ok := p.Extensions[token]; ok {
return &ex, nil
}
if token == "$ref" {
return &p.Ref, nil
}
r, _, err := jsonpointer.GetForToken(p.ResponseProps, token)
return r, err
}
// UnmarshalJSON hydrates this items instance with the data from JSON
@ -44,6 +58,9 @@ func (r *Response) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &r.Refable); err != nil {
return err
}
if err := json.Unmarshal(data, &r.VendorExtensible); err != nil {
return err
}
return nil
}
@ -57,7 +74,11 @@ func (r Response) MarshalJSON() ([]byte, error) {
if err != nil {
return nil, err
}
return swag.ConcatJSON(b1, b2), nil
b3, err := json.Marshal(r.VendorExtensible)
if err != nil {
return nil, err
}
return swag.ConcatJSON(b1, b2, b3), nil
}
// NewResponse creates a new response instance

View File

@ -51,7 +51,7 @@ func (r Responses) JSONLookup(token string) (interface{}, error) {
}
if i, err := strconv.Atoi(token); err == nil {
if scr, ok := r.StatusCodeResponses[i]; ok {
return &scr, nil
return scr, nil
}
}
return nil, fmt.Errorf("object has no field %q", token)

View File

@ -201,8 +201,8 @@ func (r *SchemaURL) UnmarshalJSON(data []byte) error {
type SchemaProps struct {
ID string `json:"id,omitempty"`
Ref Ref `json:"-,omitempty"`
Schema SchemaURL `json:"-,omitempty"`
Ref Ref `json:"-"`
Schema SchemaURL `json:"-"`
Description string `json:"description,omitempty"`
Type StringOrArray `json:"type,omitempty"`
Format string `json:"format,omitempty"`
@ -269,7 +269,7 @@ func (s Schema) JSONLookup(token string) (interface{}, error) {
}
r, _, err := jsonpointer.GetForToken(s.SchemaProps, token)
if r != nil || err != nil {
if r != nil || (err != nil && !strings.HasPrefix(err.Error(), "object has no field")) {
return r, err
}
r, _, err = jsonpointer.GetForToken(s.SwaggerSchemaProps, token)

View File

@ -16,6 +16,8 @@ package spec
import "encoding/json"
//go:generate curl -L --progress -o ./schemas/v2/schema.json http://swagger.io/v2/schema.json
//go:generate curl -L --progress -o ./schemas/jsonschema-draft-04.json http://json-schema.org/draft-04/schema
//go:generate go-bindata -pkg=spec -prefix=./schemas -ignore=.*\.md ./schemas/...
//go:generate perl -pi -e s,Json,JSON,g bindata.go
@ -27,9 +29,14 @@ const (
)
var (
jsonSchema *Schema
swaggerSchema *Schema
)
func init() {
jsonSchema = MustLoadJSONSchemaDraft04()
swaggerSchema = MustLoadSwagger20Schema()
)
}
// MustLoadJSONSchemaDraft04 panics when Swagger20Schema returns an error
func MustLoadJSONSchemaDraft04() *Schema {

View File

@ -77,7 +77,7 @@ type SwaggerProps struct {
Host string `json:"host,omitempty"`
BasePath string `json:"basePath,omitempty"` // must start with a leading "/"
Paths *Paths `json:"paths"` // required
Definitions Definitions `json:"definitions"`
Definitions Definitions `json:"definitions,omitempty"`
Parameters map[string]Parameter `json:"parameters,omitempty"`
Responses map[string]Response `json:"responses,omitempty"`
SecurityDefinitions SecurityDefinitions `json:"securityDefinitions,omitempty"`
@ -156,7 +156,7 @@ func (s SchemaOrStringArray) MarshalJSON() ([]byte, error) {
if s.Schema != nil {
return json.Marshal(s.Schema)
}
return nil, nil
return []byte("null"), nil
}
// UnmarshalJSON converts this schema object or array from a JSON structure

View File

@ -1 +0,0 @@
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.darMHuSYnLhsknrnqjdXLGcyEJ5kM13yQbLGi2UWcKXpddHvPT3dMCnP5y7e27c76R2HFnvr56BqDMI-x0zyuQtjYKzSFUGjOcEhOH3OL1Hxu-Cm2z2443BS8asXNA3sEveAGQvG68jffm7CvtEtMo57wBpggI7UHbfIdLMK47s1EDpC4xanjiS1BJe5NC_Ikf0jfa6vf18oggbjxuoqSEvSNVdNRyZwG_npFaZFJzvdtehTG7GqunWjGiqBb81qNcEdzSdIZW7A_Esv4U-nOL5gGr55E9jKhv3bX4Z9ygGcSrJ3NCgR_3zRhYKkPEAOXIqQKfL6-h82BY--cHq9uw.NHL3X-1tjb8a8zF7.eRmLvOG32e7260K8rkI-HmUGG5Gb6Hu-obKKxBqHd-vVzsKnwTVJavLWktPqlXGMsnDt7MimSysNqsWemMUEviW2p3godnvjOOXTDb-RAtQ-39rvxnZ2bN8qwUVFrdiKTZD06l60yTeLW7L1psyLj50NxklFObhkpUcK5uukxLXT1SzGM9aY6_3dzW4HU9pZGQrIH1pj1UzvWIjz7iIzE1a37DHBN-FiYSASsw01v1SSIFr34gwlGcqzGfJBonffVrM4ordm3IiVm50Zvr25DrmYTKrQpJRB-KOvYxBNYDzjCaanHDyWGUGN44FUx38azHHEVBTaiOM7xwPeyCc-xTTv8WXGnL1xrhL3M_jNuwnbAjzL9X_li7KUSeYajwhGihdMZaHLYaqxh3NNnbPfYhR6sBxu8vaT1Sc4eE84QC4dV4OaAglPvrPdWL-DC7OYQyoPU8u9ggwUQHpFUzJyD549T_Tlgn-2Cw7kTe41VonH9HkoXGANDGtQCGTqTIEeFQJ3MDDucf5VteFP8_SJPfyJYxpStFt5U1AuULV9sXmpGQL_-GGFXowd0X0bHxFeo_eu1vm-oTqQQNbKRnyt5V3n4U9jhOUGnnIBy3JOG3DA2YhVJsHdlLZ9vaDpFYcxts4.SqYfES30FqVSufGbPZ6YXA

View File

@ -1,32 +0,0 @@
clone:
path: github.com/go-openapi/swag
matrix:
GO_VERSION:
- "1.6"
build:
integration:
image: golang:$$GO_VERSION
pull: true
commands:
- go get -u github.com/stretchr/testify
- go get -u github.com/mailru/easyjson
- go test -race
- go test -v -cover -coverprofile=coverage.out -covermode=count ./...
notify:
slack:
channel: bots
webhook_url: $$SLACK_URL
username: drone
publish:
coverage:
server: https://coverage.vmware.run
token: $$GITHUB_TOKEN
# threshold: 70
# must_increase: true
when:
matrix:
GO_VERSION: "1.6"

26
vendor/github.com/go-openapi/swag/.editorconfig generated vendored Normal file
View File

@ -0,0 +1,26 @@
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
# Set default charset
[*.{js,py,go,scala,rb,java,html,css,less,sass,md}]
charset = utf-8
# Tab indentation (no size specified)
[*.go]
indent_style = tab
[*.md]
trim_trailing_whitespace = false
# Matches the exact files either package.json or .travis.yml
[{package.json,.travis.yml}]
indent_style = space
indent_size = 2

View File

@ -1,13 +0,0 @@
approve_by_comment: true
approve_regex: '^(:shipit:|:\+1:|\+1|LGTM|lgtm|Approved)'
reject_regex: ^[Rr]ejected
reset_on_push: false
reviewers:
members:
- casualjim
- chancez
- frapposelli
- vburenin
- pytlesk4
name: pullapprove
required: 1

14
vendor/github.com/go-openapi/swag/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,14 @@
language: go
go:
- 1.8
install:
- go get -u github.com/stretchr/testify
- go get -u github.com/mailru/easyjson
- go get -u gopkg.in/yaml.v2
script:
- go test -v -race -cover -coverprofile=coverage.txt -covermode=atomic ./...
after_success:
- bash <(curl -s https://codecov.io/bash)
notifications:
slack:
secure: QUWvCkBBK09GF7YtEvHHVt70JOkdlNBG0nIKu/5qc4/nW5HP8I2w0SEf/XR2je0eED1Qe3L/AfMCWwrEj+IUZc3l4v+ju8X8R3Lomhme0Eb0jd1MTMCuPcBT47YCj0M7RON7vXtbFfm1hFJ/jLe5+9FXz0hpXsR24PJc5ZIi/ogNwkaPqG4BmndzecpSh0vc2FJPZUD9LT0I09REY/vXR0oQAalLkW0asGD5taHZTUZq/kBpsNxaAFrLM23i4mUcf33M5fjLpvx5LRICrX/57XpBrDh2TooBU6Qj3CgoY0uPRYUmSNxbVx1czNzl2JtEpb5yjoxfVPQeg0BvQM00G8LJINISR+ohrjhkZmAqchDupAX+yFrxTtORa78CtnIL6z/aTNlgwwVD8kvL/1pFA/JWYmKDmz93mV/+6wubGzNSQCstzjkFA4/iZEKewKUoRIAi/fxyscP6L/rCpmY/4llZZvrnyTqVbt6URWpopUpH4rwYqreXAtJxJsfBJIeSmUIiDIOMGkCTvyTEW3fWGmGoqWtSHLoaWDyAIGb7azb+KvfpWtEcoPFWfSWU+LGee0A/YsUhBl7ADB9A0CJEuR8q4BPpKpfLwPKSiKSAXL7zDkyjExyhtgqbSl2jS+rKIHOZNL8JkCcTP2MKMVd563C5rC5FMKqu3S9m2b6380E=

View File

@ -10,11 +10,13 @@ go_library(
"net.go",
"path.go",
"util.go",
"yaml.go",
],
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/mailru/easyjson/jlexer:go_default_library",
"//vendor/github.com/mailru/easyjson/jwriter:go_default_library",
"//vendor/gopkg.in/yaml.v2:go_default_library",
],
)

View File

@ -1,4 +1,4 @@
# Swag [![Build Status](https://ci.vmware.run/api/badges/go-openapi/swag/status.svg)](https://ci.vmware.run/go-openapi/swag) [![Coverage](https://coverage.vmware.run/badges/go-openapi/swag/coverage.svg)](https://coverage.vmware.run/go-openapi/swag) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
# Swag [![Build Status](https://travis-ci.org/go-openapi/swag.svg?branch=master)](https://travis-ci.org/go-openapi/swag) [![codecov](https://codecov.io/gh/go-openapi/swag/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/swag) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/swag/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/swag?status.svg)](http://godoc.org/github.com/go-openapi/swag)

View File

@ -159,7 +159,7 @@ func FormatInt16(value int16) string {
// FormatInt32 turns an int32 into a string
func FormatInt32(value int32) string {
return strconv.FormatInt(int64(value), 10)
return strconv.Itoa(int(value))
}
// FormatInt64 turns an int64 into a string

View File

@ -17,6 +17,7 @@ package swag
import (
"bytes"
"encoding/json"
"log"
"reflect"
"strings"
"sync"
@ -110,28 +111,40 @@ func ConcatJSON(blobs ...[]byte) []byte {
if len(b) < 3 { // yep empty but also the last one, so closing this thing
if i == last && a > 0 {
buf.WriteByte(closing)
if err := buf.WriteByte(closing); err != nil {
log.Println(err)
}
}
continue
}
idx = 0
if a > 0 { // we need to join with a comma for everything beyond the first non-empty item
buf.WriteByte(comma)
if err := buf.WriteByte(comma); err != nil {
log.Println(err)
}
idx = 1 // this is not the first or the last so we want to drop the leading bracket
}
if i != last { // not the last one, strip brackets
buf.Write(b[idx : len(b)-1])
if _, err := buf.Write(b[idx : len(b)-1]); err != nil {
log.Println(err)
}
} else { // last one, strip only the leading bracket
buf.Write(b[idx:])
if _, err := buf.Write(b[idx:]); err != nil {
log.Println(err)
}
}
a++
}
// somehow it ended up being empty, so provide a default value
if buf.Len() == 0 {
buf.WriteByte(opening)
buf.WriteByte(closing)
if err := buf.WriteByte(opening); err != nil {
log.Println(err)
}
if err := buf.WriteByte(closing); err != nil {
log.Println(err)
}
}
return buf.Bytes()
}
@ -139,15 +152,23 @@ func ConcatJSON(blobs ...[]byte) []byte {
// ToDynamicJSON turns an object into a properly JSON typed structure
func ToDynamicJSON(data interface{}) interface{} {
// TODO: convert straight to a json typed map (mergo + iterate?)
b, _ := json.Marshal(data)
b, err := json.Marshal(data)
if err != nil {
log.Println(err)
}
var res interface{}
json.Unmarshal(b, &res)
if err := json.Unmarshal(b, &res); err != nil {
log.Println(err)
}
return res
}
// FromDynamicJSON turns an object into a properly JSON typed structure
func FromDynamicJSON(data, target interface{}) error {
b, _ := json.Marshal(data)
b, err := json.Marshal(data)
if err != nil {
log.Println(err)
}
return json.Unmarshal(b, target)
}
@ -216,6 +237,8 @@ func newNameIndex(tpe reflect.Type) nameIndex {
// GetJSONNames gets all the json property names for a type
func (n *NameProvider) GetJSONNames(subject interface{}) []string {
n.lock.Lock()
defer n.lock.Unlock()
tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
names, ok := n.index[tpe]
if !ok {
@ -237,6 +260,8 @@ func (n *NameProvider) GetJSONName(subject interface{}, name string) (string, bo
// GetJSONNameForType gets the json name for a go property name on a given type
func (n *NameProvider) GetJSONNameForType(tpe reflect.Type, name string) (string, bool) {
n.lock.Lock()
defer n.lock.Unlock()
names, ok := n.index[tpe]
if !ok {
names = n.makeNameIndex(tpe)
@ -246,8 +271,6 @@ func (n *NameProvider) GetJSONNameForType(tpe reflect.Type, name string) (string
}
func (n *NameProvider) makeNameIndex(tpe reflect.Type) nameIndex {
n.lock.Lock()
defer n.lock.Unlock()
names := newNameIndex(tpe)
n.index[tpe] = names
return names
@ -261,6 +284,8 @@ func (n *NameProvider) GetGoName(subject interface{}, name string) (string, bool
// GetGoNameForType gets the go name for a given type for a json property name
func (n *NameProvider) GetGoNameForType(tpe reflect.Type, name string) (string, bool) {
n.lock.Lock()
defer n.lock.Unlock()
names, ok := n.index[tpe]
if !ok {
names = n.makeNameIndex(tpe)

View File

@ -17,13 +17,25 @@ package swag
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"path/filepath"
"strings"
"time"
)
// LoadHTTPTimeout the default timeout for load requests
var LoadHTTPTimeout = 30 * time.Second
// 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)(path)
return LoadStrategy(path, ioutil.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)
}
// LoadStrategy returns a loader function for a given path or uri
@ -31,19 +43,32 @@ func LoadStrategy(path string, local, remote func(string) ([]byte, error)) func(
if strings.HasPrefix(path, "http") {
return remote
}
return local
return func(pth string) ([]byte, error) { return local(filepath.FromSlash(pth)) }
}
func loadHTTPBytes(path string) ([]byte, error) {
resp, err := http.Get(path)
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)
if err != nil {
return nil, err
}
resp, err := client.Do(req)
defer func() {
if resp != nil {
if e := resp.Body.Close(); e != nil {
log.Println(e)
}
}
}()
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("could not access document at %q [%s] ", path, resp.Status)
}
return ioutil.ReadAll(resp.Body)
}
}

View File

@ -47,6 +47,9 @@ func FindInGoSearchPath(pkg string) string {
// FullGoSearchPath gets the search paths for finding packages
func FullGoSearchPath() string {
allPaths := os.Getenv(GOPATHKey)
if allPaths == "" {
allPaths = filepath.Join(os.Getenv("HOME"), "go")
}
if allPaths != "" {
allPaths = strings.Join([]string{allPaths, runtime.GOROOT()}, ":")
} else {

View File

@ -20,10 +20,12 @@ import (
"regexp"
"sort"
"strings"
"unicode"
)
// Taken from https://github.com/golang/lint/blob/1fab560e16097e5b69afb66eb93aab843ef77845/lint.go#L663-L698
// Taken from https://github.com/golang/lint/blob/3390df4df2787994aea98de825b964ac7944b817/lint.go#L732-L769
var commonInitialisms = map[string]bool{
"ACL": true,
"API": true,
"ASCII": true,
"CPU": true,
@ -44,19 +46,21 @@ var commonInitialisms = map[string]bool{
"RPC": true,
"SLA": true,
"SMTP": true,
"SQL": true,
"SSH": true,
"TCP": true,
"TLS": true,
"TTL": true,
"UDP": true,
"UUID": true,
"UID": true,
"UI": true,
"UID": true,
"UUID": true,
"URI": true,
"URL": true,
"UTF8": true,
"VM": true,
"XML": true,
"XMPP": true,
"XSRF": true,
"XSS": true,
}
@ -246,6 +250,9 @@ func ToJSONName(name string) string {
// ToVarName camelcases a name which can be underscored or pascal cased
func ToVarName(name string) string {
res := ToGoName(name)
if _, ok := commonInitialisms[res]; ok {
return lower(res)
}
if len(res) <= 1 {
return lower(res)
}
@ -263,7 +270,18 @@ func ToGoName(name string) string {
}
out = append(out, uw)
}
return strings.Join(out, "")
result := strings.Join(out, "")
if len(result) > 0 {
ud := upper(result[:1])
ru := []rune(ud)
if unicode.IsUpper(ru[0]) {
result = ud + result[1:]
} else {
result = "X" + ud + result[1:]
}
}
return result
}
// ContainsStringsCI searches a slice of strings for a case-insensitive match

215
vendor/github.com/go-openapi/swag/yaml.go generated vendored Normal file
View File

@ -0,0 +1,215 @@
// Copyright 2015 go-swagger maintainers
//
// 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 swag
import (
"encoding/json"
"fmt"
"path/filepath"
"strconv"
"github.com/mailru/easyjson/jlexer"
"github.com/mailru/easyjson/jwriter"
yaml "gopkg.in/yaml.v2"
)
// YAMLMatcher matches yaml
func YAMLMatcher(path string) bool {
ext := filepath.Ext(path)
return ext == ".yaml" || ext == ".yml"
}
// YAMLToJSON converts YAML unmarshaled data into json compatible data
func YAMLToJSON(data interface{}) (json.RawMessage, error) {
jm, err := transformData(data)
if err != nil {
return nil, err
}
b, err := WriteJSON(jm)
return json.RawMessage(b), err
}
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 {
return nil, err
}
var document yaml.MapSlice // preserve order that is present in the document
if err := yaml.Unmarshal(data, &document); err != nil {
return nil, err
}
return document, nil
}
type JSONMapSlice []JSONMapItem
func (s JSONMapSlice) MarshalJSON() ([]byte, error) {
w := &jwriter.Writer{Flags: jwriter.NilMapAsEmpty | jwriter.NilSliceAsEmpty}
s.MarshalEasyJSON(w)
return w.BuildBytes()
}
func (s JSONMapSlice) MarshalEasyJSON(w *jwriter.Writer) {
w.RawByte('{')
ln := len(s)
last := ln - 1
for i := 0; i < ln; i++ {
s[i].MarshalEasyJSON(w)
if i != last { // last item
w.RawByte(',')
}
}
w.RawByte('}')
}
func (s *JSONMapSlice) UnmarshalJSON(data []byte) error {
l := jlexer.Lexer{Data: data}
s.UnmarshalEasyJSON(&l)
return l.Error()
}
func (s *JSONMapSlice) UnmarshalEasyJSON(in *jlexer.Lexer) {
if in.IsNull() {
in.Skip()
return
}
var result JSONMapSlice
in.Delim('{')
for !in.IsDelim('}') {
var mi JSONMapItem
mi.UnmarshalEasyJSON(in)
result = append(result, mi)
}
*s = result
}
type JSONMapItem struct {
Key string
Value interface{}
}
func (s JSONMapItem) MarshalJSON() ([]byte, error) {
w := &jwriter.Writer{Flags: jwriter.NilMapAsEmpty | jwriter.NilSliceAsEmpty}
s.MarshalEasyJSON(w)
return w.BuildBytes()
}
func (s JSONMapItem) MarshalEasyJSON(w *jwriter.Writer) {
w.String(s.Key)
w.RawByte(':')
w.Raw(WriteJSON(s.Value))
}
func (s *JSONMapItem) UnmarshalEasyJSON(in *jlexer.Lexer) {
key := in.UnsafeString()
in.WantColon()
value := in.Interface()
in.WantComma()
s.Key = key
s.Value = value
}
func (s *JSONMapItem) UnmarshalJSON(data []byte) error {
l := jlexer.Lexer{Data: data}
s.UnmarshalEasyJSON(&l)
return l.Error()
}
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
switch k := mi.Key.(type) {
case string:
nmi.Key = k
case int:
nmi.Key = strconv.Itoa(k)
default:
return nil, fmt.Errorf("types don't match expect map key string or int got: %T", mi.Key)
}
v, err := transformData(mi.Value)
if err != nil {
return nil, err
}
nmi.Value = v
o[i] = nmi
}
return o, nil
case map[interface{}]interface{}:
o := make(JSONMapSlice, 0, len(in))
for ke, va := range in {
var nmi JSONMapItem
switch k := ke.(type) {
case string:
nmi.Key = k
case int:
nmi.Key = strconv.Itoa(k)
default:
return nil, fmt.Errorf("types don't match expect map key string or int got: %T", ke)
}
v, err := transformData(va)
if err != nil {
return nil, err
}
nmi.Value = v
o = append(o, nmi)
}
return o, nil
case []interface{}:
len1 := len(in)
o := make([]interface{}, len1)
for i := 0; i < len1; i++ {
o[i], err = transformData(in[i])
if err != nil {
return nil, err
}
}
return o, nil
}
return input, nil
}
// YAMLDoc loads a yaml document from either http or a file and converts it to json
func YAMLDoc(path string) (json.RawMessage, error) {
yamlDoc, err := YAMLData(path)
if err != nil {
return nil, err
}
data, err := YAMLToJSON(yamlDoc)
if err != nil {
return nil, err
}
return json.RawMessage(data), nil
}
// YAMLData loads a yaml document from either http or a file
func YAMLData(path string) (interface{}, error) {
data, err := LoadFromFileOrHTTP(path)
if err != nil {
return nil, err
}
return BytesToYAMLDoc(data)
}

View File

@ -179,18 +179,25 @@ func (b *Buffer) DumpTo(w io.Writer) (written int, err error) {
}
// BuildBytes creates a single byte slice with all the contents of the buffer. Data is
// copied if it does not fit in a single chunk.
func (b *Buffer) BuildBytes() []byte {
// copied if it does not fit in a single chunk. You can optionally provide one byte
// slice as argument that it will try to reuse.
func (b *Buffer) BuildBytes(reuse ...[]byte) []byte {
if len(b.bufs) == 0 {
ret := b.Buf
b.toPool = nil
b.Buf = nil
return ret
}
ret := make([]byte, 0, b.Size())
var ret []byte
size := b.Size()
// If we got a buffer as argument and it is big enought, reuse it.
if len(reuse) == 1 && cap(reuse[0]) >= size {
ret = reuse[0][:0]
} else {
ret = make([]byte, 0, size)
}
for _, buf := range b.bufs {
ret = append(ret, buf...)
putBuf(buf)
@ -205,3 +212,59 @@ func (b *Buffer) BuildBytes() []byte {
return ret
}
type readCloser struct {
offset int
bufs [][]byte
}
func (r *readCloser) Read(p []byte) (n int, err error) {
for _, buf := range r.bufs {
// Copy as much as we can.
x := copy(p[n:], buf[r.offset:])
n += x // Increment how much we filled.
// Did we empty the whole buffer?
if r.offset+x == len(buf) {
// On to the next buffer.
r.offset = 0
r.bufs = r.bufs[1:]
// We can release this buffer.
putBuf(buf)
} else {
r.offset += x
}
if n == len(p) {
break
}
}
// No buffers left or nothing read?
if len(r.bufs) == 0 {
err = io.EOF
}
return
}
func (r *readCloser) Close() error {
// Release all remaining buffers.
for _, buf := range r.bufs {
putBuf(buf)
}
// In case Close gets called multiple times.
r.bufs = nil
return nil
}
// ReadCloser creates an io.ReadCloser with all the contents of the buffer.
func (b *Buffer) ReadCloser() io.ReadCloser {
ret := &readCloser{0, append(b.bufs, b.Buf)}
b.bufs = nil
b.toPool = nil
b.Buf = nil
return ret
}

View File

@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"bytestostr.go",
"error.go",
"lexer.go",
],

24
vendor/github.com/mailru/easyjson/jlexer/bytestostr.go generated vendored Normal file
View File

@ -0,0 +1,24 @@
// This file will only be included to the build if neither
// easyjson_nounsafe nor appengine build tag is set. See README notes
// for more details.
//+build !easyjson_nounsafe
//+build !appengine
package jlexer
import (
"reflect"
"unsafe"
)
// bytesToStr creates a string pointing at the slice to avoid copying.
//
// Warning: the string returned by the function should be used with care, as the whole input data
// chunk may be either blocked from being freed by GC because of a single string or the buffer.Data
// may be garbage-collected even when the string exists.
func bytesToStr(data []byte) string {
h := (*reflect.SliceHeader)(unsafe.Pointer(&data))
shdr := reflect.StringHeader{Data: h.Data, Len: h.Len}
return *(*string)(unsafe.Pointer(&shdr))
}

View File

@ -0,0 +1,13 @@
// This file is included to the build if any of the buildtags below
// are defined. Refer to README notes for more details.
//+build easyjson_nounsafe appengine
package jlexer
// bytesToStr creates a string normally from []byte
//
// Note that this method is roughly 1.5x slower than using the 'unsafe' method.
func bytesToStr(data []byte) string {
return string(data)
}

View File

@ -5,12 +5,14 @@
package jlexer
import (
"encoding/base64"
"errors"
"fmt"
"io"
"reflect"
"strconv"
"unicode"
"unicode/utf16"
"unicode/utf8"
"unsafe"
)
// tokenKind determines type of a token.
@ -45,11 +47,13 @@ type Lexer struct {
firstElement bool // Whether current element is the first in array or an object.
wantSep byte // A comma or a colon character, which need to occur before a token.
err error // Error encountered during lexing, if any.
UseMultipleErrors bool // If we want to use multiple errors.
fatalError error // Fatal error occurred during lexing. It is usually a syntax error.
multipleErrors []*LexerError // Semantic errors occurred during lexing. Marshalling will be continued after finding this errors.
}
// fetchToken scans the input for the next token.
func (r *Lexer) fetchToken() {
// FetchToken scans the input for the next token.
func (r *Lexer) FetchToken() {
r.token.kind = tokenUndef
r.start = r.pos
@ -147,7 +151,7 @@ func (r *Lexer) fetchToken() {
return
}
}
r.err = io.EOF
r.fatalError = io.EOF
return
}
@ -199,17 +203,6 @@ func (r *Lexer) fetchFalse() {
}
}
// bytesToStr creates a string pointing at the slice to avoid copying.
//
// Warning: the string returned by the function should be used with care, as the whole input data
// chunk may be either blocked from being freed by GC because of a single string or the buffer.Data
// may be garbage-collected even when the string exists.
func bytesToStr(data []byte) string {
h := (*reflect.SliceHeader)(unsafe.Pointer(&data))
shdr := reflect.StringHeader{h.Data, h.Len}
return *(*string)(unsafe.Pointer(&shdr))
}
// fetchNumber scans a number literal token.
func (r *Lexer) fetchNumber() {
hasE := false
@ -265,6 +258,33 @@ func findStringLen(data []byte) (hasEscapes bool, length int) {
return false, len(data)
}
// getu4 decodes \uXXXX from the beginning of s, returning the hex value,
// or it returns -1.
func getu4(s []byte) rune {
if len(s) < 6 || s[0] != '\\' || s[1] != 'u' {
return -1
}
var val rune
for i := 2; i < len(s) && i < 6; i++ {
var v byte
c := s[i]
switch c {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
v = c - '0'
case 'a', 'b', 'c', 'd', 'e', 'f':
v = c - 'a' + 10
case 'A', 'B', 'C', 'D', 'E', 'F':
v = c - 'A' + 10
default:
return -1
}
val <<= 4
val |= rune(v)
}
return val
}
// processEscape processes a single escape sequence and returns number of bytes processed.
func (r *Lexer) processEscape(data []byte) (int, error) {
if len(data) < 2 {
@ -292,39 +312,28 @@ func (r *Lexer) processEscape(data []byte) (int, error) {
r.token.byteValue = append(r.token.byteValue, '\t')
return 2, nil
case 'u':
default:
return 0, fmt.Errorf("syntax error")
rr := getu4(data)
if rr < 0 {
return 0, errors.New("syntax error")
}
var val rune
for i := 2; i < len(data) && i < 6; i++ {
var v byte
c = data[i]
switch c {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
v = c - '0'
case 'a', 'b', 'c', 'd', 'e', 'f':
v = c - 'a' + 10
case 'A', 'B', 'C', 'D', 'E', 'F':
v = c - 'A' + 10
default:
return 0, fmt.Errorf("syntax error")
read := 6
if utf16.IsSurrogate(rr) {
rr1 := getu4(data[read:])
if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar {
read += 6
rr = dec
} else {
rr = unicode.ReplacementChar
}
val <<= 4
val |= rune(v)
}
l := utf8.RuneLen(val)
if l == -1 {
return 0, fmt.Errorf("invalid unicode escape")
}
var d [4]byte
utf8.EncodeRune(d[:], val)
r.token.byteValue = append(r.token.byteValue, d[:l]...)
return 6, nil
s := utf8.EncodeRune(d[:], rr)
r.token.byteValue = append(r.token.byteValue, d[:s]...)
return read, nil
}
return 0, errors.New("syntax error")
}
// fetchString scans a string literal token.
@ -368,11 +377,11 @@ func (r *Lexer) fetchString() {
// scanToken scans the next token if no token is currently available in the lexer.
func (r *Lexer) scanToken() {
if r.token.kind != tokenUndef || r.err != nil {
if r.token.kind != tokenUndef || r.fatalError != nil {
return
}
r.fetchToken()
r.FetchToken()
}
// consume resets the current token to allow scanning the next one.
@ -383,20 +392,20 @@ func (r *Lexer) consume() {
// Ok returns true if no error (including io.EOF) was encountered during scanning.
func (r *Lexer) Ok() bool {
return r.err == nil
return r.fatalError == nil
}
const maxErrorContextLen = 13
func (r *Lexer) errParse(what string) {
if r.err == nil {
if r.fatalError == nil {
var str string
if len(r.Data)-r.pos <= maxErrorContextLen {
str = string(r.Data)
} else {
str = string(r.Data[r.pos:r.pos+maxErrorContextLen-3]) + "..."
}
r.err = &LexerError{
r.fatalError = &LexerError{
Reason: what,
Offset: r.pos,
Data: str,
@ -409,36 +418,64 @@ func (r *Lexer) errSyntax() {
}
func (r *Lexer) errInvalidToken(expected string) {
if r.err == nil {
if r.fatalError != nil {
return
}
if r.UseMultipleErrors {
r.pos = r.start
r.consume()
r.SkipRecursive()
switch expected {
case "[":
r.token.delimValue = ']'
r.token.kind = tokenDelim
case "{":
r.token.delimValue = '}'
r.token.kind = tokenDelim
}
r.addNonfatalError(&LexerError{
Reason: fmt.Sprintf("expected %s", expected),
Offset: r.start,
Data: string(r.Data[r.start:r.pos]),
})
return
}
var str string
if len(r.token.byteValue) <= maxErrorContextLen {
str = string(r.token.byteValue)
} else {
str = string(r.token.byteValue[:maxErrorContextLen-3]) + "..."
}
r.err = &LexerError{
r.fatalError = &LexerError{
Reason: fmt.Sprintf("expected %s", expected),
Offset: r.pos,
Data: str,
}
}
}
func (r *Lexer) GetPos() int {
return r.pos
}
// Delim consumes a token and verifies that it is the given delimiter.
func (r *Lexer) Delim(c byte) {
if r.token.kind == tokenUndef && r.Ok() {
r.fetchToken()
r.FetchToken()
}
if !r.Ok() || r.token.delimValue != c {
r.consume() // errInvalidToken can change token if UseMultipleErrors is enabled.
r.errInvalidToken(string([]byte{c}))
}
} else {
r.consume()
}
}
// IsDelim returns true if there was no scanning error and next token is the given delimiter.
func (r *Lexer) IsDelim(c byte) bool {
if r.token.kind == tokenUndef && r.Ok() {
r.fetchToken()
r.FetchToken()
}
return !r.Ok() || r.token.delimValue == c
}
@ -446,7 +483,7 @@ func (r *Lexer) IsDelim(c byte) bool {
// Null verifies that the next token is null and consumes it.
func (r *Lexer) Null() {
if r.token.kind == tokenUndef && r.Ok() {
r.fetchToken()
r.FetchToken()
}
if !r.Ok() || r.token.kind != tokenNull {
r.errInvalidToken("null")
@ -457,7 +494,7 @@ func (r *Lexer) Null() {
// IsNull returns true if the next token is a null keyword.
func (r *Lexer) IsNull() bool {
if r.token.kind == tokenUndef && r.Ok() {
r.fetchToken()
r.FetchToken()
}
return r.Ok() && r.token.kind == tokenNull
}
@ -465,7 +502,7 @@ func (r *Lexer) IsNull() bool {
// Skip skips a single token.
func (r *Lexer) Skip() {
if r.token.kind == tokenUndef && r.Ok() {
r.fetchToken()
r.FetchToken()
}
r.consume()
}
@ -476,7 +513,6 @@ func (r *Lexer) Skip() {
// Note: no syntax validation is performed on the skipped data.
func (r *Lexer) SkipRecursive() {
r.scanToken()
var start, end byte
if r.token.delimValue == '{' {
@ -505,7 +541,7 @@ func (r *Lexer) SkipRecursive() {
return
}
case c == '\\' && inQuotes:
wasEscape = true
wasEscape = !wasEscape
continue
case c == '"' && inQuotes:
inQuotes = wasEscape
@ -515,7 +551,11 @@ func (r *Lexer) SkipRecursive() {
wasEscape = false
}
r.pos = len(r.Data)
r.err = io.EOF
r.fatalError = &LexerError{
Reason: "EOF reached while skipping array/object or token",
Offset: r.pos,
Data: string(r.Data[r.pos:]),
}
}
// Raw fetches the next item recursively as a data slice
@ -527,48 +567,107 @@ func (r *Lexer) Raw() []byte {
return r.Data[r.start:r.pos]
}
// IsStart returns whether the lexer is positioned at the start
// of an input string.
func (r *Lexer) IsStart() bool {
return r.pos == 0
}
// Consumed reads all remaining bytes from the input, publishing an error if
// there is anything but whitespace remaining.
func (r *Lexer) Consumed() {
if r.pos > len(r.Data) || !r.Ok() {
return
}
for _, c := range r.Data[r.pos:] {
if c != ' ' && c != '\t' && c != '\r' && c != '\n' {
r.AddError(&LexerError{
Reason: "invalid character '" + string(c) + "' after top-level value",
Offset: r.pos,
Data: string(r.Data[r.pos:]),
})
return
}
r.pos++
r.start++
}
}
func (r *Lexer) unsafeString() (string, []byte) {
if r.token.kind == tokenUndef && r.Ok() {
r.FetchToken()
}
if !r.Ok() || r.token.kind != tokenString {
r.errInvalidToken("string")
return "", nil
}
bytes := r.token.byteValue
ret := bytesToStr(r.token.byteValue)
r.consume()
return ret, bytes
}
// UnsafeString returns the string value if the token is a string literal.
//
// Warning: returned string may point to the input buffer, so the string should not outlive
// the input buffer. Intended pattern of usage is as an argument to a switch statement.
func (r *Lexer) UnsafeString() string {
if r.token.kind == tokenUndef && r.Ok() {
r.fetchToken()
}
if !r.Ok() || r.token.kind != tokenString {
r.errInvalidToken("string")
return ""
}
ret, _ := r.unsafeString()
return ret
}
ret := bytesToStr(r.token.byteValue)
r.consume()
// UnsafeBytes returns the byte slice if the token is a string literal.
func (r *Lexer) UnsafeBytes() []byte {
_, ret := r.unsafeString()
return ret
}
// String reads a string literal.
func (r *Lexer) String() string {
if r.token.kind == tokenUndef && r.Ok() {
r.fetchToken()
r.FetchToken()
}
if !r.Ok() || r.token.kind != tokenString {
r.errInvalidToken("string")
return ""
}
ret := string(r.token.byteValue)
r.consume()
return ret
}
// Bytes reads a string literal and base64 decodes it into a byte slice.
func (r *Lexer) Bytes() []byte {
if r.token.kind == tokenUndef && r.Ok() {
r.FetchToken()
}
if !r.Ok() || r.token.kind != tokenString {
r.errInvalidToken("string")
return nil
}
ret := make([]byte, base64.StdEncoding.DecodedLen(len(r.token.byteValue)))
len, err := base64.StdEncoding.Decode(ret, r.token.byteValue)
if err != nil {
r.fatalError = &LexerError{
Reason: err.Error(),
}
return nil
}
r.consume()
return ret[:len]
}
// Bool reads a true or false boolean keyword.
func (r *Lexer) Bool() bool {
if r.token.kind == tokenUndef && r.Ok() {
r.fetchToken()
r.FetchToken()
}
if !r.Ok() || r.token.kind != tokenBool {
r.errInvalidToken("bool")
return false
}
ret := r.token.boolValue
r.consume()
@ -577,12 +676,11 @@ func (r *Lexer) Bool() bool {
func (r *Lexer) number() string {
if r.token.kind == tokenUndef && r.Ok() {
r.fetchToken()
r.FetchToken()
}
if !r.Ok() || r.token.kind != tokenNumber {
r.errInvalidToken("number")
return ""
}
ret := bytesToStr(r.token.byteValue)
r.consume()
@ -597,9 +695,11 @@ func (r *Lexer) Uint8() uint8 {
n, err := strconv.ParseUint(s, 10, 8)
if err != nil {
r.err = &LexerError{
r.addNonfatalError(&LexerError{
Offset: r.start,
Reason: err.Error(),
}
Data: s,
})
}
return uint8(n)
}
@ -612,9 +712,11 @@ func (r *Lexer) Uint16() uint16 {
n, err := strconv.ParseUint(s, 10, 16)
if err != nil {
r.err = &LexerError{
r.addNonfatalError(&LexerError{
Offset: r.start,
Reason: err.Error(),
}
Data: s,
})
}
return uint16(n)
}
@ -627,9 +729,11 @@ func (r *Lexer) Uint32() uint32 {
n, err := strconv.ParseUint(s, 10, 32)
if err != nil {
r.err = &LexerError{
r.addNonfatalError(&LexerError{
Offset: r.start,
Reason: err.Error(),
}
Data: s,
})
}
return uint32(n)
}
@ -642,9 +746,11 @@ func (r *Lexer) Uint64() uint64 {
n, err := strconv.ParseUint(s, 10, 64)
if err != nil {
r.err = &LexerError{
r.addNonfatalError(&LexerError{
Offset: r.start,
Reason: err.Error(),
}
Data: s,
})
}
return n
}
@ -661,9 +767,11 @@ func (r *Lexer) Int8() int8 {
n, err := strconv.ParseInt(s, 10, 8)
if err != nil {
r.err = &LexerError{
r.addNonfatalError(&LexerError{
Offset: r.start,
Reason: err.Error(),
}
Data: s,
})
}
return int8(n)
}
@ -676,9 +784,11 @@ func (r *Lexer) Int16() int16 {
n, err := strconv.ParseInt(s, 10, 16)
if err != nil {
r.err = &LexerError{
r.addNonfatalError(&LexerError{
Offset: r.start,
Reason: err.Error(),
}
Data: s,
})
}
return int16(n)
}
@ -691,9 +801,11 @@ func (r *Lexer) Int32() int32 {
n, err := strconv.ParseInt(s, 10, 32)
if err != nil {
r.err = &LexerError{
r.addNonfatalError(&LexerError{
Offset: r.start,
Reason: err.Error(),
}
Data: s,
})
}
return int32(n)
}
@ -706,9 +818,11 @@ func (r *Lexer) Int64() int64 {
n, err := strconv.ParseInt(s, 10, 64)
if err != nil {
r.err = &LexerError{
r.addNonfatalError(&LexerError{
Offset: r.start,
Reason: err.Error(),
}
Data: s,
})
}
return n
}
@ -718,61 +832,69 @@ func (r *Lexer) Int() int {
}
func (r *Lexer) Uint8Str() uint8 {
s := r.UnsafeString()
s, b := r.unsafeString()
if !r.Ok() {
return 0
}
n, err := strconv.ParseUint(s, 10, 8)
if err != nil {
r.err = &LexerError{
r.addNonfatalError(&LexerError{
Offset: r.start,
Reason: err.Error(),
}
Data: string(b),
})
}
return uint8(n)
}
func (r *Lexer) Uint16Str() uint16 {
s := r.UnsafeString()
s, b := r.unsafeString()
if !r.Ok() {
return 0
}
n, err := strconv.ParseUint(s, 10, 16)
if err != nil {
r.err = &LexerError{
r.addNonfatalError(&LexerError{
Offset: r.start,
Reason: err.Error(),
}
Data: string(b),
})
}
return uint16(n)
}
func (r *Lexer) Uint32Str() uint32 {
s := r.UnsafeString()
s, b := r.unsafeString()
if !r.Ok() {
return 0
}
n, err := strconv.ParseUint(s, 10, 32)
if err != nil {
r.err = &LexerError{
r.addNonfatalError(&LexerError{
Offset: r.start,
Reason: err.Error(),
}
Data: string(b),
})
}
return uint32(n)
}
func (r *Lexer) Uint64Str() uint64 {
s := r.UnsafeString()
s, b := r.unsafeString()
if !r.Ok() {
return 0
}
n, err := strconv.ParseUint(s, 10, 64)
if err != nil {
r.err = &LexerError{
r.addNonfatalError(&LexerError{
Offset: r.start,
Reason: err.Error(),
}
Data: string(b),
})
}
return n
}
@ -782,61 +904,69 @@ func (r *Lexer) UintStr() uint {
}
func (r *Lexer) Int8Str() int8 {
s := r.UnsafeString()
s, b := r.unsafeString()
if !r.Ok() {
return 0
}
n, err := strconv.ParseInt(s, 10, 8)
if err != nil {
r.err = &LexerError{
r.addNonfatalError(&LexerError{
Offset: r.start,
Reason: err.Error(),
}
Data: string(b),
})
}
return int8(n)
}
func (r *Lexer) Int16Str() int16 {
s := r.UnsafeString()
s, b := r.unsafeString()
if !r.Ok() {
return 0
}
n, err := strconv.ParseInt(s, 10, 16)
if err != nil {
r.err = &LexerError{
r.addNonfatalError(&LexerError{
Offset: r.start,
Reason: err.Error(),
}
Data: string(b),
})
}
return int16(n)
}
func (r *Lexer) Int32Str() int32 {
s := r.UnsafeString()
s, b := r.unsafeString()
if !r.Ok() {
return 0
}
n, err := strconv.ParseInt(s, 10, 32)
if err != nil {
r.err = &LexerError{
r.addNonfatalError(&LexerError{
Offset: r.start,
Reason: err.Error(),
}
Data: string(b),
})
}
return int32(n)
}
func (r *Lexer) Int64Str() int64 {
s := r.UnsafeString()
s, b := r.unsafeString()
if !r.Ok() {
return 0
}
n, err := strconv.ParseInt(s, 10, 64)
if err != nil {
r.err = &LexerError{
r.addNonfatalError(&LexerError{
Offset: r.start,
Reason: err.Error(),
}
Data: string(b),
})
}
return n
}
@ -853,9 +983,11 @@ func (r *Lexer) Float32() float32 {
n, err := strconv.ParseFloat(s, 32)
if err != nil {
r.err = &LexerError{
r.addNonfatalError(&LexerError{
Offset: r.start,
Reason: err.Error(),
}
Data: s,
})
}
return float32(n)
}
@ -868,27 +1000,53 @@ func (r *Lexer) Float64() float64 {
n, err := strconv.ParseFloat(s, 64)
if err != nil {
r.err = &LexerError{
r.addNonfatalError(&LexerError{
Offset: r.start,
Reason: err.Error(),
}
Data: s,
})
}
return n
}
func (r *Lexer) Error() error {
return r.err
return r.fatalError
}
func (r *Lexer) AddError(e error) {
if r.err == nil {
r.err = e
if r.fatalError == nil {
r.fatalError = e
}
}
func (r *Lexer) AddNonFatalError(e error) {
r.addNonfatalError(&LexerError{
Offset: r.start,
Data: string(r.Data[r.start:r.pos]),
Reason: e.Error(),
})
}
func (r *Lexer) addNonfatalError(err *LexerError) {
if r.UseMultipleErrors {
// We don't want to add errors with the same offset.
if len(r.multipleErrors) != 0 && r.multipleErrors[len(r.multipleErrors)-1].Offset == err.Offset {
return
}
r.multipleErrors = append(r.multipleErrors, err)
return
}
r.fatalError = err
}
func (r *Lexer) GetNonFatalErrors() []*LexerError {
return r.multipleErrors
}
// Interface fetches an interface{} analogous to the 'encoding/json' package.
func (r *Lexer) Interface() interface{} {
if r.token.kind == tokenUndef && r.Ok() {
r.fetchToken()
r.FetchToken()
}
if !r.Ok() {

View File

@ -2,6 +2,7 @@
package jwriter
import (
"encoding/base64"
"io"
"strconv"
"unicode/utf8"
@ -9,10 +10,22 @@ import (
"github.com/mailru/easyjson/buffer"
)
// Flags describe various encoding options. The behavior may be actually implemented in the encoder, but
// Flags field in Writer is used to set and pass them around.
type Flags int
const (
NilMapAsEmpty Flags = 1 << iota // Encode nil map as '{}' rather than 'null'.
NilSliceAsEmpty // Encode nil slice as '[]' rather than 'null'.
)
// Writer is a JSON writer.
type Writer struct {
Flags Flags
Error error
Buffer buffer.Buffer
NoEscapeHTML bool
}
// Size returns the size of the data that was written out.
@ -25,13 +38,24 @@ func (w *Writer) DumpTo(out io.Writer) (written int, err error) {
return w.Buffer.DumpTo(out)
}
// BuildBytes returns writer data as a single byte slice.
func (w *Writer) BuildBytes() ([]byte, error) {
// BuildBytes returns writer data as a single byte slice. You can optionally provide one byte slice
// as argument that it will try to reuse.
func (w *Writer) BuildBytes(reuse ...[]byte) ([]byte, error) {
if w.Error != nil {
return nil, w.Error
}
return w.Buffer.BuildBytes(), nil
return w.Buffer.BuildBytes(reuse...), nil
}
// ReadCloser returns an io.ReadCloser that can be used to read the data.
// ReadCloser also resets the buffer.
func (w *Writer) ReadCloser() (io.ReadCloser, error) {
if w.Error != nil {
return nil, w.Error
}
return w.Buffer.ReadCloser(), nil
}
// RawByte appends raw binary data to the buffer.
@ -44,7 +68,7 @@ func (w *Writer) RawString(s string) {
w.Buffer.AppendString(s)
}
// RawByte appends raw binary data to the buffer or sets the error if it is given. Useful for
// Raw appends raw binary data to the buffer or sets the error if it is given. Useful for
// calling with results of MarshalJSON-like functions.
func (w *Writer) Raw(data []byte, err error) {
switch {
@ -59,6 +83,34 @@ func (w *Writer) Raw(data []byte, err error) {
}
}
// RawText encloses raw binary data in quotes and appends in to the buffer.
// Useful for calling with results of MarshalText-like functions.
func (w *Writer) RawText(data []byte, err error) {
switch {
case w.Error != nil:
return
case err != nil:
w.Error = err
case len(data) > 0:
w.String(string(data))
default:
w.RawString("null")
}
}
// Base64Bytes appends data to the buffer after base64 encoding it
func (w *Writer) Base64Bytes(data []byte) {
if data == nil {
w.Buffer.AppendString("null")
return
}
w.Buffer.AppendByte('"')
dst := make([]byte, base64.StdEncoding.EncodedLen(len(data)))
base64.StdEncoding.Encode(dst, data)
w.Buffer.AppendBytes(dst)
w.Buffer.AppendByte('"')
}
func (w *Writer) Uint8(n uint8) {
w.Buffer.EnsureSpace(3)
w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
@ -200,6 +252,16 @@ func (w *Writer) Bool(v bool) {
const chars = "0123456789abcdef"
func isNotEscapedSingleChar(c byte, escapeHTML bool) bool {
// Note: might make sense to use a table if there are more chars to escape. With 4 chars
// it benchmarks the same.
if escapeHTML {
return c != '<' && c != '>' && c != '&' && c != '\\' && c != '"' && c >= 0x20 && c < utf8.RuneSelf
} else {
return c != '\\' && c != '"' && c >= 0x20 && c < utf8.RuneSelf
}
}
func (w *Writer) String(s string) {
w.Buffer.AppendByte('"')
@ -209,39 +271,32 @@ func (w *Writer) String(s string) {
p := 0 // last non-escape symbol
for i := 0; i < len(s); {
// single-with character
if c := s[i]; c < utf8.RuneSelf {
var escape byte
switch c {
case '\t':
escape = 't'
case '\r':
escape = 'r'
case '\n':
escape = 'n'
case '\\':
escape = '\\'
case '"':
escape = '"'
case '<', '>':
// do nothing
default:
if c >= 0x20 {
// no escaping is required
c := s[i]
if isNotEscapedSingleChar(c, !w.NoEscapeHTML) {
// single-width character, no escaping is required
i++
continue
}
}
if escape != 0 {
w.Buffer.AppendString(s[p:i])
w.Buffer.AppendByte('\\')
w.Buffer.AppendByte(escape)
} else {
} else if c < utf8.RuneSelf {
// single-with character, need to escape
w.Buffer.AppendString(s[p:i])
switch c {
case '\t':
w.Buffer.AppendString(`\t`)
case '\r':
w.Buffer.AppendString(`\r`)
case '\n':
w.Buffer.AppendString(`\n`)
case '\\':
w.Buffer.AppendString(`\\`)
case '"':
w.Buffer.AppendString(`\"`)
default:
w.Buffer.AppendString(`\u00`)
w.Buffer.AppendByte(chars[c>>4])
w.Buffer.AppendByte(chars[c&0xf])
}
i++
p = i
continue