You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
246 lines
5.9 KiB
246 lines
5.9 KiB
// 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
|
|
}
|
|
|
|
// BytesToYAMLDoc converts a byte slice into a YAML document
|
|
func BytesToYAMLDoc(data []byte) (interface{}, error) {
|
|
var canary map[interface{}]interface{} // validate this is an object and not a different type
|
|
if err := yaml.Unmarshal(data, &canary); err != nil {
|
|
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
|
|
}
|
|
|
|
// JSONMapSlice represent a JSON object, with the order of keys maintained
|
|
type JSONMapSlice []JSONMapItem
|
|
|
|
// MarshalJSON renders a JSONMapSlice as JSON
|
|
func (s JSONMapSlice) MarshalJSON() ([]byte, error) {
|
|
w := &jwriter.Writer{Flags: jwriter.NilMapAsEmpty | jwriter.NilSliceAsEmpty}
|
|
s.MarshalEasyJSON(w)
|
|
return w.BuildBytes()
|
|
}
|
|
|
|
// MarshalEasyJSON renders a JSONMapSlice as JSON, using easyJSON
|
|
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('}')
|
|
}
|
|
|
|
// UnmarshalJSON makes a JSONMapSlice from JSON
|
|
func (s *JSONMapSlice) UnmarshalJSON(data []byte) error {
|
|
l := jlexer.Lexer{Data: data}
|
|
s.UnmarshalEasyJSON(&l)
|
|
return l.Error()
|
|
}
|
|
|
|
// UnmarshalEasyJSON makes a JSONMapSlice from JSON, using easyJSON
|
|
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
|
|
}
|
|
|
|
// JSONMapItem represents the value of a key in a JSON object held by JSONMapSlice
|
|
type JSONMapItem struct {
|
|
Key string
|
|
Value interface{}
|
|
}
|
|
|
|
// MarshalJSON renders a JSONMapItem as JSON
|
|
func (s JSONMapItem) MarshalJSON() ([]byte, error) {
|
|
w := &jwriter.Writer{Flags: jwriter.NilMapAsEmpty | jwriter.NilSliceAsEmpty}
|
|
s.MarshalEasyJSON(w)
|
|
return w.BuildBytes()
|
|
}
|
|
|
|
// MarshalEasyJSON renders a JSONMapItem as JSON, using easyJSON
|
|
func (s JSONMapItem) MarshalEasyJSON(w *jwriter.Writer) {
|
|
w.String(s.Key)
|
|
w.RawByte(':')
|
|
w.Raw(WriteJSON(s.Value))
|
|
}
|
|
|
|
// UnmarshalJSON makes a JSONMapItem from JSON
|
|
func (s *JSONMapItem) UnmarshalJSON(data []byte) error {
|
|
l := jlexer.Lexer{Data: data}
|
|
s.UnmarshalEasyJSON(&l)
|
|
return l.Error()
|
|
}
|
|
|
|
// UnmarshalEasyJSON makes a JSONMapItem from JSON, using easyJSON
|
|
func (s *JSONMapItem) UnmarshalEasyJSON(in *jlexer.Lexer) {
|
|
key := in.UnsafeString()
|
|
in.WantColon()
|
|
value := in.Interface()
|
|
in.WantComma()
|
|
s.Key = key
|
|
s.Value = value
|
|
}
|
|
|
|
func transformData(input interface{}) (out interface{}, err error) {
|
|
format := func(t interface{}) (string, error) {
|
|
switch k := t.(type) {
|
|
case string:
|
|
return k, nil
|
|
case uint:
|
|
return strconv.FormatUint(uint64(k), 10), nil
|
|
case uint8:
|
|
return strconv.FormatUint(uint64(k), 10), nil
|
|
case uint16:
|
|
return strconv.FormatUint(uint64(k), 10), nil
|
|
case uint32:
|
|
return strconv.FormatUint(uint64(k), 10), nil
|
|
case uint64:
|
|
return strconv.FormatUint(k, 10), nil
|
|
case int:
|
|
return strconv.Itoa(k), nil
|
|
case int8:
|
|
return strconv.FormatInt(int64(k), 10), nil
|
|
case int16:
|
|
return strconv.FormatInt(int64(k), 10), nil
|
|
case int32:
|
|
return strconv.FormatInt(int64(k), 10), nil
|
|
case int64:
|
|
return strconv.FormatInt(k, 10), nil
|
|
default:
|
|
return "", fmt.Errorf("unexpected map key type, got: %T", k)
|
|
}
|
|
}
|
|
|
|
switch in := input.(type) {
|
|
case yaml.MapSlice:
|
|
|
|
o := make(JSONMapSlice, len(in))
|
|
for i, mi := range in {
|
|
var nmi JSONMapItem
|
|
if nmi.Key, err = format(mi.Key); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
v, ert := transformData(mi.Value)
|
|
if ert != nil {
|
|
return nil, ert
|
|
}
|
|
nmi.Value = v
|
|
o[i] = nmi
|
|
}
|
|
return o, nil
|
|
case map[interface{}]interface{}:
|
|
o := make(JSONMapSlice, 0, len(in))
|
|
for ke, va := range in {
|
|
var nmi JSONMapItem
|
|
if nmi.Key, err = format(ke); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
v, ert := transformData(va)
|
|
if ert != nil {
|
|
return nil, ert
|
|
}
|
|
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 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)
|
|
}
|
|
|