mirror of
https://github.com/kataras/iris.git
synced 2025-01-24 11:11:03 +01:00
120 lines
2.6 KiB
Go
120 lines
2.6 KiB
Go
|
package methodfunc
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"fmt"
|
||
|
"strings"
|
||
|
"unicode"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
by = "By"
|
||
|
wildcard = "Wildcard"
|
||
|
paramName = "param"
|
||
|
)
|
||
|
|
||
|
type pathInfo struct {
|
||
|
GoParamType string
|
||
|
ParamType string
|
||
|
RelPath string
|
||
|
}
|
||
|
|
||
|
const (
|
||
|
paramTypeInt = "int"
|
||
|
paramTypeLong = "long"
|
||
|
paramTypeString = "string"
|
||
|
paramTypePath = "path"
|
||
|
)
|
||
|
|
||
|
var macroTypes = map[string]string{
|
||
|
"int": paramTypeInt,
|
||
|
"int64": paramTypeLong,
|
||
|
"string": paramTypeString,
|
||
|
// there is "path" param type but it's being captured "on-air"
|
||
|
// "file" param type is not supported by the current implementation, yet
|
||
|
// but if someone ask for it I'll implement it, it's easy.
|
||
|
}
|
||
|
|
||
|
func resolveRelativePath(info FuncInfo) (p pathInfo, ok bool) {
|
||
|
if info.Trailing == "" {
|
||
|
// it's valid
|
||
|
// it's just don't have a relative path,
|
||
|
// therefore p.RelPath will be empty, as we want.
|
||
|
return p, true
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
typ = info.Type
|
||
|
tr = info.Trailing
|
||
|
relPath = resolvePathFromFunc(tr)
|
||
|
|
||
|
goType, paramType string
|
||
|
)
|
||
|
|
||
|
byKeywordIdx := strings.LastIndex(tr, by)
|
||
|
if byKeywordIdx != -1 && typ.NumIn() == 2 { // first is the struct receiver.
|
||
|
funcPath := tr[0:byKeywordIdx] // remove the "By"
|
||
|
goType = typ.In(1).Name()
|
||
|
afterBy := byKeywordIdx + len(by)
|
||
|
if len(tr) > afterBy {
|
||
|
if tr[afterBy:] == wildcard {
|
||
|
paramType = paramTypePath
|
||
|
} else {
|
||
|
// invalid syntax
|
||
|
return p, false
|
||
|
}
|
||
|
} else {
|
||
|
// it's not wildcard, so check base on our available macro types.
|
||
|
if paramType, ok = macroTypes[goType]; !ok {
|
||
|
// ivalid type
|
||
|
return p, false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// int and string are supported.
|
||
|
// as there is no way to get the parameter name
|
||
|
// we will use the "param" everywhere.
|
||
|
suffix := fmt.Sprintf("/{%s:%s}", paramName, paramType)
|
||
|
relPath = resolvePathFromFunc(funcPath) + suffix
|
||
|
}
|
||
|
|
||
|
// if GetSomething/PostSomething/PutSomething...
|
||
|
// we will not check for "Something" because we could
|
||
|
// occur unexpected behaviors to the existing users
|
||
|
// who using exported functions for controller's internal
|
||
|
// functionalities and not for serving a request path.
|
||
|
|
||
|
return pathInfo{
|
||
|
GoParamType: goType,
|
||
|
ParamType: paramType,
|
||
|
RelPath: relPath,
|
||
|
}, true
|
||
|
}
|
||
|
|
||
|
func resolvePathFromFunc(funcName string) string {
|
||
|
end := len(funcName)
|
||
|
start := -1
|
||
|
buf := &bytes.Buffer{}
|
||
|
|
||
|
for i, n := 0, end; i < n; i++ {
|
||
|
c := rune(funcName[i])
|
||
|
if unicode.IsUpper(c) {
|
||
|
// it doesn't count the last uppercase
|
||
|
if start != -1 {
|
||
|
end = i
|
||
|
s := "/" + strings.ToLower(funcName[start:end])
|
||
|
buf.WriteString(s)
|
||
|
}
|
||
|
start = i
|
||
|
continue
|
||
|
}
|
||
|
end = i + 1
|
||
|
}
|
||
|
|
||
|
if end > 0 && len(funcName) >= end {
|
||
|
buf.WriteString("/" + strings.ToLower(funcName[start:end]))
|
||
|
}
|
||
|
|
||
|
return buf.String()
|
||
|
}
|