mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-09-19 01:29:57 +00:00
961c878e0d
Switch to using Go modules. This migrates our vendor.json to use Go 1.11's modules system, and replaces the vendor folder with the output of go mod vendor. The vendored code should remain basically the same; I believe some tree shaking of packages and support scripts/licenses/READMEs/etc. happened. This also fixes Travis and our Makefile to no longer use govendor.
171 lines
3.6 KiB
Go
171 lines
3.6 KiB
Go
package json
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"github.com/zclconf/go-cty/cty"
|
|
)
|
|
|
|
// ImpliedType returns the cty Type implied by the structure of the given
|
|
// JSON-compliant buffer. This function implements the default type mapping
|
|
// behavior used when decoding arbitrary JSON without explicit cty Type
|
|
// information.
|
|
//
|
|
// The rules are as follows:
|
|
//
|
|
// JSON strings, numbers and bools map to their equivalent primitive type in
|
|
// cty.
|
|
//
|
|
// JSON objects map to cty object types, with the attributes defined by the
|
|
// object keys and the types of their values.
|
|
//
|
|
// JSON arrays map to cty tuple types, with the elements defined by the
|
|
// types of the array members.
|
|
//
|
|
// Any nulls are typed as DynamicPseudoType, so callers of this function
|
|
// must be prepared to deal with this. Callers that do not wish to deal with
|
|
// dynamic typing should not use this function and should instead describe
|
|
// their required types explicitly with a cty.Type instance when decoding.
|
|
//
|
|
// Any JSON syntax errors will be returned as an error, and the type will
|
|
// be the invalid value cty.NilType.
|
|
func ImpliedType(buf []byte) (cty.Type, error) {
|
|
r := bytes.NewReader(buf)
|
|
dec := json.NewDecoder(r)
|
|
dec.UseNumber()
|
|
|
|
ty, err := impliedType(dec)
|
|
if err != nil {
|
|
return cty.NilType, err
|
|
}
|
|
|
|
if dec.More() {
|
|
return cty.NilType, fmt.Errorf("extraneous data after JSON object")
|
|
}
|
|
|
|
return ty, nil
|
|
}
|
|
|
|
func impliedType(dec *json.Decoder) (cty.Type, error) {
|
|
tok, err := dec.Token()
|
|
if err != nil {
|
|
return cty.NilType, err
|
|
}
|
|
|
|
return impliedTypeForTok(tok, dec)
|
|
}
|
|
|
|
func impliedTypeForTok(tok json.Token, dec *json.Decoder) (cty.Type, error) {
|
|
if tok == nil {
|
|
return cty.DynamicPseudoType, nil
|
|
}
|
|
|
|
switch ttok := tok.(type) {
|
|
case bool:
|
|
return cty.Bool, nil
|
|
|
|
case json.Number:
|
|
return cty.Number, nil
|
|
|
|
case string:
|
|
return cty.String, nil
|
|
|
|
case json.Delim:
|
|
|
|
switch rune(ttok) {
|
|
case '{':
|
|
return impliedObjectType(dec)
|
|
case '[':
|
|
return impliedTupleType(dec)
|
|
default:
|
|
return cty.NilType, fmt.Errorf("unexpected token %q", ttok)
|
|
}
|
|
|
|
default:
|
|
return cty.NilType, fmt.Errorf("unsupported JSON token %#v", tok)
|
|
}
|
|
}
|
|
|
|
func impliedObjectType(dec *json.Decoder) (cty.Type, error) {
|
|
// By the time we get in here, we've already consumed the { delimiter
|
|
// and so our next token should be the first object key.
|
|
|
|
var atys map[string]cty.Type
|
|
|
|
for {
|
|
// Read the object key first
|
|
tok, err := dec.Token()
|
|
if err != nil {
|
|
return cty.NilType, err
|
|
}
|
|
|
|
if ttok, ok := tok.(json.Delim); ok {
|
|
if rune(ttok) != '}' {
|
|
return cty.NilType, fmt.Errorf("unexpected delimiter %q", ttok)
|
|
}
|
|
break
|
|
}
|
|
|
|
key, ok := tok.(string)
|
|
if !ok {
|
|
return cty.NilType, fmt.Errorf("expected string but found %T", tok)
|
|
}
|
|
|
|
// Now read the value
|
|
tok, err = dec.Token()
|
|
if err != nil {
|
|
return cty.NilType, err
|
|
}
|
|
|
|
aty, err := impliedTypeForTok(tok, dec)
|
|
if err != nil {
|
|
return cty.NilType, err
|
|
}
|
|
|
|
if atys == nil {
|
|
atys = make(map[string]cty.Type)
|
|
}
|
|
atys[key] = aty
|
|
}
|
|
|
|
if len(atys) == 0 {
|
|
return cty.EmptyObject, nil
|
|
}
|
|
|
|
return cty.Object(atys), nil
|
|
}
|
|
|
|
func impliedTupleType(dec *json.Decoder) (cty.Type, error) {
|
|
// By the time we get in here, we've already consumed the [ delimiter
|
|
// and so our next token should be the first value.
|
|
|
|
var etys []cty.Type
|
|
|
|
for {
|
|
tok, err := dec.Token()
|
|
if err != nil {
|
|
return cty.NilType, err
|
|
}
|
|
|
|
if ttok, ok := tok.(json.Delim); ok {
|
|
if rune(ttok) == ']' {
|
|
break
|
|
}
|
|
}
|
|
|
|
ety, err := impliedTypeForTok(tok, dec)
|
|
if err != nil {
|
|
return cty.NilType, err
|
|
}
|
|
etys = append(etys, ety)
|
|
}
|
|
|
|
if len(etys) == 0 {
|
|
return cty.EmptyTuple, nil
|
|
}
|
|
|
|
return cty.Tuple(etys), nil
|
|
}
|