12
"github.com/aws/aws-sdk-go/private/util"
15
// A ShapeRef defines the usage of a shape within the API.
16
type ShapeRef struct {
18
Shape *Shape `json:"-"`
20
ShapeName string `json:"shape"`
29
IdempotencyToken bool `json:"idempotencyToken"`
30
Deprecated bool `json:"deprecated"`
33
// A XMLInfo defines URL and prefix for Shapes when rendered as XML
39
// A Shape defines the definition of a shape type
44
MemberRefs map[string]*ShapeRef `json:"members"`
45
MemberRef ShapeRef `json:"member"`
46
KeyRef ShapeRef `json:"key"`
47
ValueRef ShapeRef `json:"value"`
58
IdempotencyToken bool `json:"idempotencyToken"`
60
Min int // optional Minimum length (string, list) or value (number)
61
Max int // optional Minimum length (string, list) or value (number)
63
refs []*ShapeRef // References to this shape
64
resolvePkg string // use this package in the goType() if present
66
// Defines if the shape is a placeholder and should not be used directly
69
Deprecated bool `json:"deprecated"`
72
// Rename changes the name of the Shape to newName. Also updates
73
// the associated API's reference to use newName.
74
func (s *Shape) Rename(newName string) {
75
for _, r := range s.refs {
79
delete(s.API.Shapes, s.ShapeName)
80
s.API.Shapes[newName] = s
84
// MemberNames returns a slice of struct member names.
85
func (s *Shape) MemberNames() []string {
86
i, names := 0, make([]string, len(s.MemberRefs))
87
for n := range s.MemberRefs {
95
// GoTypeWithPkgName returns a shape's type as a string with the package name in
96
// <packageName>.<type> format. Package naming only applies to structures.
97
func (s *Shape) GoTypeWithPkgName() string {
98
return goType(s, true)
101
// GoType returns a shape's Go type
102
func (s *Shape) GoType() string {
103
return goType(s, false)
106
// GoType returns a shape ref's Go type.
107
func (ref *ShapeRef) GoType() string {
108
if ref.Shape == nil {
109
panic(fmt.Errorf("missing shape definition on reference for %#v", ref))
112
return ref.Shape.GoType()
115
// GoTypeWithPkgName returns a shape's type as a string with the package name in
116
// <packageName>.<type> format. Package naming only applies to structures.
117
func (ref *ShapeRef) GoTypeWithPkgName() string {
118
if ref.Shape == nil {
119
panic(fmt.Errorf("missing shape definition on reference for %#v", ref))
122
return ref.Shape.GoTypeWithPkgName()
125
// Returns a string version of the Shape's type.
126
// If withPkgName is true, the package name will be added as a prefix
127
func goType(s *Shape, withPkgName bool) string {
130
if withPkgName || s.resolvePkg != "" {
133
s.API.imports[pkg] = true
136
pkg = s.API.PackageName()
138
return fmt.Sprintf("*%s.%s", pkg, s.ShapeName)
140
return "*" + s.ShapeName
142
return "map[string]" + s.ValueRef.GoType()
144
return "[]" + s.MemberRef.GoType()
147
case "string", "character":
151
case "integer", "long":
153
case "float", "double":
156
s.API.imports["time"] = true
159
panic("Unsupported shape type: " + s.Type)
163
// GoTypeElem returns the Go type for the Shape. If the shape type is a pointer just
164
// the type will be returned minus the pointer *.
165
func (s *Shape) GoTypeElem() string {
167
if strings.HasPrefix(t, "*") {
173
// GoTypeElem returns the Go type for the Shape. If the shape type is a pointer just
174
// the type will be returned minus the pointer *.
175
func (ref *ShapeRef) GoTypeElem() string {
176
if ref.Shape == nil {
177
panic(fmt.Errorf("missing shape definition on reference for %#v", ref))
180
return ref.Shape.GoTypeElem()
183
// ShapeTag is a struct tag that will be applied to a shape's generated code
184
type ShapeTag struct {
188
// String returns the string representation of the shape tag
189
func (s ShapeTag) String() string {
190
return fmt.Sprintf(`%s:"%s"`, s.Key, s.Val)
193
// ShapeTags is a collection of shape tags and provides serialization of the
194
// tags in an ordered list.
195
type ShapeTags []ShapeTag
197
// Join returns an ordered serialization of the shape tags with the provided
199
func (s ShapeTags) Join(sep string) string {
201
for i, t := range s {
202
o.WriteString(t.String())
211
// String is an alias for Join with the empty space seperator.
212
func (s ShapeTags) String() string {
216
// GoTags returns the rendered tags string for the ShapeRef
217
func (ref *ShapeRef) GoTags(toplevel bool, isRequired bool) string {
220
if ref.Location != "" {
221
tags = append(tags, ShapeTag{"location", ref.Location})
222
} else if ref.Shape.Location != "" {
223
tags = append(tags, ShapeTag{"location", ref.Shape.Location})
226
if ref.LocationName != "" {
227
tags = append(tags, ShapeTag{"locationName", ref.LocationName})
228
} else if ref.Shape.LocationName != "" {
229
tags = append(tags, ShapeTag{"locationName", ref.Shape.LocationName})
232
if ref.QueryName != "" {
233
tags = append(tags, ShapeTag{"queryName", ref.QueryName})
235
if ref.Shape.MemberRef.LocationName != "" {
236
tags = append(tags, ShapeTag{"locationNameList", ref.Shape.MemberRef.LocationName})
238
if ref.Shape.KeyRef.LocationName != "" {
239
tags = append(tags, ShapeTag{"locationNameKey", ref.Shape.KeyRef.LocationName})
241
if ref.Shape.ValueRef.LocationName != "" {
242
tags = append(tags, ShapeTag{"locationNameValue", ref.Shape.ValueRef.LocationName})
244
if ref.Shape.Min > 0 {
245
tags = append(tags, ShapeTag{"min", fmt.Sprintf("%d", ref.Shape.Min)})
248
if ref.Deprecated || ref.Shape.Deprecated {
249
tags = append(tags, ShapeTag{"deprecated", "true"})
251
// All shapes have a type
252
tags = append(tags, ShapeTag{"type", ref.Shape.Type})
254
// embed the timestamp type for easier lookups
255
if ref.Shape.Type == "timestamp" {
256
t := ShapeTag{Key: "timestampFormat"}
257
if ref.Location == "header" {
260
switch ref.API.Metadata.Protocol {
261
case "json", "rest-json":
263
case "rest-xml", "ec2", "query":
267
tags = append(tags, t)
270
if ref.Shape.Flattened || ref.Flattened {
271
tags = append(tags, ShapeTag{"flattened", "true"})
273
if ref.XMLAttribute {
274
tags = append(tags, ShapeTag{"xmlAttribute", "true"})
277
tags = append(tags, ShapeTag{"required", "true"})
279
if ref.Shape.IsEnum() {
280
tags = append(tags, ShapeTag{"enum", ref.ShapeName})
284
if ref.Shape.Payload != "" {
285
tags = append(tags, ShapeTag{"payload", ref.Shape.Payload})
287
if ref.XMLNamespace.Prefix != "" {
288
tags = append(tags, ShapeTag{"xmlPrefix", ref.XMLNamespace.Prefix})
289
} else if ref.Shape.XMLNamespace.Prefix != "" {
290
tags = append(tags, ShapeTag{"xmlPrefix", ref.Shape.XMLNamespace.Prefix})
292
if ref.XMLNamespace.URI != "" {
293
tags = append(tags, ShapeTag{"xmlURI", ref.XMLNamespace.URI})
294
} else if ref.Shape.XMLNamespace.URI != "" {
295
tags = append(tags, ShapeTag{"xmlURI", ref.Shape.XMLNamespace.URI})
299
if ref.IdempotencyToken || ref.Shape.IdempotencyToken {
300
tags = append(tags, ShapeTag{"idempotencyToken", "true"})
303
return fmt.Sprintf("`%s`", tags)
306
// Docstring returns the godocs formated documentation
307
func (ref *ShapeRef) Docstring() string {
308
if ref.Documentation != "" {
309
return ref.Documentation
311
return ref.Shape.Docstring()
314
// Docstring returns the godocs formated documentation
315
func (s *Shape) Docstring() string {
316
return s.Documentation
319
var goCodeStringerTmpl = template.Must(template.New("goCodeStringerTmpl").Parse(`
320
// String returns the string representation
321
func (s {{ .ShapeName }}) String() string {
322
return awsutil.Prettify(s)
324
// GoString returns the string representation
325
func (s {{ .ShapeName }}) GoString() string {
330
func (s *Shape) goCodeStringers() string {
332
if err := goCodeStringerTmpl.Execute(&w, s); err != nil {
333
panic(fmt.Sprintln("Unexpected error executing goCodeStringers template", err))
339
var enumStrip = regexp.MustCompile(`[^a-zA-Z0-9_:\./-]`)
340
var enumDelims = regexp.MustCompile(`[-_:\./]+`)
341
var enumCamelCase = regexp.MustCompile(`([a-z])([A-Z])`)
343
// EnumName returns the Nth enum in the shapes Enum list
344
func (s *Shape) EnumName(n int) string {
346
enum = enumStrip.ReplaceAllLiteralString(enum, "")
347
enum = enumCamelCase.ReplaceAllString(enum, "$1-$2")
348
parts := enumDelims.Split(enum, -1)
349
for i, v := range parts {
350
v = strings.ToLower(v)
353
parts[i] = strings.ToUpper(v[0:1])
359
enum = strings.Join(parts, "")
360
enum = strings.ToUpper(enum[0:1]) + enum[1:]
364
// GoCode returns the rendered Go code for the Shape.
365
func (s *Shape) GoCode() string {
366
code := s.Docstring()
368
code += "type " + s.ShapeName + " "
372
case s.Type == "structure":
373
ref := &ShapeRef{ShapeName: s.ShapeName, API: s.API, Shape: s}
376
code += "_ struct{} " + ref.GoTags(true, false) + "\n\n"
377
for _, n := range s.MemberNames() {
379
code += m.Docstring()
380
if (m.Streaming || m.Shape.Streaming) && s.Payload == n {
381
rtype := "io.ReadSeeker"
383
rtype = "aws.ReaderSeekCloser"
384
} else if strings.HasSuffix(s.ShapeName, "Output") {
385
rtype = "io.ReadCloser"
388
s.API.imports["io"] = true
389
code += n + " " + rtype + " " + m.GoTags(false, s.IsRequired(n)) + "\n\n"
391
code += n + " " + m.GoType() + " " + m.GoTags(false, s.IsRequired(n)) + "\n\n"
396
if !s.API.NoStringerMethods {
397
code += s.goCodeStringers()
401
for n, e := range s.Enum {
402
code += fmt.Sprintf("\t// @enum %s\n\t%s = %q\n",
403
s.ShapeName, s.EnumConsts[n], e)
407
panic("Cannot generate toplevel shape for " + s.Type)
410
return util.GoFmt(code)
413
// IsEnum returns whether this shape is an enum list
414
func (s *Shape) IsEnum() bool {
415
return s.Type == "string" && len(s.Enum) > 0
418
// IsRequired returns if member is a required field.
419
func (s *Shape) IsRequired(member string) bool {
420
for _, n := range s.Required {
428
// IsInternal returns whether the shape was defined in this package
429
func (s *Shape) IsInternal() bool {
430
return s.resolvePkg == ""
433
// removeRef removes a shape reference from the list of references this
435
func (s *Shape) removeRef(ref *ShapeRef) {
437
for i := 0; i < len(r); i++ {
441
for k, n := len(r)-j+i, len(r); k < n; k++ {
442
r[k] = nil // free up the end of the list
444
s.refs = r[:len(r)-j+i]