schema.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. package swag
  2. import (
  3. "errors"
  4. "fmt"
  5. "go/ast"
  6. "strings"
  7. "github.com/go-openapi/spec"
  8. )
  9. const (
  10. // ARRAY represent a array value.
  11. ARRAY = "array"
  12. // OBJECT represent a object value.
  13. OBJECT = "object"
  14. // PRIMITIVE represent a primitive value.
  15. PRIMITIVE = "primitive"
  16. // BOOLEAN represent a boolean value.
  17. BOOLEAN = "boolean"
  18. // INTEGER represent a integer value.
  19. INTEGER = "integer"
  20. // NUMBER represent a number value.
  21. NUMBER = "number"
  22. // STRING represent a string value.
  23. STRING = "string"
  24. // FUNC represent a function value.
  25. FUNC = "func"
  26. // ERROR represent a error value.
  27. ERROR = "error"
  28. // INTERFACE represent a interface value.
  29. INTERFACE = "interface{}"
  30. // ANY represent a any value.
  31. ANY = "any"
  32. // NIL represent a empty value.
  33. NIL = "nil"
  34. // IgnoreNameOverridePrefix Prepend to model to avoid renaming based on comment.
  35. IgnoreNameOverridePrefix = '$'
  36. )
  37. // CheckSchemaType checks if typeName is not a name of primitive type.
  38. func CheckSchemaType(typeName string) error {
  39. if !IsPrimitiveType(typeName) {
  40. return fmt.Errorf("%s is not basic types", typeName)
  41. }
  42. return nil
  43. }
  44. // IsSimplePrimitiveType determine whether the type name is a simple primitive type.
  45. func IsSimplePrimitiveType(typeName string) bool {
  46. switch typeName {
  47. case STRING, NUMBER, INTEGER, BOOLEAN:
  48. return true
  49. }
  50. return false
  51. }
  52. // IsPrimitiveType determine whether the type name is a primitive type.
  53. func IsPrimitiveType(typeName string) bool {
  54. switch typeName {
  55. case STRING, NUMBER, INTEGER, BOOLEAN, ARRAY, OBJECT, FUNC:
  56. return true
  57. }
  58. return false
  59. }
  60. // IsInterfaceLike determines whether the swagger type name is an go named interface type like error type.
  61. func IsInterfaceLike(typeName string) bool {
  62. return typeName == ERROR || typeName == ANY
  63. }
  64. // IsNumericType determines whether the swagger type name is a numeric type.
  65. func IsNumericType(typeName string) bool {
  66. return typeName == INTEGER || typeName == NUMBER
  67. }
  68. // TransToValidSchemeType indicates type will transfer golang basic type to swagger supported type.
  69. func TransToValidSchemeType(typeName string) string {
  70. switch typeName {
  71. case "uint", "int", "uint8", "int8", "uint16", "int16", "byte":
  72. return INTEGER
  73. case "uint32", "int32", "rune":
  74. return INTEGER
  75. case "uint64", "int64":
  76. return INTEGER
  77. case "float32", "float64":
  78. return NUMBER
  79. case "bool":
  80. return BOOLEAN
  81. case "string":
  82. return STRING
  83. }
  84. return typeName
  85. }
  86. // IsGolangPrimitiveType determine whether the type name is a golang primitive type.
  87. func IsGolangPrimitiveType(typeName string) bool {
  88. switch typeName {
  89. case "uint",
  90. "int",
  91. "uint8",
  92. "int8",
  93. "uint16",
  94. "int16",
  95. "byte",
  96. "uint32",
  97. "int32",
  98. "rune",
  99. "uint64",
  100. "int64",
  101. "float32",
  102. "float64",
  103. "bool",
  104. "string":
  105. return true
  106. }
  107. return false
  108. }
  109. // TransToValidCollectionFormat determine valid collection format.
  110. func TransToValidCollectionFormat(format string) string {
  111. switch format {
  112. case "csv", "multi", "pipes", "tsv", "ssv":
  113. return format
  114. }
  115. return ""
  116. }
  117. // TypeDocName get alias from comment '// @name ', otherwise the original type name to display in doc.
  118. func TypeDocName(pkgName string, spec *ast.TypeSpec) string {
  119. if spec != nil && !ignoreNameOverride(pkgName) {
  120. if spec.Comment != nil {
  121. for _, comment := range spec.Comment.List {
  122. texts := strings.Split(strings.TrimSpace(strings.TrimLeft(comment.Text, "/")), " ")
  123. if len(texts) > 1 && strings.ToLower(texts[0]) == "@name" {
  124. return texts[1]
  125. }
  126. }
  127. }
  128. if spec.Name != nil {
  129. return fullTypeName(strings.Split(pkgName, ".")[0], spec.Name.Name)
  130. }
  131. }
  132. if ignoreNameOverride(pkgName) {
  133. return pkgName[1:]
  134. }
  135. return pkgName
  136. }
  137. func ignoreNameOverride(name string) bool {
  138. return len(name) != 0 && name[0] == IgnoreNameOverridePrefix
  139. }
  140. // TypeDocNameFuncScoped get alias from comment '// @name ', otherwise the original type name to display in doc.
  141. func TypeDocNameFuncScoped(pkgName string, spec *ast.TypeSpec, fnName string) string {
  142. if spec != nil && !ignoreNameOverride(pkgName) {
  143. if spec.Comment != nil {
  144. for _, comment := range spec.Comment.List {
  145. texts := strings.Split(strings.TrimSpace(strings.TrimLeft(comment.Text, "/")), " ")
  146. if len(texts) > 1 && strings.ToLower(texts[0]) == "@name" {
  147. return texts[1]
  148. }
  149. }
  150. }
  151. if spec.Name != nil {
  152. return fullTypeNameFunctionScoped(strings.Split(pkgName, ".")[0], fnName, spec.Name.Name)
  153. }
  154. }
  155. if ignoreNameOverride(pkgName) {
  156. return pkgName[1:]
  157. }
  158. return pkgName
  159. }
  160. // RefSchema build a reference schema.
  161. func RefSchema(refType string) *spec.Schema {
  162. return spec.RefSchema("#/definitions/" + refType)
  163. }
  164. // PrimitiveSchema build a primitive schema.
  165. func PrimitiveSchema(refType string) *spec.Schema {
  166. return &spec.Schema{SchemaProps: spec.SchemaProps{Type: []string{refType}}}
  167. }
  168. // BuildCustomSchema build custom schema specified by tag swaggertype.
  169. func BuildCustomSchema(types []string) (*spec.Schema, error) {
  170. if len(types) == 0 {
  171. return nil, nil
  172. }
  173. switch types[0] {
  174. case PRIMITIVE:
  175. if len(types) == 1 {
  176. return nil, errors.New("need primitive type after primitive")
  177. }
  178. return BuildCustomSchema(types[1:])
  179. case ARRAY:
  180. if len(types) == 1 {
  181. return nil, errors.New("need array item type after array")
  182. }
  183. schema, err := BuildCustomSchema(types[1:])
  184. if err != nil {
  185. return nil, err
  186. }
  187. return spec.ArrayProperty(schema), nil
  188. case OBJECT:
  189. if len(types) == 1 {
  190. return PrimitiveSchema(types[0]), nil
  191. }
  192. schema, err := BuildCustomSchema(types[1:])
  193. if err != nil {
  194. return nil, err
  195. }
  196. return spec.MapProperty(schema), nil
  197. default:
  198. err := CheckSchemaType(types[0])
  199. if err != nil {
  200. return nil, err
  201. }
  202. return PrimitiveSchema(types[0]), nil
  203. }
  204. }