// godef is the common implementation for both GoTypeDef and GoResDef. // The only difference between the two is how the type names for fields that refer to a media type // is generated: GoTypeDef uses the type name but GoResDef uses the underlying resource name if the // type is a media type that corresponds to the canonical representation of a resource. func godef(ds design.DataStructure, tabs int, jsonTags, inner, res bool) string { var buffer bytes.Buffer def := ds.Definition() t := def.Type switch actual := t.(type) { case design.Primitive: return GoTypeName(t, tabs) case *design.Array: return "[]" + godef(actual.ElemType, tabs, jsonTags, true, res) case *design.Hash: keyDef := godef(actual.KeyType, tabs, jsonTags, true, res) elemDef := godef(actual.ElemType, tabs, jsonTags, true, res) return fmt.Sprintf("map[%s]%s", keyDef, elemDef) case design.Object: if inner { buffer.WriteByte('*') } buffer.WriteString("struct {\n") keys := make([]string, len(actual)) i := 0 for n := range actual { keys[i] = n i++ } sort.Strings(keys) for _, name := range keys { WriteTabs(&buffer, tabs+1) typedef := godef(actual[name], tabs+1, jsonTags, true, res) fname := Goify(name, true) var tags string if jsonTags { var omit string if !def.IsRequired(name) { omit = ",omitempty" } tags = fmt.Sprintf(" `json:\"%s%s\"`", name, omit) } desc := actual[name].Description if desc != "" { desc = fmt.Sprintf("// %s\n", desc) } buffer.WriteString(fmt.Sprintf("%s%s %s%s\n", desc, fname, typedef, tags)) } WriteTabs(&buffer, tabs) buffer.WriteString("}") return buffer.String() case *design.UserTypeDefinition: name := GoTypeName(actual, tabs) if actual.Type.IsObject() { return "*" + name } return name case *design.MediaTypeDefinition: if res && actual.Resource != nil { return "*" + Goify(actual.Resource.Name, true) } name := GoTypeName(actual, tabs) if actual.Type.IsObject() { return "*" + name } return name default: panic("goa bug: unknown data structure type") } }
// GoTypeDef returns the Go code that defines a Go type which matches the data structure // definition (the part that comes after `type foo`). // versioned indicates whether the type is being referenced from a version package (true) or the // default package (false). // tabs is the number of tab character(s) used to tabulate the definition however the first // line is never indented. // jsonTags controls whether to produce json tags. func GoTypeDef(ds design.DataStructure, versioned bool, defPkg string, tabs int, jsonTags bool) string { var buffer bytes.Buffer def := ds.Definition() t := def.Type switch actual := t.(type) { case design.Primitive: return GoTypeName(t, nil, tabs) case *design.Array: d := GoTypeDef(actual.ElemType, versioned, defPkg, tabs, jsonTags) if actual.ElemType.Type.IsObject() { d = "*" + d } return "[]" + d case *design.Hash: keyDef := GoTypeDef(actual.KeyType, versioned, defPkg, tabs, jsonTags) if actual.KeyType.Type.IsObject() { keyDef = "*" + keyDef } elemDef := GoTypeDef(actual.ElemType, versioned, defPkg, tabs, jsonTags) if actual.ElemType.Type.IsObject() { elemDef = "*" + elemDef } return fmt.Sprintf("map[%s]%s", keyDef, elemDef) case design.Object: buffer.WriteString("struct {\n") keys := make([]string, len(actual)) i := 0 for n := range actual { keys[i] = n i++ } sort.Strings(keys) for _, name := range keys { WriteTabs(&buffer, tabs+1) field := actual[name] typedef := GoTypeDef(field, versioned, defPkg, tabs+1, jsonTags) if field.Type.IsObject() || def.IsPrimitivePointer(name) { typedef = "*" + typedef } fname := Goify(name, true) var tags string if jsonTags { var omit string if !def.IsRequired(name) { omit = ",omitempty" } tags = fmt.Sprintf(" `json:\"%s%s\"`", name, omit) } desc := actual[name].Description if desc != "" { desc = fmt.Sprintf("// %s\n", desc) } buffer.WriteString(fmt.Sprintf("%s%s %s%s\n", desc, fname, typedef, tags)) } WriteTabs(&buffer, tabs) buffer.WriteString("}") return buffer.String() case *design.UserTypeDefinition: return GoPackageTypeName(actual, actual.AllRequired(), versioned, defPkg, tabs) case *design.MediaTypeDefinition: return GoPackageTypeName(actual, actual.AllRequired(), versioned, defPkg, tabs) default: panic("goa bug: unknown data structure type") } return GoTypeDef(ds, versioned, defPkg, tabs, jsonTags) }