forked from vikunja/vikunja
140 lines
5.0 KiB
Go
140 lines
5.0 KiB
Go
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}
|
|
}
|
|
}
|