Linting 🅰️

Former-commit-id: 367bb53ed6656002c60c40e3ad30bda578de21c6
This commit is contained in:
kataras 2017-06-12 04:47:16 +03:00
parent 74989ad0a1
commit fb85ae15d5
8 changed files with 148 additions and 69 deletions

View File

@ -73,7 +73,7 @@ type RoutesProvider interface { // api builder
// and child routers.
type APIBuilder struct {
// the api builder global macros registry
macros *macro.MacroMap
macros *macro.Map
// the api builder global handlers per status code registry (used for custom http errors)
errorCodeHandlers *ErrorCodeHandlers
// the api builder global routes repository
@ -181,7 +181,9 @@ func (rb *APIBuilder) Party(relativePath string, handlers ...context.Handler) Pa
// Macros returns the macro map which is responsible
// to register custom macro functions for all routes.
func (rb *APIBuilder) Macros() *macro.MacroMap {
//
// Learn more at: https://github.com/kataras/iris/tree/master/_examples/beginner/routing/dynamic-path
func (rb *APIBuilder) Macros() *macro.Map {
return rb.macros
}

View File

@ -17,8 +17,8 @@ import (
// defaultMacros returns a new macro map which
// contains the default router's named param types functions.
func defaultMacros() *macro.MacroMap {
macros := macro.NewMacroMap()
func defaultMacros() *macro.Map {
macros := macro.NewMap()
// registers the String and Int default macro funcs
// user can add or override of his own funcs later on
// i.e:
@ -31,7 +31,7 @@ func defaultMacros() *macro.MacroMap {
return macros
}
func registerBuiltinsMacroFuncs(out *macro.MacroMap) {
func registerBuiltinsMacroFuncs(out *macro.Map) {
// register the String which is the default type if not
// parameter type is specified or
// if a given parameter into path given but the func doesn't exist on the

View File

@ -9,19 +9,39 @@ import (
"strconv"
)
// ParamType is a specific uint8 type
// which holds the parameter types' type.
type ParamType uint8
const (
// ParamTypeUnExpected is an unexpected parameter type.
ParamTypeUnExpected ParamType = iota
// /myparam1
// ParamTypeString is the string type.
// If parameter type is missing then it defaults to String type.
// Allows anything
// Declaration: /mypath/{myparam:string} or /mypath{myparam}
ParamTypeString
// /42
// ParamTypeInt is the integer, a number type.
// Allows only numbers (0-9)
// Declaration: /mypath/{myparam:int}
ParamTypeInt
// /myparam
// ParamTypeAlphabetical is the alphabetical/letter type type.
// Allows letters only (upper or lowercase)
// Declaration: /mypath/{myparam:alphabetical}
ParamTypeAlphabetical
// /main.css
// ParamTypeFile is the file single path type.
// Allows:
// letters (upper or lowercase)
// numbers (0-9)
// underscore (_)
// dash (-)
// point (.)
// no spaces! or other character
// Declaration: /mypath/{myparam:file}
ParamTypeFile
// /myparam1/myparam2
// ParamTypePath is the multi path (or wildcard) type.
// Allows anything, should be the last part
// Declaration: /mypath/{myparam:path}
ParamTypePath
)
@ -38,6 +58,14 @@ var paramTypes = map[string]ParamType{
}
// LookupParamType accepts the string
// representation of a parameter type.
// Available:
// "string"
// "int"
// "alphabetical"
// "file"
// "path"
func LookupParamType(ident string) ParamType {
if typ, ok := paramTypes[ident]; ok {
return typ
@ -45,6 +73,14 @@ func LookupParamType(ident string) ParamType {
return ParamTypeUnExpected
}
// ParamStatement is a struct
// which holds all the necessary information about a macro parameter.
// It holds its type (string, int, alphabetical, file, path),
// its source ({param:type}),
// its name ("param"),
// its attached functions by the user (min, max...)
// and the http error code if that parameter
// failed to be evaluated.
type ParamStatement struct {
Src string // the original unparsed source, i.e: {id:int range(1,5) else 404}
Name string // id
@ -53,35 +89,11 @@ type ParamStatement struct {
ErrorCode int // 404
}
// ParamFuncArg represents a single parameter function's argument
type ParamFuncArg interface{}
func ParamFuncArgInt64(a ParamFuncArg) (int64, bool) {
if v, ok := a.(int64); ok {
return v, false
}
return -1, false
}
func ParamFuncArgToInt64(a ParamFuncArg) (int64, error) {
switch a.(type) {
case int64:
return a.(int64), nil
case string:
return strconv.ParseInt(a.(string), 10, 64)
case int:
return int64(a.(int)), nil
default:
return -1, fmt.Errorf("unexpected function argument type: %q", a)
}
}
func ParamFuncArgInt(a ParamFuncArg) (int, bool) {
if v, ok := a.(int); ok {
return v, false
}
return -1, false
}
// ParamFuncArgToInt converts and returns
// any type of "a", to an integer.
func ParamFuncArgToInt(a ParamFuncArg) (int, error) {
switch a.(type) {
case int:
@ -95,26 +107,13 @@ func ParamFuncArgToInt(a ParamFuncArg) (int, error) {
}
}
func ParamFuncArgString(a ParamFuncArg) (string, bool) {
if v, ok := a.(string); ok {
return v, false
}
return "", false
}
func ParamFuncArgToString(a ParamFuncArg) (string, error) {
switch a.(type) {
case string:
return a.(string), nil
case int:
return strconv.Itoa(a.(int)), nil
case int64:
return strconv.FormatInt(a.(int64), 10), nil
default:
return "", fmt.Errorf("unexpected function argument type: %q", a)
}
}
// ParamFunc holds the name of a parameter's function
// and its arguments (values)
// A param func is declared with:
// {param:int range(1,5)},
// the range is the
// param function name
// the 1 and 5 are the two param function arguments
// range(1,5)
type ParamFunc struct {
Name string // range

View File

@ -14,6 +14,9 @@ import (
"github.com/kataras/iris/core/router/macro/interpreter/token"
)
// Parse takes a route "fullpath"
// and returns its param statements
// and an error on failure.
func Parse(fullpath string) ([]*ast.ParamStatement, error) {
pathParts := strings.SplitN(fullpath, "/", -1)
p := new(ParamParser)
@ -45,20 +48,27 @@ func Parse(fullpath string) ([]*ast.ParamStatement, error) {
return statements, nil
}
// ParamParser is the parser
// which is being used by the Parse function
// to parse path segments one by one
// and return their parsed parameter statements (param name, param type its functions and the inline route's functions).
type ParamParser struct {
src string
errors []string
}
// NewParamParser receives a "src" of a single parameter
// and returns a new ParamParser, ready to Parse.
func NewParamParser(src string) *ParamParser {
p := new(ParamParser)
p.Reset(src)
return p
}
// Reset resets this ParamParser,
// reset the errors and set the source to the input "src".
func (p *ParamParser) Reset(src string) {
p.src = src
p.errors = []string{}
}
@ -66,8 +76,15 @@ func (p *ParamParser) appendErr(format string, a ...interface{}) {
p.errors = append(p.errors, fmt.Sprintf(format, a...))
}
const DefaultParamErrorCode = 404
const DefaultParamType = ast.ParamTypeString
const (
// DefaultParamErrorCode is the default http error code, 404 not found,
// per-parameter. An error code can be setted via
// the "else" keyword inside a route's path.
DefaultParamErrorCode = 404
// DefaultParamType when parameter type is missing use this param type, defaults to string
// and it should be remains unless earth split in two.
DefaultParamType = ast.ParamTypeString
)
func parseParamFuncArg(t token.Token) (a ast.ParamFuncArg, err error) {
if t.Type == token.INT {
@ -83,6 +100,8 @@ func (p ParamParser) Error() error {
return nil
}
// Parse parses the p.src and returns its param statement
// and an error on failure.
func (p *ParamParser) Parse() (*ast.ParamStatement, error) {
l := lexer.New(p.src)

View File

@ -129,7 +129,8 @@ func TestParseParam(t *testing.T) {
}}, // 7
}
var p *ParamParser = new(ParamParser)
p := new(ParamParser)
for i, tt := range tests {
p.Reset(tt.expectedStatement.Src)
resultStmt, err := p.Parse()

View File

@ -13,9 +13,16 @@ import (
"github.com/kataras/iris/core/router/macro/interpreter/ast"
)
// final evaluator signature for both param types and param funcs
// EvaluatorFunc is the signature for both param types and param funcs.
// It should accepts the param's value as string
// and return true if validated otherwise false.
type EvaluatorFunc func(paramValue string) bool
// NewEvaluatorFromRegexp accepts a regexp "expr" expression
// and returns an EvaluatorFunc based on that regexp.
// the regexp is compiled before return.
//
// Returns a not-nil error on regexp compile failure.
func NewEvaluatorFromRegexp(expr string) (EvaluatorFunc, error) {
if expr == "" {
return nil, fmt.Errorf("empty regex expression")
@ -34,6 +41,8 @@ func NewEvaluatorFromRegexp(expr string) (EvaluatorFunc, error) {
return r.MatchString, nil
}
// MustNewEvaluatorFromRegexp same as NewEvaluatorFromRegexp
// but it panics on the "expr" parse failure.
func MustNewEvaluatorFromRegexp(expr string) EvaluatorFunc {
r, err := NewEvaluatorFromRegexp(expr)
if err != nil {
@ -122,13 +131,34 @@ func convertBuilderFunc(fn interface{}) ParamEvaluatorBuilder {
}
type (
// Macro represents the parsed macro,
// which holds
// the evaluator (param type's evaluator + param functions evaluators)
// and its param functions.
//
// Any type contains its own macro
// instance, so an String type
// contains its type evaluator
// which is the "Evaluator" field
// and it can register param functions
// to that macro which maps to a parameter type.
Macro struct {
Evaluator EvaluatorFunc
funcs []ParamFunc
}
// ParamEvaluatorBuilder is a func
// which accepts a param function's arguments (values)
// and returns an EvaluatorFunc, its job
// is to make the macros to be registered
// by user at the most generic possible way.
ParamEvaluatorBuilder func([]ast.ParamFuncArg) EvaluatorFunc
// ParamFunc represents the parsed
// parameter function, it holds
// the parameter's name
// and the function which will build
// the evaluator func.
ParamFunc struct {
Name string
Func ParamEvaluatorBuilder
@ -139,7 +169,12 @@ func newMacro(evaluator EvaluatorFunc) *Macro {
return &Macro{Evaluator: evaluator}
}
// at boot time, per param
// RegisterFunc registers a parameter function
// to that macro.
// Accepts the func name ("range")
// and the function body, which should return an EvaluatorFunc
// a bool (it will be converted to EvaluatorFunc later on),
// i.e RegisterFunc("min", func(minValue int) func(paramValue string) bool){})
func (m *Macro) RegisterFunc(funcName string, fn interface{}) {
fullFn := convertBuilderFunc(fn)
m.registerFunc(funcName, fullFn)
@ -175,7 +210,10 @@ func (m *Macro) getFunc(funcName string) ParamEvaluatorBuilder {
return nil
}
type MacroMap struct {
// Map contains the default macros mapped to their types.
// This is the manager which is used by the caller to register custom
// parameter functions per param-type (String, Int, Alphabetical, File, Path).
type Map struct {
// string type
// anything
String *Macro
@ -198,8 +236,12 @@ type MacroMap struct {
Path *Macro
}
func NewMacroMap() *MacroMap {
return &MacroMap{
// NewMap returns a new macro Map with default
// type evaluators.
//
// Learn more at: https://github.com/kataras/iris/tree/master/_examples/beginner/routing/dynamic-path
func NewMap() *Map {
return &Map{
// it allows everything, so no need for a regexp here.
String: newMacro(func(string) bool { return true }),
Int: newMacro(MustNewEvaluatorFromRegexp("^[0-9]+$")),
@ -213,7 +255,11 @@ func NewMacroMap() *MacroMap {
}
}
func (m *MacroMap) Lookup(typ ast.ParamType) *Macro {
// Lookup returns the specific Macro from the map
// based on the parameter type.
// i.e if ast.ParamTypeInt then it will return the m.Int.
// Returns the m.String if not matched.
func (m *Map) Lookup(typ ast.ParamType) *Macro {
switch typ {
case ast.ParamTypeInt:
return m.Int

View File

@ -9,12 +9,20 @@ import (
"github.com/kataras/iris/core/router/macro/interpreter/parser"
)
// Template contains a route's path full parsed template.
//
// Fields:
// Src is the raw source of the path, i.e /users/{id:int min(1)}
// Params is the list of the Params that are being used to the
// path, i.e the min as param name and 1 as the param argument.
type Template struct {
// Src is the original template given by the client
Src string
Params []TemplateParam
}
// TemplateParam is the parsed macro parameter's template
// they are being used to describe the param's syntax result.
type TemplateParam struct {
Src string // the unparsed param'false source
// Type is not useful anywhere here but maybe
@ -26,7 +34,11 @@ type TemplateParam struct {
Funcs []EvaluatorFunc
}
func Parse(src string, macros *MacroMap) (*Template, error) {
// Parse takes a full route path and a macro map (macro map contains the macro types with their registered param functions)
// and returns a new Template.
// It builds all the parameter functions for that template
// and their evaluators, it's the api call that makes use the interpeter's parser -> lexer.
func Parse(src string, macros *Map) (*Template, error) {
params, err := parser.Parse(src)
if err != nil {
return nil, err

View File

@ -33,7 +33,7 @@ type Route struct {
// It parses the path based on the "macros",
// handlers are being changed to validate the macros at serve time, if needed.
func NewRoute(method, subdomain, unparsedPath string,
handlers context.Handlers, macros *macro.MacroMap) (*Route, error) {
handlers context.Handlers, macros *macro.Map) (*Route, error) {
tmpl, err := macro.Parse(unparsedPath, macros)
if err != nil {