2017-12-08 12:03:10 +00:00
|
|
|
// +build codegen
|
|
|
|
|
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"path"
|
|
|
|
"regexp"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
"text/template"
|
2019-01-21 14:27:20 +00:00
|
|
|
|
|
|
|
"github.com/aws/aws-sdk-go/private/protocol"
|
2017-12-08 12:03:10 +00:00
|
|
|
)
|
|
|
|
|
2019-01-21 14:27:20 +00:00
|
|
|
// ErrorInfo represents the error block of a shape's structure
|
|
|
|
type ErrorInfo struct {
|
|
|
|
Type string
|
|
|
|
Code string
|
|
|
|
HTTPStatusCode int
|
|
|
|
}
|
|
|
|
|
|
|
|
// A XMLInfo defines URL and prefix for Shapes when rendered as XML
|
|
|
|
type XMLInfo struct {
|
|
|
|
Prefix string
|
|
|
|
URI string
|
|
|
|
}
|
|
|
|
|
2017-12-08 12:03:10 +00:00
|
|
|
// A ShapeRef defines the usage of a shape within the API.
|
|
|
|
type ShapeRef struct {
|
|
|
|
API *API `json:"-"`
|
|
|
|
Shape *Shape `json:"-"`
|
|
|
|
Documentation string
|
|
|
|
ShapeName string `json:"shape"`
|
|
|
|
Location string
|
|
|
|
LocationName string
|
|
|
|
QueryName string
|
|
|
|
Flattened bool
|
|
|
|
Streaming bool
|
|
|
|
XMLAttribute bool
|
|
|
|
// Ignore, if set, will not be sent over the wire
|
2019-01-21 14:27:20 +00:00
|
|
|
Ignore bool
|
|
|
|
XMLNamespace XMLInfo
|
|
|
|
Payload string
|
|
|
|
IdempotencyToken bool `json:"idempotencyToken"`
|
|
|
|
TimestampFormat string `json:"timestampFormat"`
|
|
|
|
JSONValue bool `json:"jsonvalue"`
|
|
|
|
Deprecated bool `json:"deprecated"`
|
|
|
|
DeprecatedMsg string `json:"deprecatedMessage"`
|
|
|
|
EndpointDiscoveryID bool `json:"endpointdiscoveryid"`
|
|
|
|
HostLabel bool `json:"hostLabel"`
|
2017-12-08 12:03:10 +00:00
|
|
|
|
|
|
|
OrigShapeName string `json:"-"`
|
|
|
|
|
|
|
|
GenerateGetter bool
|
|
|
|
|
2019-01-21 14:27:20 +00:00
|
|
|
IsEventPayload bool `json:"eventpayload"`
|
|
|
|
IsEventHeader bool `json:"eventheader"`
|
2017-12-08 12:03:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// A Shape defines the definition of a shape type
|
|
|
|
type Shape struct {
|
|
|
|
API *API `json:"-"`
|
|
|
|
ShapeName string
|
|
|
|
Documentation string
|
|
|
|
MemberRefs map[string]*ShapeRef `json:"members"`
|
2019-01-21 14:27:20 +00:00
|
|
|
MemberRef ShapeRef `json:"member"` // List ref
|
|
|
|
KeyRef ShapeRef `json:"key"` // map key ref
|
|
|
|
ValueRef ShapeRef `json:"value"` // map value ref
|
2017-12-08 12:03:10 +00:00
|
|
|
Required []string
|
|
|
|
Payload string
|
|
|
|
Type string
|
|
|
|
Exception bool
|
|
|
|
Enum []string
|
|
|
|
EnumConsts []string
|
|
|
|
Flattened bool
|
|
|
|
Streaming bool
|
|
|
|
Location string
|
|
|
|
LocationName string
|
2019-01-21 14:27:20 +00:00
|
|
|
IdempotencyToken bool `json:"idempotencyToken"`
|
|
|
|
TimestampFormat string `json:"timestampFormat"`
|
2017-12-08 12:03:10 +00:00
|
|
|
XMLNamespace XMLInfo
|
|
|
|
Min float64 // optional Minimum length (string, list) or value (number)
|
2019-01-21 14:27:20 +00:00
|
|
|
|
|
|
|
EventStreamsMemberName string `json:"-"`
|
|
|
|
EventStreamAPI *EventStreamAPI `json:"-"`
|
|
|
|
EventFor []*EventStream `json:"-"`
|
|
|
|
|
|
|
|
IsEventStream bool `json:"eventstream"`
|
|
|
|
IsEvent bool `json:"event"`
|
2017-12-08 12:03:10 +00:00
|
|
|
|
|
|
|
refs []*ShapeRef // References to this shape
|
|
|
|
resolvePkg string // use this package in the goType() if present
|
|
|
|
|
|
|
|
OrigShapeName string `json:"-"`
|
|
|
|
|
|
|
|
// Defines if the shape is a placeholder and should not be used directly
|
|
|
|
Placeholder bool
|
|
|
|
|
2019-01-21 14:27:20 +00:00
|
|
|
Deprecated bool `json:"deprecated"`
|
|
|
|
DeprecatedMsg string `json:"deprecatedMessage"`
|
2017-12-08 12:03:10 +00:00
|
|
|
|
|
|
|
Validations ShapeValidations
|
|
|
|
|
|
|
|
// Error information that is set if the shape is an error shape.
|
|
|
|
IsError bool
|
|
|
|
ErrorInfo ErrorInfo `json:"error"`
|
2019-01-21 14:27:20 +00:00
|
|
|
|
|
|
|
// Flags that the shape cannot be rename. Prevents the shape from being
|
|
|
|
// renamed further by the Input/Output.
|
|
|
|
AliasedShapeName bool
|
|
|
|
|
|
|
|
// Sensitive types should not be logged by SDK type loggers.
|
|
|
|
Sensitive bool `json:"sensitive"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// CanBeEmpty returns if the shape value can sent request as an empty value.
|
|
|
|
// String, blob, list, and map are types must not be empty when the member is
|
|
|
|
// serialized to the uri path, or decorated with HostLabel.
|
|
|
|
func (ref *ShapeRef) CanBeEmpty() bool {
|
|
|
|
switch ref.Shape.Type {
|
|
|
|
case "string":
|
|
|
|
return !(ref.Location == "uri" || ref.HostLabel)
|
|
|
|
case "blob", "map", "list":
|
|
|
|
return !(ref.Location == "uri")
|
|
|
|
default:
|
|
|
|
return true
|
|
|
|
}
|
2017-12-08 12:03:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ErrorCodeName will return the error shape's name formated for
|
|
|
|
// error code const.
|
|
|
|
func (s *Shape) ErrorCodeName() string {
|
|
|
|
return "ErrCode" + s.ShapeName
|
|
|
|
}
|
|
|
|
|
|
|
|
// ErrorName will return the shape's name or error code if available based
|
|
|
|
// on the API's protocol. This is the error code string returned by the service.
|
|
|
|
func (s *Shape) ErrorName() string {
|
2019-01-21 14:27:20 +00:00
|
|
|
name := s.ErrorInfo.Type
|
2017-12-08 12:03:10 +00:00
|
|
|
switch s.API.Metadata.Protocol {
|
|
|
|
case "query", "ec2query", "rest-xml":
|
|
|
|
if len(s.ErrorInfo.Code) > 0 {
|
|
|
|
name = s.ErrorInfo.Code
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return name
|
|
|
|
}
|
|
|
|
|
2019-01-21 14:27:20 +00:00
|
|
|
// PayloadRefName returns the payload member of the shape if there is one
|
|
|
|
// modeled. If no payload is modeled, empty string will be returned.
|
|
|
|
func (s *Shape) PayloadRefName() string {
|
|
|
|
if name := s.Payload; len(name) != 0 {
|
|
|
|
// Root shape
|
|
|
|
return name
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, ref := range s.MemberRefs {
|
|
|
|
if ref.IsEventPayload {
|
|
|
|
return name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2017-12-08 12:03:10 +00:00
|
|
|
// GoTags returns the struct tags for a shape.
|
|
|
|
func (s *Shape) GoTags(root, required bool) string {
|
|
|
|
ref := &ShapeRef{ShapeName: s.ShapeName, API: s.API, Shape: s}
|
|
|
|
return ref.GoTags(root, required)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Rename changes the name of the Shape to newName. Also updates
|
|
|
|
// the associated API's reference to use newName.
|
|
|
|
func (s *Shape) Rename(newName string) {
|
2019-01-21 14:27:20 +00:00
|
|
|
if s.AliasedShapeName {
|
|
|
|
panic(fmt.Sprintf("attempted to rename %s, but flagged as aliased",
|
|
|
|
s.ShapeName))
|
|
|
|
}
|
|
|
|
|
2017-12-08 12:03:10 +00:00
|
|
|
for _, r := range s.refs {
|
|
|
|
r.OrigShapeName = r.ShapeName
|
|
|
|
r.ShapeName = newName
|
|
|
|
}
|
|
|
|
|
|
|
|
delete(s.API.Shapes, s.ShapeName)
|
|
|
|
s.OrigShapeName = s.ShapeName
|
|
|
|
s.API.Shapes[newName] = s
|
|
|
|
s.ShapeName = newName
|
|
|
|
}
|
|
|
|
|
|
|
|
// MemberNames returns a slice of struct member names.
|
|
|
|
func (s *Shape) MemberNames() []string {
|
|
|
|
i, names := 0, make([]string, len(s.MemberRefs))
|
|
|
|
for n := range s.MemberRefs {
|
|
|
|
names[i] = n
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
sort.Strings(names)
|
|
|
|
return names
|
|
|
|
}
|
|
|
|
|
2019-01-21 14:27:20 +00:00
|
|
|
// HasMember will return whether or not the shape has a given
|
|
|
|
// member by name.
|
|
|
|
func (s *Shape) HasMember(name string) bool {
|
|
|
|
_, ok := s.MemberRefs[name]
|
|
|
|
return ok
|
|
|
|
}
|
|
|
|
|
2017-12-08 12:03:10 +00:00
|
|
|
// GoTypeWithPkgName returns a shape's type as a string with the package name in
|
|
|
|
// <packageName>.<type> format. Package naming only applies to structures.
|
|
|
|
func (s *Shape) GoTypeWithPkgName() string {
|
|
|
|
return goType(s, true)
|
|
|
|
}
|
|
|
|
|
2019-01-21 14:27:20 +00:00
|
|
|
// GoTypeWithPkgNameElem returns the shapes type as a string with the "*"
|
|
|
|
// removed if there was one preset.
|
2017-12-08 12:03:10 +00:00
|
|
|
func (s *Shape) GoTypeWithPkgNameElem() string {
|
|
|
|
t := goType(s, true)
|
|
|
|
if strings.HasPrefix(t, "*") {
|
|
|
|
return t[1:]
|
|
|
|
}
|
|
|
|
return t
|
|
|
|
}
|
|
|
|
|
2019-01-21 14:27:20 +00:00
|
|
|
// UseIndirection returns if the shape's reference should use indirection or not.
|
2017-12-08 12:03:10 +00:00
|
|
|
func (s *ShapeRef) UseIndirection() bool {
|
|
|
|
switch s.Shape.Type {
|
|
|
|
case "map", "list", "blob", "structure", "jsonvalue":
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.Streaming || s.Shape.Streaming {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.JSONValue {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2019-01-21 14:27:20 +00:00
|
|
|
func (s Shape) GetTimestampFormat() string {
|
|
|
|
format := s.TimestampFormat
|
|
|
|
|
|
|
|
if len(format) > 0 && !protocol.IsKnownTimestampFormat(format) {
|
|
|
|
panic(fmt.Sprintf("Unknown timestampFormat %s, for %s",
|
|
|
|
format, s.ShapeName))
|
|
|
|
}
|
|
|
|
|
|
|
|
return format
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ref ShapeRef) GetTimestampFormat() string {
|
|
|
|
format := ref.TimestampFormat
|
|
|
|
|
|
|
|
if len(format) == 0 {
|
|
|
|
format = ref.Shape.TimestampFormat
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(format) > 0 && !protocol.IsKnownTimestampFormat(format) {
|
|
|
|
panic(fmt.Sprintf("Unknown timestampFormat %s, for %s",
|
|
|
|
format, ref.ShapeName))
|
|
|
|
}
|
|
|
|
|
|
|
|
return format
|
|
|
|
}
|
|
|
|
|
2017-12-08 12:03:10 +00:00
|
|
|
// GoStructValueType returns the Shape's Go type value instead of a pointer
|
|
|
|
// for the type.
|
|
|
|
func (s *Shape) GoStructValueType(name string, ref *ShapeRef) string {
|
|
|
|
v := s.GoStructType(name, ref)
|
|
|
|
|
|
|
|
if ref.UseIndirection() && v[0] == '*' {
|
|
|
|
return v[1:]
|
|
|
|
}
|
|
|
|
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
|
|
|
// GoStructType returns the type of a struct field based on the API
|
|
|
|
// model definition.
|
|
|
|
func (s *Shape) GoStructType(name string, ref *ShapeRef) string {
|
|
|
|
if (ref.Streaming || ref.Shape.Streaming) && s.Payload == name {
|
|
|
|
rtype := "io.ReadSeeker"
|
|
|
|
if strings.HasSuffix(s.ShapeName, "Output") {
|
|
|
|
rtype = "io.ReadCloser"
|
|
|
|
}
|
|
|
|
|
|
|
|
s.API.imports["io"] = true
|
|
|
|
return rtype
|
|
|
|
}
|
|
|
|
|
|
|
|
if ref.JSONValue {
|
2019-01-21 14:27:20 +00:00
|
|
|
s.API.AddSDKImport("aws")
|
2017-12-08 12:03:10 +00:00
|
|
|
return "aws.JSONValue"
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, v := range s.Validations {
|
|
|
|
// TODO move this to shape validation resolution
|
|
|
|
if (v.Ref.Shape.Type == "map" || v.Ref.Shape.Type == "list") && v.Type == ShapeValidationNested {
|
|
|
|
s.API.imports["fmt"] = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ref.GoType()
|
|
|
|
}
|
|
|
|
|
|
|
|
// GoType returns a shape's Go type
|
|
|
|
func (s *Shape) GoType() string {
|
|
|
|
return goType(s, false)
|
|
|
|
}
|
|
|
|
|
|
|
|
// GoType returns a shape ref's Go type.
|
|
|
|
func (ref *ShapeRef) GoType() string {
|
|
|
|
if ref.Shape == nil {
|
|
|
|
panic(fmt.Errorf("missing shape definition on reference for %#v", ref))
|
|
|
|
}
|
|
|
|
|
|
|
|
return ref.Shape.GoType()
|
|
|
|
}
|
|
|
|
|
|
|
|
// GoTypeWithPkgName returns a shape's type as a string with the package name in
|
|
|
|
// <packageName>.<type> format. Package naming only applies to structures.
|
|
|
|
func (ref *ShapeRef) GoTypeWithPkgName() string {
|
|
|
|
if ref.Shape == nil {
|
|
|
|
panic(fmt.Errorf("missing shape definition on reference for %#v", ref))
|
|
|
|
}
|
|
|
|
|
|
|
|
return ref.Shape.GoTypeWithPkgName()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a string version of the Shape's type.
|
|
|
|
// If withPkgName is true, the package name will be added as a prefix
|
|
|
|
func goType(s *Shape, withPkgName bool) string {
|
|
|
|
switch s.Type {
|
|
|
|
case "structure":
|
|
|
|
if withPkgName || s.resolvePkg != "" {
|
|
|
|
pkg := s.resolvePkg
|
|
|
|
if pkg != "" {
|
|
|
|
s.API.imports[pkg] = true
|
|
|
|
pkg = path.Base(pkg)
|
|
|
|
} else {
|
|
|
|
pkg = s.API.PackageName()
|
|
|
|
}
|
|
|
|
return fmt.Sprintf("*%s.%s", pkg, s.ShapeName)
|
|
|
|
}
|
|
|
|
return "*" + s.ShapeName
|
|
|
|
case "map":
|
|
|
|
return "map[string]" + goType(s.ValueRef.Shape, withPkgName)
|
|
|
|
case "jsonvalue":
|
|
|
|
return "aws.JSONValue"
|
|
|
|
case "list":
|
|
|
|
return "[]" + goType(s.MemberRef.Shape, withPkgName)
|
|
|
|
case "boolean":
|
|
|
|
return "*bool"
|
|
|
|
case "string", "character":
|
|
|
|
return "*string"
|
|
|
|
case "blob":
|
|
|
|
return "[]byte"
|
2019-01-21 14:27:20 +00:00
|
|
|
case "byte", "short", "integer", "long":
|
2017-12-08 12:03:10 +00:00
|
|
|
return "*int64"
|
|
|
|
case "float", "double":
|
|
|
|
return "*float64"
|
|
|
|
case "timestamp":
|
|
|
|
s.API.imports["time"] = true
|
|
|
|
return "*time.Time"
|
|
|
|
default:
|
|
|
|
panic("Unsupported shape type: " + s.Type)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GoTypeElem returns the Go type for the Shape. If the shape type is a pointer just
|
|
|
|
// the type will be returned minus the pointer *.
|
|
|
|
func (s *Shape) GoTypeElem() string {
|
|
|
|
t := s.GoType()
|
|
|
|
if strings.HasPrefix(t, "*") {
|
|
|
|
return t[1:]
|
|
|
|
}
|
|
|
|
return t
|
|
|
|
}
|
|
|
|
|
|
|
|
// GoTypeElem returns the Go type for the Shape. If the shape type is a pointer just
|
|
|
|
// the type will be returned minus the pointer *.
|
|
|
|
func (ref *ShapeRef) GoTypeElem() string {
|
|
|
|
if ref.Shape == nil {
|
|
|
|
panic(fmt.Errorf("missing shape definition on reference for %#v", ref))
|
|
|
|
}
|
|
|
|
|
|
|
|
return ref.Shape.GoTypeElem()
|
|
|
|
}
|
|
|
|
|
|
|
|
// ShapeTag is a struct tag that will be applied to a shape's generated code
|
|
|
|
type ShapeTag struct {
|
|
|
|
Key, Val string
|
|
|
|
}
|
|
|
|
|
|
|
|
// String returns the string representation of the shape tag
|
|
|
|
func (s ShapeTag) String() string {
|
|
|
|
return fmt.Sprintf(`%s:"%s"`, s.Key, s.Val)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ShapeTags is a collection of shape tags and provides serialization of the
|
|
|
|
// tags in an ordered list.
|
|
|
|
type ShapeTags []ShapeTag
|
|
|
|
|
|
|
|
// Join returns an ordered serialization of the shape tags with the provided
|
|
|
|
// separator.
|
|
|
|
func (s ShapeTags) Join(sep string) string {
|
|
|
|
o := &bytes.Buffer{}
|
|
|
|
for i, t := range s {
|
|
|
|
o.WriteString(t.String())
|
|
|
|
if i < len(s)-1 {
|
|
|
|
o.WriteString(sep)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return o.String()
|
|
|
|
}
|
|
|
|
|
|
|
|
// String is an alias for Join with the empty space separator.
|
|
|
|
func (s ShapeTags) String() string {
|
|
|
|
return s.Join(" ")
|
|
|
|
}
|
|
|
|
|
|
|
|
// GoTags returns the rendered tags string for the ShapeRef
|
|
|
|
func (ref *ShapeRef) GoTags(toplevel bool, isRequired bool) string {
|
|
|
|
tags := ShapeTags{}
|
|
|
|
|
|
|
|
if ref.Location != "" {
|
|
|
|
tags = append(tags, ShapeTag{"location", ref.Location})
|
|
|
|
} else if ref.Shape.Location != "" {
|
|
|
|
tags = append(tags, ShapeTag{"location", ref.Shape.Location})
|
2019-01-21 14:27:20 +00:00
|
|
|
} else if ref.IsEventHeader {
|
|
|
|
tags = append(tags, ShapeTag{"location", "header"})
|
2017-12-08 12:03:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ref.LocationName != "" {
|
|
|
|
tags = append(tags, ShapeTag{"locationName", ref.LocationName})
|
|
|
|
} else if ref.Shape.LocationName != "" {
|
|
|
|
tags = append(tags, ShapeTag{"locationName", ref.Shape.LocationName})
|
2019-01-21 14:27:20 +00:00
|
|
|
} else if len(ref.Shape.EventFor) != 0 && ref.API.Metadata.Protocol == "rest-xml" {
|
|
|
|
// RPC JSON events need to have location name modeled for round trip testing.
|
|
|
|
tags = append(tags, ShapeTag{"locationName", ref.Shape.ShapeName})
|
2017-12-08 12:03:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ref.QueryName != "" {
|
|
|
|
tags = append(tags, ShapeTag{"queryName", ref.QueryName})
|
|
|
|
}
|
|
|
|
if ref.Shape.MemberRef.LocationName != "" {
|
|
|
|
tags = append(tags, ShapeTag{"locationNameList", ref.Shape.MemberRef.LocationName})
|
|
|
|
}
|
|
|
|
if ref.Shape.KeyRef.LocationName != "" {
|
|
|
|
tags = append(tags, ShapeTag{"locationNameKey", ref.Shape.KeyRef.LocationName})
|
|
|
|
}
|
|
|
|
if ref.Shape.ValueRef.LocationName != "" {
|
|
|
|
tags = append(tags, ShapeTag{"locationNameValue", ref.Shape.ValueRef.LocationName})
|
|
|
|
}
|
|
|
|
if ref.Shape.Min > 0 {
|
|
|
|
tags = append(tags, ShapeTag{"min", fmt.Sprintf("%v", ref.Shape.Min)})
|
|
|
|
}
|
|
|
|
|
|
|
|
if ref.Deprecated || ref.Shape.Deprecated {
|
|
|
|
tags = append(tags, ShapeTag{"deprecated", "true"})
|
|
|
|
}
|
|
|
|
|
|
|
|
// All shapes have a type
|
|
|
|
tags = append(tags, ShapeTag{"type", ref.Shape.Type})
|
|
|
|
|
|
|
|
// embed the timestamp type for easier lookups
|
|
|
|
if ref.Shape.Type == "timestamp" {
|
2019-01-21 14:27:20 +00:00
|
|
|
if format := ref.GetTimestampFormat(); len(format) > 0 {
|
|
|
|
tags = append(tags, ShapeTag{
|
|
|
|
Key: "timestampFormat",
|
|
|
|
Val: format,
|
|
|
|
})
|
2017-12-08 12:03:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ref.Shape.Flattened || ref.Flattened {
|
|
|
|
tags = append(tags, ShapeTag{"flattened", "true"})
|
|
|
|
}
|
|
|
|
if ref.XMLAttribute {
|
|
|
|
tags = append(tags, ShapeTag{"xmlAttribute", "true"})
|
|
|
|
}
|
|
|
|
if isRequired {
|
|
|
|
tags = append(tags, ShapeTag{"required", "true"})
|
|
|
|
}
|
|
|
|
if ref.Shape.IsEnum() {
|
|
|
|
tags = append(tags, ShapeTag{"enum", ref.ShapeName})
|
|
|
|
}
|
|
|
|
|
|
|
|
if toplevel {
|
2019-01-21 14:27:20 +00:00
|
|
|
if name := ref.Shape.PayloadRefName(); len(name) > 0 {
|
|
|
|
tags = append(tags, ShapeTag{"payload", name})
|
2017-12-08 12:03:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ref.XMLNamespace.Prefix != "" {
|
|
|
|
tags = append(tags, ShapeTag{"xmlPrefix", ref.XMLNamespace.Prefix})
|
|
|
|
} else if ref.Shape.XMLNamespace.Prefix != "" {
|
|
|
|
tags = append(tags, ShapeTag{"xmlPrefix", ref.Shape.XMLNamespace.Prefix})
|
|
|
|
}
|
|
|
|
|
|
|
|
if ref.XMLNamespace.URI != "" {
|
|
|
|
tags = append(tags, ShapeTag{"xmlURI", ref.XMLNamespace.URI})
|
|
|
|
} else if ref.Shape.XMLNamespace.URI != "" {
|
|
|
|
tags = append(tags, ShapeTag{"xmlURI", ref.Shape.XMLNamespace.URI})
|
|
|
|
}
|
|
|
|
|
|
|
|
if ref.IdempotencyToken || ref.Shape.IdempotencyToken {
|
|
|
|
tags = append(tags, ShapeTag{"idempotencyToken", "true"})
|
|
|
|
}
|
|
|
|
|
|
|
|
if ref.Ignore {
|
|
|
|
tags = append(tags, ShapeTag{"ignore", "true"})
|
|
|
|
}
|
|
|
|
|
2019-01-21 14:27:20 +00:00
|
|
|
if ref.Shape.Sensitive {
|
|
|
|
tags = append(tags, ShapeTag{"sensitive", "true"})
|
|
|
|
}
|
|
|
|
|
2017-12-08 12:03:10 +00:00
|
|
|
return fmt.Sprintf("`%s`", tags)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Docstring returns the godocs formated documentation
|
|
|
|
func (ref *ShapeRef) Docstring() string {
|
|
|
|
if ref.Documentation != "" {
|
|
|
|
return strings.Trim(ref.Documentation, "\n ")
|
|
|
|
}
|
|
|
|
return ref.Shape.Docstring()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Docstring returns the godocs formated documentation
|
|
|
|
func (s *Shape) Docstring() string {
|
|
|
|
return strings.Trim(s.Documentation, "\n ")
|
|
|
|
}
|
|
|
|
|
|
|
|
// IndentedDocstring is the indented form of the doc string.
|
|
|
|
func (ref *ShapeRef) IndentedDocstring() string {
|
|
|
|
doc := ref.Docstring()
|
|
|
|
return strings.Replace(doc, "// ", "// ", -1)
|
|
|
|
}
|
|
|
|
|
|
|
|
var goCodeStringerTmpl = template.Must(template.New("goCodeStringerTmpl").Parse(`
|
|
|
|
// String returns the string representation
|
|
|
|
func (s {{ .ShapeName }}) String() string {
|
|
|
|
return awsutil.Prettify(s)
|
|
|
|
}
|
|
|
|
// GoString returns the string representation
|
|
|
|
func (s {{ .ShapeName }}) GoString() string {
|
|
|
|
return s.String()
|
|
|
|
}
|
|
|
|
`))
|
|
|
|
|
|
|
|
// GoCodeStringers renders the Stringers for API input/output shapes
|
|
|
|
func (s *Shape) GoCodeStringers() string {
|
|
|
|
w := bytes.Buffer{}
|
|
|
|
if err := goCodeStringerTmpl.Execute(&w, s); err != nil {
|
|
|
|
panic(fmt.Sprintln("Unexpected error executing GoCodeStringers template", err))
|
|
|
|
}
|
|
|
|
|
|
|
|
return w.String()
|
|
|
|
}
|
|
|
|
|
|
|
|
var enumStrip = regexp.MustCompile(`[^a-zA-Z0-9_:\./-]`)
|
|
|
|
var enumDelims = regexp.MustCompile(`[-_:\./]+`)
|
|
|
|
var enumCamelCase = regexp.MustCompile(`([a-z])([A-Z])`)
|
|
|
|
|
|
|
|
// EnumName returns the Nth enum in the shapes Enum list
|
|
|
|
func (s *Shape) EnumName(n int) string {
|
|
|
|
enum := s.Enum[n]
|
|
|
|
enum = enumStrip.ReplaceAllLiteralString(enum, "")
|
|
|
|
enum = enumCamelCase.ReplaceAllString(enum, "$1-$2")
|
|
|
|
parts := enumDelims.Split(enum, -1)
|
|
|
|
for i, v := range parts {
|
|
|
|
v = strings.ToLower(v)
|
|
|
|
parts[i] = ""
|
|
|
|
if len(v) > 0 {
|
|
|
|
parts[i] = strings.ToUpper(v[0:1])
|
|
|
|
}
|
|
|
|
if len(v) > 1 {
|
|
|
|
parts[i] += v[1:]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
enum = strings.Join(parts, "")
|
|
|
|
enum = strings.ToUpper(enum[0:1]) + enum[1:]
|
|
|
|
return enum
|
|
|
|
}
|
|
|
|
|
|
|
|
// NestedShape returns the shape pointer value for the shape which is nested
|
|
|
|
// under the current shape. If the shape is not nested nil will be returned.
|
|
|
|
//
|
|
|
|
// strucutures, the current shape is returned
|
|
|
|
// map: the value shape of the map is returned
|
|
|
|
// list: the element shape of the list is returned
|
|
|
|
func (s *Shape) NestedShape() *Shape {
|
|
|
|
var nestedShape *Shape
|
|
|
|
switch s.Type {
|
|
|
|
case "structure":
|
|
|
|
nestedShape = s
|
|
|
|
case "map":
|
|
|
|
nestedShape = s.ValueRef.Shape
|
|
|
|
case "list":
|
|
|
|
nestedShape = s.MemberRef.Shape
|
|
|
|
}
|
|
|
|
|
|
|
|
return nestedShape
|
|
|
|
}
|
|
|
|
|
2019-01-21 14:27:20 +00:00
|
|
|
var structShapeTmpl = func() *template.Template {
|
|
|
|
shapeTmpl := template.Must(
|
|
|
|
template.New("structShapeTmpl").
|
|
|
|
Funcs(template.FuncMap{
|
|
|
|
"GetCrosslinkURL": GetCrosslinkURL,
|
|
|
|
"GetDeprecatedMsg": getDeprecatedMessage,
|
|
|
|
}).
|
|
|
|
Parse(structShapeTmplDef),
|
|
|
|
)
|
|
|
|
|
|
|
|
template.Must(
|
|
|
|
shapeTmpl.AddParseTree(
|
|
|
|
"eventStreamAPILoopMethodTmpl", eventStreamAPILoopMethodTmpl.Tree),
|
|
|
|
)
|
|
|
|
|
|
|
|
template.Must(
|
|
|
|
shapeTmpl.AddParseTree(
|
|
|
|
"eventStreamEventShapeTmpl", eventStreamEventShapeTmpl.Tree),
|
|
|
|
)
|
|
|
|
template.Must(
|
|
|
|
shapeTmpl.AddParseTree(
|
|
|
|
"eventStreamExceptionEventShapeTmpl",
|
|
|
|
eventStreamExceptionEventShapeTmpl.Tree),
|
|
|
|
)
|
|
|
|
shapeTmpl.Funcs(eventStreamEventShapeTmplFuncs)
|
|
|
|
|
|
|
|
template.Must(
|
|
|
|
shapeTmpl.AddParseTree(
|
|
|
|
"hostLabelsShapeTmpl",
|
|
|
|
hostLabelsShapeTmpl.Tree),
|
|
|
|
)
|
|
|
|
|
|
|
|
return shapeTmpl
|
|
|
|
}()
|
|
|
|
|
|
|
|
const structShapeTmplDef = `
|
2017-12-08 12:03:10 +00:00
|
|
|
{{ .Docstring }}
|
2019-01-21 14:27:20 +00:00
|
|
|
{{ if .Deprecated -}}
|
|
|
|
{{ if .Docstring -}}
|
|
|
|
//
|
2017-12-08 12:03:10 +00:00
|
|
|
{{ end -}}
|
2019-01-21 14:27:20 +00:00
|
|
|
// Deprecated: {{ GetDeprecatedMsg .DeprecatedMsg .ShapeName }}
|
2017-12-08 12:03:10 +00:00
|
|
|
{{ end -}}
|
|
|
|
{{ $context := . -}}
|
|
|
|
type {{ .ShapeName }} struct {
|
|
|
|
_ struct{} {{ .GoTags true false }}
|
|
|
|
|
|
|
|
{{ range $_, $name := $context.MemberNames -}}
|
|
|
|
{{ $elem := index $context.MemberRefs $name -}}
|
|
|
|
{{ $isBlob := $context.WillRefBeBase64Encoded $name -}}
|
|
|
|
{{ $isRequired := $context.IsRequired $name -}}
|
|
|
|
{{ $doc := $elem.Docstring -}}
|
|
|
|
|
|
|
|
{{ if $doc -}}
|
|
|
|
{{ $doc }}
|
2019-01-21 14:27:20 +00:00
|
|
|
{{ if $elem.Deprecated -}}
|
|
|
|
//
|
|
|
|
// Deprecated: {{ GetDeprecatedMsg $elem.DeprecatedMsg $name }}
|
|
|
|
{{ end -}}
|
2017-12-08 12:03:10 +00:00
|
|
|
{{ end -}}
|
|
|
|
{{ if $isBlob -}}
|
|
|
|
{{ if $doc -}}
|
|
|
|
//
|
|
|
|
{{ end -}}
|
|
|
|
// {{ $name }} is automatically base64 encoded/decoded by the SDK.
|
|
|
|
{{ end -}}
|
|
|
|
{{ if $isRequired -}}
|
|
|
|
{{ if or $doc $isBlob -}}
|
|
|
|
//
|
|
|
|
{{ end -}}
|
|
|
|
// {{ $name }} is a required field
|
|
|
|
{{ end -}}
|
|
|
|
{{ $name }} {{ $context.GoStructType $name $elem }} {{ $elem.GoTags false $isRequired }}
|
|
|
|
|
|
|
|
{{ end }}
|
|
|
|
}
|
|
|
|
{{ if not .API.NoStringerMethods }}
|
|
|
|
{{ .GoCodeStringers }}
|
|
|
|
{{ end }}
|
2019-01-21 14:27:20 +00:00
|
|
|
{{ if not (or .API.NoValidataShapeMethods .Exception) }}
|
2017-12-08 12:03:10 +00:00
|
|
|
{{ if .Validations -}}
|
|
|
|
{{ .Validations.GoCode . }}
|
|
|
|
{{ end }}
|
|
|
|
{{ end }}
|
|
|
|
|
2019-01-21 14:27:20 +00:00
|
|
|
{{ if not (or .API.NoGenStructFieldAccessors .Exception) }}
|
|
|
|
{{ $builderShapeName := print .ShapeName -}}
|
|
|
|
{{ range $_, $name := $context.MemberNames -}}
|
|
|
|
{{ $elem := index $context.MemberRefs $name -}}
|
|
|
|
|
|
|
|
// Set{{ $name }} sets the {{ $name }} field's value.
|
|
|
|
func (s *{{ $builderShapeName }}) Set{{ $name }}(v {{ $context.GoStructValueType $name $elem }}) *{{ $builderShapeName }} {
|
|
|
|
{{ if $elem.UseIndirection -}}
|
|
|
|
s.{{ $name }} = &v
|
|
|
|
{{ else -}}
|
|
|
|
s.{{ $name }} = v
|
|
|
|
{{ end -}}
|
|
|
|
return s
|
|
|
|
}
|
2017-12-08 12:03:10 +00:00
|
|
|
|
2019-01-21 14:27:20 +00:00
|
|
|
{{ if $elem.GenerateGetter -}}
|
|
|
|
func (s *{{ $builderShapeName }}) get{{ $name }}() (v {{ $context.GoStructValueType $name $elem }}) {
|
|
|
|
{{ if $elem.UseIndirection -}}
|
|
|
|
if s.{{ $name }} == nil {
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
return *s.{{ $name }}
|
|
|
|
{{ else -}}
|
|
|
|
return s.{{ $name }}
|
|
|
|
{{ end -}}
|
|
|
|
}
|
|
|
|
{{- end }}
|
|
|
|
{{ end }}
|
|
|
|
{{ end }}
|
2017-12-08 12:03:10 +00:00
|
|
|
|
2019-01-21 14:27:20 +00:00
|
|
|
{{ if $.EventStreamsMemberName }}
|
|
|
|
{{ template "eventStreamAPILoopMethodTmpl" $ }}
|
|
|
|
{{ end }}
|
2017-12-08 12:03:10 +00:00
|
|
|
|
2019-01-21 14:27:20 +00:00
|
|
|
{{ if $.EventFor }}
|
|
|
|
{{ template "eventStreamEventShapeTmpl" $ }}
|
2017-12-08 12:03:10 +00:00
|
|
|
|
2019-01-21 14:27:20 +00:00
|
|
|
{{- if $.Exception }}
|
|
|
|
{{ template "eventStreamExceptionEventShapeTmpl" $ }}
|
2017-12-08 12:03:10 +00:00
|
|
|
{{ end -}}
|
|
|
|
{{ end }}
|
2019-01-21 14:27:20 +00:00
|
|
|
|
|
|
|
{{ if $.HasHostLabelMembers }}
|
|
|
|
{{ template "hostLabelsShapeTmpl" $ }}
|
2017-12-08 12:03:10 +00:00
|
|
|
{{ end }}
|
2019-01-21 14:27:20 +00:00
|
|
|
`
|
2017-12-08 12:03:10 +00:00
|
|
|
|
|
|
|
var enumShapeTmpl = template.Must(template.New("EnumShape").Parse(`
|
|
|
|
{{ .Docstring }}
|
|
|
|
const (
|
|
|
|
{{ $context := . -}}
|
|
|
|
{{ range $index, $elem := .Enum -}}
|
|
|
|
{{ $name := index $context.EnumConsts $index -}}
|
|
|
|
// {{ $name }} is a {{ $context.ShapeName }} enum value
|
|
|
|
{{ $name }} = "{{ $elem }}"
|
|
|
|
|
|
|
|
{{ end }}
|
|
|
|
)
|
|
|
|
`))
|
|
|
|
|
|
|
|
// GoCode returns the rendered Go code for the Shape.
|
|
|
|
func (s *Shape) GoCode() string {
|
2019-01-21 14:27:20 +00:00
|
|
|
w := &bytes.Buffer{}
|
2017-12-08 12:03:10 +00:00
|
|
|
|
|
|
|
switch {
|
2019-01-21 14:27:20 +00:00
|
|
|
case s.EventStreamAPI != nil:
|
|
|
|
if err := renderEventStreamAPIShape(w, s); err != nil {
|
|
|
|
panic(
|
|
|
|
fmt.Sprintf(
|
|
|
|
"failed to generate eventstream API shape, %s, %v",
|
|
|
|
s.ShapeName, err),
|
|
|
|
)
|
|
|
|
}
|
2017-12-08 12:03:10 +00:00
|
|
|
case s.Type == "structure":
|
2019-01-21 14:27:20 +00:00
|
|
|
if err := structShapeTmpl.Execute(w, s); err != nil {
|
|
|
|
panic(
|
|
|
|
fmt.Sprintf(
|
|
|
|
"Failed to generate struct shape %s, %v",
|
|
|
|
s.ShapeName, err),
|
|
|
|
)
|
2017-12-08 12:03:10 +00:00
|
|
|
}
|
|
|
|
case s.IsEnum():
|
2019-01-21 14:27:20 +00:00
|
|
|
if err := enumShapeTmpl.Execute(w, s); err != nil {
|
|
|
|
panic(
|
|
|
|
fmt.Sprintf(
|
|
|
|
"Failed to generate enum shape %s, %v",
|
|
|
|
s.ShapeName, err),
|
|
|
|
)
|
2017-12-08 12:03:10 +00:00
|
|
|
}
|
|
|
|
default:
|
|
|
|
panic(fmt.Sprintln("Cannot generate toplevel shape for", s.Type))
|
|
|
|
}
|
|
|
|
|
2019-01-21 14:27:20 +00:00
|
|
|
return w.String()
|
2017-12-08 12:03:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// IsEnum returns whether this shape is an enum list
|
|
|
|
func (s *Shape) IsEnum() bool {
|
|
|
|
return s.Type == "string" && len(s.Enum) > 0
|
|
|
|
}
|
|
|
|
|
2019-01-21 14:27:20 +00:00
|
|
|
// IsRequired returns if member is a required field. Required fields are fields
|
|
|
|
// marked as required, hostLabels, or location of uri path.
|
2017-12-08 12:03:10 +00:00
|
|
|
func (s *Shape) IsRequired(member string) bool {
|
2019-01-21 14:27:20 +00:00
|
|
|
ref, ok := s.MemberRefs[member]
|
|
|
|
if !ok {
|
|
|
|
panic(fmt.Sprintf(
|
|
|
|
"attempted to check required for unknown member, %s.%s",
|
|
|
|
s.ShapeName, member,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
if ref.IdempotencyToken || ref.Shape.IdempotencyToken {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if ref.Location == "uri" || ref.HostLabel {
|
|
|
|
return true
|
|
|
|
}
|
2017-12-08 12:03:10 +00:00
|
|
|
for _, n := range s.Required {
|
|
|
|
if n == member {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsInternal returns whether the shape was defined in this package
|
|
|
|
func (s *Shape) IsInternal() bool {
|
|
|
|
return s.resolvePkg == ""
|
|
|
|
}
|
|
|
|
|
|
|
|
// removeRef removes a shape reference from the list of references this
|
|
|
|
// shape is used in.
|
|
|
|
func (s *Shape) removeRef(ref *ShapeRef) {
|
|
|
|
r := s.refs
|
|
|
|
for i := 0; i < len(r); i++ {
|
|
|
|
if r[i] == ref {
|
|
|
|
j := i + 1
|
|
|
|
copy(r[i:], r[j:])
|
|
|
|
for k, n := len(r)-j+i, len(r); k < n; k++ {
|
|
|
|
r[k] = nil // free up the end of the list
|
|
|
|
} // for k
|
|
|
|
s.refs = r[:len(r)-j+i]
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Shape) WillRefBeBase64Encoded(refName string) bool {
|
|
|
|
payloadRefName := s.Payload
|
|
|
|
if payloadRefName == refName {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
ref, ok := s.MemberRefs[refName]
|
|
|
|
if !ok {
|
|
|
|
panic(fmt.Sprintf("shape %s does not contain %q refName", s.ShapeName, refName))
|
|
|
|
}
|
|
|
|
|
|
|
|
return ref.Shape.Type == "blob"
|
|
|
|
}
|
2019-01-21 14:27:20 +00:00
|
|
|
|
|
|
|
// Clone returns a cloned version of the shape with all references clones.
|
|
|
|
//
|
|
|
|
// Does not clone EventStream or Validate related values.
|
|
|
|
func (s *Shape) Clone(newName string) *Shape {
|
|
|
|
if s.AliasedShapeName {
|
|
|
|
panic(fmt.Sprintf("attempted to clone and rename %s, but flagged as aliased",
|
|
|
|
s.ShapeName))
|
|
|
|
}
|
|
|
|
|
|
|
|
n := new(Shape)
|
|
|
|
*n = *s
|
|
|
|
|
|
|
|
debugLogger.Logln("cloning", s.ShapeName, "to", newName)
|
|
|
|
|
|
|
|
n.MemberRefs = map[string]*ShapeRef{}
|
|
|
|
for k, r := range s.MemberRefs {
|
|
|
|
nr := new(ShapeRef)
|
|
|
|
*nr = *r
|
|
|
|
nr.Shape.refs = append(nr.Shape.refs, nr)
|
|
|
|
n.MemberRefs[k] = nr
|
|
|
|
}
|
|
|
|
|
|
|
|
if n.MemberRef.Shape != nil {
|
|
|
|
n.MemberRef.Shape.refs = append(n.MemberRef.Shape.refs, &n.MemberRef)
|
|
|
|
}
|
|
|
|
if n.KeyRef.Shape != nil {
|
|
|
|
n.KeyRef.Shape.refs = append(n.KeyRef.Shape.refs, &n.KeyRef)
|
|
|
|
}
|
|
|
|
if n.ValueRef.Shape != nil {
|
|
|
|
n.ValueRef.Shape.refs = append(n.ValueRef.Shape.refs, &n.ValueRef)
|
|
|
|
}
|
|
|
|
|
|
|
|
n.refs = []*ShapeRef{}
|
|
|
|
|
|
|
|
n.Required = append([]string{}, n.Required...)
|
|
|
|
n.Enum = append([]string{}, n.Enum...)
|
|
|
|
n.EnumConsts = append([]string{}, n.EnumConsts...)
|
|
|
|
|
|
|
|
n.OrigShapeName = n.ShapeName
|
|
|
|
n.API.Shapes[newName] = n
|
|
|
|
n.ShapeName = newName
|
|
|
|
|
|
|
|
return n
|
|
|
|
}
|