mirror of
https://github.com/kataras/iris.git
synced 2025-03-13 21:36:28 +01:00
partial cleanup of the macro pkg and move it from /core/router to the root because it may be used by the end-developers now to ammend the available macros per application
Former-commit-id: 951a5e7a401af25ecaa904ff6463b0def2c87afb
This commit is contained in:
parent
bf880033cd
commit
6d9a35ddba
|
@ -294,7 +294,7 @@ For example: at [_examples/mvc/basic/main.go line 100](_examples/mvc/basic/main.
|
|||
|
||||
- fix `APIBuilder, Party#StaticWeb` and `APIBuilder, Party#StaticEmbedded` wrong strip prefix inside children parties
|
||||
- keep the `iris, core/router#StaticEmbeddedHandler` and remove the `core/router/APIBuilder#StaticEmbeddedHandler`, (note the `Handler` suffix) it's global and has nothing to do with the `Party` or the `APIBuilder`
|
||||
- fix high path cleaning between `{}` (we already escape those contents at the [interpreter](core/router/macro/interpreter) level but some symbols are still removed by the higher-level api builder) , i.e `\\` from the string's macro function `regex` contents as reported at [927](https://github.com/kataras/iris/issues/927) by [commit e85b113476eeefffbc7823297cc63cd152ebddfd](https://github.com/kataras/iris/commit/e85b113476eeefffbc7823297cc63cd152ebddfd)
|
||||
- fix high path cleaning between `{}` (we already escape those contents at the [interpreter](macro/interpreter) level but some symbols are still removed by the higher-level api builder) , i.e `\\` from the string's macro function `regex` contents as reported at [927](https://github.com/kataras/iris/issues/927) by [commit e85b113476eeefffbc7823297cc63cd152ebddfd](https://github.com/kataras/iris/commit/e85b113476eeefffbc7823297cc63cd152ebddfd)
|
||||
- sync the `golang.org/x/sys/unix` vendor
|
||||
|
||||
## The most important
|
||||
|
|
|
@ -83,7 +83,7 @@ For example: at [_examples/mvc/basic/main.go line 100](_examples/mvc/basic/main.
|
|||
|
||||
- fix `APIBuilder, Party#StaticWeb` and `APIBuilder, Party#StaticEmbedded` wrong strip prefix inside children parties
|
||||
- keep the `iris, core/router#StaticEmbeddedHandler` and remove the `core/router/APIBuilder#StaticEmbeddedHandler`, (note the `Handler` suffix) it's global and has nothing to do with the `Party` or the `APIBuilder`
|
||||
- fix high path cleaning between `{}` (we already escape those contents at the [interpreter](core/router/macro/interpreter) level but some symbols are still removed by the higher-level api builder) , i.e `\\` from the string's macro function `regex` contents as reported at [927](https://github.com/kataras/iris/issues/927) by [commit e85b113476eeefffbc7823297cc63cd152ebddfd](https://github.com/kataras/iris/commit/e85b113476eeefffbc7823297cc63cd152ebddfd)
|
||||
- fix high path cleaning between `{}` (we already escape those contents at the [interpreter](macro/interpreter) level but some symbols are still removed by the higher-level api builder) , i.e `\\` from the string's macro function `regex` contents as reported at [927](https://github.com/kataras/iris/issues/927) by [commit e85b113476eeefffbc7823297cc63cd152ebddfd](https://github.com/kataras/iris/commit/e85b113476eeefffbc7823297cc63cd152ebddfd)
|
||||
- sync the `golang.org/x/sys/unix` vendor
|
||||
|
||||
## The most important
|
||||
|
|
|
@ -79,7 +79,7 @@ This history entry is not translated yet to the Chinese language yet, please ref
|
|||
|
||||
- 修正 `APIBuilder, Party#StaticWeb` 和 `APIBuilder, Party#StaticEmbedded` 子分组内的前缀错误
|
||||
- 保留 `iris, core/router#StaticEmbeddedHandler` 并移除 `core/router/APIBuilder#StaticEmbeddedHandler`, (`Handler` 后缀) 这是全局性的,与 `Party` `APIBuilder` 无关。
|
||||
- 修正 路径 `{}` 中的路径清理 (我们已经在 [解释器](core/router/macro/interpreter) 级别转义了这些字符, 但是一些符号仍然被更高级别的API构建器删除) , 例如 `\\` 字符串的宏函数正则表达式内容 [927](https://github.com/kataras/iris/issues/927) by [commit e85b113476eeefffbc7823297cc63cd152ebddfd](https://github.com/kataras/iris/commit/e85b113476eeefffbc7823297cc63cd152ebddfd)
|
||||
- 修正 路径 `{}` 中的路径清理 (我们已经在 [解释器](macro/interpreter) 级别转义了这些字符, 但是一些符号仍然被更高级别的API构建器删除) , 例如 `\\` 字符串的宏函数正则表达式内容 [927](https://github.com/kataras/iris/issues/927) by [commit e85b113476eeefffbc7823297cc63cd152ebddfd](https://github.com/kataras/iris/commit/e85b113476eeefffbc7823297cc63cd152ebddfd)
|
||||
- 同步 `golang.org/x/sys/unix`
|
||||
|
||||
## 重要变更
|
||||
|
|
|
@ -83,7 +83,7 @@ func main() {
|
|||
ctx.Writef("myparam1: %s | myparam2: %s", myparam1, myparam2)
|
||||
})
|
||||
|
||||
app.Get("test_uint64/{myparam1:string}/{myparam2:uint64}", func(ctx context.Context) {
|
||||
app.Get("/test_uint64/{myparam1:string}/{myparam2:uint64}", func(ctx context.Context) {
|
||||
// works: ctx.Writef("Value of the parameter is: %s\n", ctx.Params().Get("myparam"))
|
||||
// but better and faster because the macro converts the string to uint64 automatically:
|
||||
println("type of myparam2 (should be uint64) is: " + reflect.ValueOf(ctx.Params().GetEntry("myparam2").ValueRaw).Kind().String())
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package context
|
||||
|
||||
import "github.com/kataras/iris/core/router/macro"
|
||||
import "github.com/kataras/iris/macro"
|
||||
|
||||
// RouteReadOnly allows decoupled access to the current route
|
||||
// inside the context.
|
||||
|
|
|
@ -15,6 +15,11 @@ import (
|
|||
)
|
||||
|
||||
type (
|
||||
// ValueSetter is the interface which can be accepted as a generic solution of RequestParams or memstore when Set is the only requirement,
|
||||
// i.e internally on macro/template/TemplateParam#Eval:paramChanger.
|
||||
ValueSetter interface {
|
||||
Set(key string, newValue interface{}) (Entry, bool)
|
||||
}
|
||||
// Entry is the entry of the context storage Store - .Values()
|
||||
Entry struct {
|
||||
Key string
|
||||
|
@ -26,6 +31,8 @@ type (
|
|||
Store []Entry
|
||||
)
|
||||
|
||||
var _ ValueSetter = (*Store)(nil)
|
||||
|
||||
// GetByKindOrNil will try to get this entry's value of "k" kind,
|
||||
// if value is not that kind it will NOT try to convert it the "k", instead
|
||||
// it will return nil, except if boolean; then it will return false
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/core/errors"
|
||||
"github.com/kataras/iris/core/router/macro"
|
||||
"github.com/kataras/iris/macro"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -1,98 +0,0 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/core/router/macro"
|
||||
"github.com/kataras/iris/core/router/macro/interpreter/ast"
|
||||
)
|
||||
|
||||
// compileRoutePathAndHandlers receives a route info and returns its parsed/"compiled" path
|
||||
// and the new handlers (prepend all the macro's handler, if any).
|
||||
//
|
||||
// It's not exported for direct use.
|
||||
func compileRoutePathAndHandlers(handlers context.Handlers, tmpl *macro.Template) (string, context.Handlers, error) {
|
||||
// parse the path to node's path, now.
|
||||
path, err := convertTmplToNodePath(tmpl)
|
||||
if err != nil {
|
||||
return tmpl.Src, handlers, err
|
||||
}
|
||||
// prepend the macro handler to the route, now,
|
||||
// right before the register to the tree, so routerbuilder.UseGlobal will work as expected.
|
||||
if len(tmpl.Params) > 0 {
|
||||
macroEvaluatorHandler := convertTmplToHandler(tmpl)
|
||||
// may return nil if no really need a macro handler evaluator
|
||||
if macroEvaluatorHandler != nil {
|
||||
handlers = append(context.Handlers{macroEvaluatorHandler}, handlers...)
|
||||
}
|
||||
}
|
||||
|
||||
return path, handlers, nil
|
||||
}
|
||||
|
||||
func convertTmplToNodePath(tmpl *macro.Template) (string, error) {
|
||||
routePath := tmpl.Src
|
||||
if len(tmpl.Params) > 0 {
|
||||
if routePath[len(routePath)-1] == '/' {
|
||||
routePath = routePath[0 : len(routePath)-2] // remove the last "/" if macro syntax instead of underline's
|
||||
}
|
||||
}
|
||||
|
||||
// if it has started with {} and it's valid
|
||||
// then the tmpl.Params will be filled,
|
||||
// so no any further check needed
|
||||
for i, p := range tmpl.Params {
|
||||
if ast.IsTrailing(p.Type) {
|
||||
if i != len(tmpl.Params)-1 {
|
||||
return "", fmt.Errorf("parameter type \"%s\" should be putted to the very last of a path", p.Type.Indent())
|
||||
}
|
||||
routePath = strings.Replace(routePath, p.Src, WildcardParam(p.Name), 1)
|
||||
} else {
|
||||
routePath = strings.Replace(routePath, p.Src, Param(p.Name), 1)
|
||||
}
|
||||
}
|
||||
|
||||
return routePath, nil
|
||||
}
|
||||
|
||||
// Note: returns nil if not needed, the caller(router) should check for that before adding that on route's Middleware.
|
||||
func convertTmplToHandler(tmpl *macro.Template) context.Handler {
|
||||
// check if we have params like: {name:string} or {name} or {anything:path} without else keyword or any functions used inside these params.
|
||||
// 1. if we don't have, then we don't need to add a handler before the main route's handler (as I said, no performance if macro is not really used)
|
||||
// 2. if we don't have any named params then we don't need a handler too.
|
||||
|
||||
needsMacroHandler := false
|
||||
for _, p := range tmpl.Params {
|
||||
if p.CanEval() {
|
||||
// if at least one needs it, then create the handler.
|
||||
needsMacroHandler = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !needsMacroHandler {
|
||||
// println("we don't need handler for: " + tmpl.Src)
|
||||
return nil
|
||||
}
|
||||
|
||||
return func(tmpl macro.Template) context.Handler {
|
||||
return func(ctx context.Context) {
|
||||
for _, p := range tmpl.Params {
|
||||
if !p.CanEval() {
|
||||
// println(p.Src + " no need to evaluate anything")
|
||||
continue // allow.
|
||||
}
|
||||
|
||||
if !p.Eval(ctx.Params().Get(p.Name), ctx.Params().Set) {
|
||||
ctx.StatusCode(p.ErrCode)
|
||||
ctx.StopExecution()
|
||||
return
|
||||
}
|
||||
}
|
||||
// if all passed, just continue.
|
||||
ctx.Next()
|
||||
}
|
||||
}(*tmpl)
|
||||
}
|
|
@ -3,7 +3,7 @@ package router
|
|||
import (
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/core/errors"
|
||||
"github.com/kataras/iris/core/router/macro"
|
||||
"github.com/kataras/iris/macro"
|
||||
)
|
||||
|
||||
// Party is just a group joiner of routes which have the same prefix and share same middleware(s) also.
|
||||
|
|
|
@ -7,7 +7,9 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/kataras/iris/core/netutil"
|
||||
"github.com/kataras/iris/core/router/macro/interpreter/lexer"
|
||||
"github.com/kataras/iris/macro"
|
||||
"github.com/kataras/iris/macro/interpreter/ast"
|
||||
"github.com/kataras/iris/macro/interpreter/lexer"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -31,6 +33,28 @@ func WildcardParam(name string) string {
|
|||
return prefix(name, WildcardParamStart)
|
||||
}
|
||||
|
||||
func convertTmplToNodePath(tmpl *macro.Template) string {
|
||||
routePath := tmpl.Src
|
||||
if len(tmpl.Params) > 0 {
|
||||
if routePath[len(routePath)-1] == '/' {
|
||||
routePath = routePath[0 : len(routePath)-2] // remove the last "/" if macro syntax instead of underline's.
|
||||
}
|
||||
}
|
||||
|
||||
// if it has started with {} and it's valid
|
||||
// then the tmpl.Params will be filled,
|
||||
// so no any further check needed.
|
||||
for _, p := range tmpl.Params {
|
||||
if ast.IsTrailing(p.Type) {
|
||||
routePath = strings.Replace(routePath, p.Src, WildcardParam(p.Name), 1)
|
||||
} else {
|
||||
routePath = strings.Replace(routePath, p.Src, Param(p.Name), 1)
|
||||
}
|
||||
}
|
||||
|
||||
return routePath
|
||||
}
|
||||
|
||||
func prefix(s string, prefix string) string {
|
||||
if !strings.HasPrefix(s, prefix) {
|
||||
return prefix + s
|
||||
|
|
|
@ -5,7 +5,8 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/core/router/macro"
|
||||
"github.com/kataras/iris/macro"
|
||||
"github.com/kataras/iris/macro/handler"
|
||||
)
|
||||
|
||||
// Route contains the information about a registered Route.
|
||||
|
@ -46,9 +47,11 @@ func NewRoute(method, subdomain, unparsedPath, mainHandlerName string,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
path, handlers, err := compileRoutePathAndHandlers(handlers, tmpl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
path := convertTmplToNodePath(tmpl)
|
||||
// prepend the macro handler to the route, now,
|
||||
// right before the register to the tree, so APIBuilder#UseGlobal will work as expected.
|
||||
if macroEvaluatorHandler, ok := handler.MakeHandler(tmpl); ok {
|
||||
handlers = append(context.Handlers{macroEvaluatorHandler}, handlers...)
|
||||
}
|
||||
|
||||
path = cleanPath(path) // maybe unnecessary here but who cares in this moment
|
||||
|
|
52
macro/handler/handler.go
Normal file
52
macro/handler/handler.go
Normal file
|
@ -0,0 +1,52 @@
|
|||
// Package handler is the highest level module of the macro package which makes use the rest of the macro package,
|
||||
// it is mainly used, internally, by the router package.
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/macro"
|
||||
)
|
||||
|
||||
// MakeHandler creates and returns a handler from a macro template, the handler evaluates each of the parameters if necessary at all.
|
||||
// If the template does not contain any dynamic attributes and a special handler is NOT required
|
||||
// then it returns a nil handler and false as its second output value,
|
||||
// the caller should check those two values before any further action.
|
||||
func MakeHandler(tmpl *macro.Template) (context.Handler, bool) {
|
||||
needsMacroHandler := len(tmpl.Params) > 0
|
||||
if !needsMacroHandler {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// check if we have params like: {name:string} or {name} or {anything:path} without else keyword or any functions used inside these params.
|
||||
// 1. if we don't have, then we don't need to add a handler before the main route's handler (as I said, no performance if macro is not really used)
|
||||
// 2. if we don't have any named params then we don't need a handler too.
|
||||
for _, p := range tmpl.Params {
|
||||
if p.CanEval() {
|
||||
// if at least one needs it, then create the handler.
|
||||
needsMacroHandler = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !needsMacroHandler {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
handler := func(ctx context.Context) {
|
||||
for _, p := range tmpl.Params {
|
||||
if !p.CanEval() {
|
||||
continue // allow.
|
||||
}
|
||||
|
||||
if !p.Eval(ctx.Params().Get(p.Name), ctx.Params()) {
|
||||
ctx.StatusCode(p.ErrCode)
|
||||
ctx.StopExecution()
|
||||
return
|
||||
}
|
||||
}
|
||||
// if all passed, just continue.
|
||||
ctx.Next()
|
||||
}
|
||||
|
||||
return handler, true
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package lexer
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris/core/router/macro/interpreter/token"
|
||||
"github.com/kataras/iris/macro/interpreter/token"
|
||||
)
|
||||
|
||||
// Lexer helps us to read/scan characters of a source and resolve their token types.
|
|
@ -3,7 +3,7 @@ package lexer
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris/core/router/macro/interpreter/token"
|
||||
"github.com/kataras/iris/macro/interpreter/token"
|
||||
)
|
||||
|
||||
func TestNextToken(t *testing.T) {
|
|
@ -5,9 +5,9 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/kataras/iris/core/router/macro/interpreter/ast"
|
||||
"github.com/kataras/iris/core/router/macro/interpreter/lexer"
|
||||
"github.com/kataras/iris/core/router/macro/interpreter/token"
|
||||
"github.com/kataras/iris/macro/interpreter/ast"
|
||||
"github.com/kataras/iris/macro/interpreter/lexer"
|
||||
"github.com/kataras/iris/macro/interpreter/token"
|
||||
)
|
||||
|
||||
// Parse takes a route "fullpath"
|
||||
|
@ -39,7 +39,7 @@ func Parse(fullpath string, paramTypes []ast.ParamType) ([]*ast.ParamStatement,
|
|||
}
|
||||
// if we have param type path but it's not the last path part
|
||||
if ast.IsTrailing(stmt.Type) && i < len(pathParts)-1 {
|
||||
return nil, fmt.Errorf("param type '%s' should be lived only inside the last path segment, but was inside: %s", stmt.Type, s)
|
||||
return nil, fmt.Errorf("%s: parameter type \"%s\" should be registered to the very last of a path", s, stmt.Type.Indent())
|
||||
}
|
||||
|
||||
statements = append(statements, stmt)
|
|
@ -6,7 +6,7 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris/core/router/macro/interpreter/ast"
|
||||
"github.com/kataras/iris/macro/interpreter/ast"
|
||||
)
|
||||
|
||||
type simpleParamType string
|
|
@ -4,7 +4,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/kataras/iris/core/router/macro/interpreter/ast"
|
||||
"github.com/kataras/iris/macro/interpreter/ast"
|
||||
)
|
||||
|
||||
var (
|
|
@ -1,11 +1,11 @@
|
|||
package macro
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris/core/memstore"
|
||||
"reflect"
|
||||
|
||||
"github.com/kataras/iris/core/router/macro/interpreter/ast"
|
||||
"github.com/kataras/iris/core/router/macro/interpreter/parser"
|
||||
"github.com/kataras/iris/core/memstore"
|
||||
"github.com/kataras/iris/macro/interpreter/ast"
|
||||
"github.com/kataras/iris/macro/interpreter/parser"
|
||||
)
|
||||
|
||||
// Template contains a route's path full parsed template.
|
||||
|
@ -59,7 +59,9 @@ func (p *TemplateParam) CanEval() bool {
|
|||
}
|
||||
|
||||
// paramChanger is the same form of context's Params().Set
|
||||
func (p *TemplateParam) Eval(paramValue string, paramChanger func(key string, newValue interface{}) (memstore.Entry, bool)) bool {
|
||||
// we could accept a memstore.Store or even context.RequestParams
|
||||
// but this form has been chosed in order to test easier and fully decoupled from a request when necessary.
|
||||
func (p *TemplateParam) Eval(paramValue string, paramChanger memstore.ValueSetter) bool {
|
||||
if p.TypeEvaluator == nil {
|
||||
for _, fn := range p.stringInFuncs {
|
||||
if !fn(paramValue) {
|
||||
|
@ -85,7 +87,7 @@ func (p *TemplateParam) Eval(paramValue string, paramChanger func(key string, ne
|
|||
}
|
||||
}
|
||||
|
||||
paramChanger(p.Name, newValue)
|
||||
paramChanger.Set(p.Name, newValue)
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -107,8 +109,8 @@ func Parse(src string, macros Macros) (*Template, error) {
|
|||
t.Src = src
|
||||
|
||||
for idx, p := range params {
|
||||
funcMap := macros.Lookup(p.Type)
|
||||
typEval := funcMap.Evaluator
|
||||
m := macros.Lookup(p.Type)
|
||||
typEval := m.Evaluator
|
||||
|
||||
tmplParam := TemplateParam{
|
||||
Src: p.Src,
|
||||
|
@ -120,7 +122,7 @@ func Parse(src string, macros Macros) (*Template, error) {
|
|||
}
|
||||
|
||||
for _, paramfn := range p.Funcs {
|
||||
tmplFn := funcMap.getFunc(paramfn.Name)
|
||||
tmplFn := m.getFunc(paramfn.Name)
|
||||
if tmplFn == nil { // if not find on this type, check for Master's which is for global funcs too.
|
||||
if m := macros.GetMaster(); m != nil {
|
||||
tmplFn = m.getFunc(paramfn.Name)
|
|
@ -7,9 +7,9 @@ import (
|
|||
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/core/router"
|
||||
"github.com/kataras/iris/core/router/macro"
|
||||
"github.com/kataras/iris/hero"
|
||||
"github.com/kataras/iris/hero/di"
|
||||
"github.com/kataras/iris/macro"
|
||||
|
||||
"github.com/kataras/golog"
|
||||
)
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"unicode"
|
||||
|
||||
"github.com/kataras/iris/core/router"
|
||||
"github.com/kataras/iris/core/router/macro"
|
||||
"github.com/kataras/iris/macro"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"reflect"
|
||||
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/core/router/macro"
|
||||
"github.com/kataras/iris/macro"
|
||||
)
|
||||
|
||||
func getPathParamsForInput(params []macro.TemplateParam, funcIn ...reflect.Type) (values []reflect.Value) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user