forked from swaggo/swag
-
Notifications
You must be signed in to change notification settings - Fork 0
/
property.go
139 lines (127 loc) · 4.96 KB
/
property.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package swag
import (
"errors"
"fmt"
"go/ast"
"strings"
)
// ErrFailedConvertPrimitiveType Failed to convert for swag to interpretable type
var ErrFailedConvertPrimitiveType = errors.New("swag property: failed convert primitive type")
type propertyName struct {
SchemaType string
ArrayType string
CrossPkg string
}
type propertyNewFunc func(schemeType string, crossPkg string) propertyName
func newArrayProperty(schemeType string, crossPkg string) propertyName {
return propertyName{
SchemaType: "array",
ArrayType: schemeType,
CrossPkg: crossPkg,
}
}
func newProperty(schemeType string, crossPkg string) propertyName {
return propertyName{
SchemaType: schemeType,
ArrayType: "string",
CrossPkg: crossPkg,
}
}
func convertFromSpecificToPrimitive(typeName string) (string, error) {
typeName = strings.ToUpper(typeName)
switch typeName {
case "TIME", "OBJECTID", "UUID":
return "string", nil
case "DECIMAL":
return "number", nil
}
return "", ErrFailedConvertPrimitiveType
}
func parseFieldSelectorExpr(astTypeSelectorExpr *ast.SelectorExpr, parser *Parser, propertyNewFunc propertyNewFunc) propertyName {
if primitiveType, err := convertFromSpecificToPrimitive(astTypeSelectorExpr.Sel.Name); err == nil {
return propertyNewFunc(primitiveType, "")
}
if pkgName, ok := astTypeSelectorExpr.X.(*ast.Ident); ok {
if typeDefinitions, ok := parser.TypeDefinitions[pkgName.Name][astTypeSelectorExpr.Sel.Name]; ok {
if expr, ok := typeDefinitions.Type.(*ast.SelectorExpr); ok {
if primitiveType, err := convertFromSpecificToPrimitive(expr.Sel.Name); err == nil {
return propertyNewFunc(primitiveType, "")
}
}
parser.ParseDefinition(pkgName.Name, astTypeSelectorExpr.Sel.Name, typeDefinitions)
return propertyNewFunc(astTypeSelectorExpr.Sel.Name, pkgName.Name)
}
if aliasedNames, ok := parser.ImportAliases[pkgName.Name]; ok {
for aliasedName := range aliasedNames {
if typeDefinitions, ok := parser.TypeDefinitions[aliasedName][astTypeSelectorExpr.Sel.Name]; ok {
if expr, ok := typeDefinitions.Type.(*ast.SelectorExpr); ok {
if primitiveType, err := convertFromSpecificToPrimitive(expr.Sel.Name); err == nil {
return propertyNewFunc(primitiveType, "")
}
}
parser.ParseDefinition(aliasedName, astTypeSelectorExpr.Sel.Name, typeDefinitions)
return propertyNewFunc(astTypeSelectorExpr.Sel.Name, aliasedName)
}
}
}
name := fmt.Sprintf("%s.%v", pkgName, astTypeSelectorExpr.Sel.Name)
if actualPrimitiveType, isCustomType := parser.CustomPrimitiveTypes[name]; isCustomType {
return propertyName{SchemaType: actualPrimitiveType, ArrayType: actualPrimitiveType}
}
}
return propertyName{SchemaType: "string", ArrayType: "string"}
}
// getPropertyName returns the string value for the given field if it exists
// allowedValues: array, boolean, integer, null, number, object, string
func getPropertyName(pkgName string, expr ast.Expr, parser *Parser) (propertyName, error) {
switch tp := expr.(type) {
case *ast.SelectorExpr:
return parseFieldSelectorExpr(tp, parser, newProperty), nil
case *ast.StarExpr:
return getPropertyName(pkgName, tp.X, parser)
case *ast.ArrayType:
return getArrayPropertyName(pkgName, tp.Elt, parser), nil
case *ast.MapType, *ast.StructType, *ast.InterfaceType:
return propertyName{SchemaType: "object", ArrayType: "object"}, nil
case *ast.FuncType:
return propertyName{SchemaType: "func", ArrayType: ""}, nil
case *ast.Ident:
name := tp.Name
// check if it is a custom type
if actualPrimitiveType, isCustomType := parser.CustomPrimitiveTypes[fullTypeName(pkgName, name)]; isCustomType {
return propertyName{SchemaType: actualPrimitiveType, ArrayType: actualPrimitiveType}, nil
}
name = TransToValidSchemeType(name)
return propertyName{SchemaType: name, ArrayType: name}, nil
default:
return propertyName{}, errors.New("not supported" + fmt.Sprint(expr))
}
}
func getArrayPropertyName(pkgName string, astTypeArrayElt ast.Expr, parser *Parser) propertyName {
switch elt := astTypeArrayElt.(type) {
case *ast.StructType, *ast.MapType, *ast.InterfaceType:
return propertyName{SchemaType: "array", ArrayType: "object"}
case *ast.ArrayType:
return propertyName{SchemaType: "array", ArrayType: "array"}
case *ast.StarExpr:
return getArrayPropertyName(pkgName, elt.X, parser)
case *ast.SelectorExpr:
return parseFieldSelectorExpr(elt, parser, newArrayProperty)
case *ast.Ident:
name := elt.Name
if actualPrimitiveType, isCustomType := parser.CustomPrimitiveTypes[fullTypeName(pkgName, name)]; isCustomType {
name = actualPrimitiveType
} else {
name = TransToValidSchemeType(elt.Name)
}
return propertyName{SchemaType: "array", ArrayType: name}
default:
name := fmt.Sprintf("%s", astTypeArrayElt)
if actualPrimitiveType, isCustomType := parser.CustomPrimitiveTypes[fullTypeName(pkgName, name)]; isCustomType {
name = actualPrimitiveType
} else {
name = TransToValidSchemeType(name)
}
return propertyName{SchemaType: "array", ArrayType: name}
}
}