macro

package
v12.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 17, 2023 License: BSD-3-Clause Imports: 13 Imported by: 4

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// String type
	// Allows anything (single path segment, as everything except the `Path`).
	// Its functions can be used by the rest of the macros and param types whenever not available function by name is used.
	// Because of its "master" boolean value to true (third parameter).
	String = NewMacro("string", "", true, false, nil).
			RegisterFunc("regexp", MustRegexp).
			RegisterFunc("prefix", func(prefix string) func(string) bool {
			return func(paramValue string) bool {
				return strings.HasPrefix(paramValue, prefix)
			}
		}).
		RegisterFunc("suffix", func(suffix string) func(string) bool {
			return func(paramValue string) bool {
				return strings.HasSuffix(paramValue, suffix)
			}
		}).
		RegisterFunc("contains", func(s string) func(string) bool {
			return func(paramValue string) bool {
				return strings.Contains(paramValue, s)
			}
		}).
		RegisterFunc("min", func(min int) func(string) bool {
			return func(paramValue string) bool {
				return len(paramValue) >= min
			}
		}).
		RegisterFunc("max", func(max int) func(string) bool {
			return func(paramValue string) bool {
				return max >= len(paramValue)
			}
		}).
		RegisterFunc("eq", func(s string) func(string) bool {
			return func(paramValue string) bool {
				return paramValue == s
			}
		}).
		RegisterFunc("eqor", func(texts []string) func(string) bool {
			if len(texts) == 1 {
				text := texts[0]
				return func(paramValue string) bool {
					return paramValue == text
				}
			}

			return func(paramValue string) bool {
				for _, s := range texts {
					if paramValue == s {
						return true
					}
				}

				return false
			}
		})

	// Int or number type
	// both positive and negative numbers, actual value can be min-max int64 or min-max int32 depends on the arch.
	// If x64: -9223372036854775808 to 9223372036854775807.
	// If x32: -2147483648 to 2147483647 and etc..
	Int = NewMacro("int", "number", false, false, func(paramValue string) (interface{}, bool) {
		v, err := strconv.Atoi(paramValue)
		if err != nil {
			return err, false
		}

		return v, true
	}).
		RegisterFunc("min", func(min int) func(int) bool {
			return func(paramValue int) bool {
				return paramValue >= min
			}
		}).
		RegisterFunc("max", func(max int) func(int) bool {
			return func(paramValue int) bool {
				return paramValue <= max
			}
		}).
		RegisterFunc("range", func(min, max int) func(int) bool {
			return func(paramValue int) bool {
				return !(paramValue < min || paramValue > max)
			}
		})

	// Int8 type
	// -128 to 127.
	Int8 = NewMacro("int8", "", false, false, func(paramValue string) (interface{}, bool) {
		v, err := strconv.ParseInt(paramValue, 10, 8)
		if err != nil {
			return err, false
		}
		return int8(v), true
	}).
		RegisterFunc("min", func(min int8) func(int8) bool {
			return func(paramValue int8) bool {
				return paramValue >= min
			}
		}).
		RegisterFunc("max", func(max int8) func(int8) bool {
			return func(paramValue int8) bool {
				return paramValue <= max
			}
		}).
		RegisterFunc("range", func(min, max int8) func(int8) bool {
			return func(paramValue int8) bool {
				return !(paramValue < min || paramValue > max)
			}
		})

	// Int16 type
	// -32768 to 32767.
	Int16 = NewMacro("int16", "", false, false, func(paramValue string) (interface{}, bool) {
		v, err := strconv.ParseInt(paramValue, 10, 16)
		if err != nil {
			return err, false
		}
		return int16(v), true
	}).
		RegisterFunc("min", func(min int16) func(int16) bool {
			return func(paramValue int16) bool {
				return paramValue >= min
			}
		}).
		RegisterFunc("max", func(max int16) func(int16) bool {
			return func(paramValue int16) bool {
				return paramValue <= max
			}
		}).
		RegisterFunc("range", func(min, max int16) func(int16) bool {
			return func(paramValue int16) bool {
				return !(paramValue < min || paramValue > max)
			}
		})

	// Int32 type
	// -2147483648 to 2147483647.
	Int32 = NewMacro("int32", "", false, false, func(paramValue string) (interface{}, bool) {
		v, err := strconv.ParseInt(paramValue, 10, 32)
		if err != nil {
			return err, false
		}
		return int32(v), true
	}).
		RegisterFunc("min", func(min int32) func(int32) bool {
			return func(paramValue int32) bool {
				return paramValue >= min
			}
		}).
		RegisterFunc("max", func(max int32) func(int32) bool {
			return func(paramValue int32) bool {
				return paramValue <= max
			}
		}).
		RegisterFunc("range", func(min, max int32) func(int32) bool {
			return func(paramValue int32) bool {
				return !(paramValue < min || paramValue > max)
			}
		})

	// Int64 as int64 type
	// -9223372036854775808 to 9223372036854775807.
	Int64 = NewMacro("int64", "long", false, false, func(paramValue string) (interface{}, bool) {
		v, err := strconv.ParseInt(paramValue, 10, 64)
		if err != nil {
			return err, false
		}
		return v, true
	}).
		RegisterFunc("min", func(min int64) func(int64) bool {
			return func(paramValue int64) bool {
				return paramValue >= min
			}
		}).
		RegisterFunc("max", func(max int64) func(int64) bool {
			return func(paramValue int64) bool {
				return paramValue <= max
			}
		}).
		RegisterFunc("range", func(min, max int64) func(int64) bool {
			return func(paramValue int64) bool {
				return !(paramValue < min || paramValue > max)
			}
		})

	// Uint as uint type
	// actual value can be min-max uint64 or min-max uint32 depends on the arch.
	// If x64: 0 to 18446744073709551615.
	// If x32: 0 to 4294967295 and etc.
	Uint = NewMacro("uint", "", false, false, func(paramValue string) (interface{}, bool) {
		v, err := strconv.ParseUint(paramValue, 10, strconv.IntSize)
		if err != nil {
			return err, false
		}
		return uint(v), true
	}).
		RegisterFunc("min", func(min uint) func(uint) bool {
			return func(paramValue uint) bool {
				return paramValue >= min
			}
		}).
		RegisterFunc("max", func(max uint) func(uint) bool {
			return func(paramValue uint) bool {
				return paramValue <= max
			}
		}).
		RegisterFunc("range", func(min, max uint) func(uint) bool {
			return func(paramValue uint) bool {
				return !(paramValue < min || paramValue > max)
			}
		})

	// Uint8 as uint8 type
	// 0 to 255.
	Uint8 = NewMacro("uint8", "", false, false, func(paramValue string) (interface{}, bool) {
		v, err := strconv.ParseUint(paramValue, 10, 8)
		if err != nil {
			return err, false
		}
		return uint8(v), true
	}).
		RegisterFunc("min", func(min uint8) func(uint8) bool {
			return func(paramValue uint8) bool {
				return paramValue >= min
			}
		}).
		RegisterFunc("max", func(max uint8) func(uint8) bool {
			return func(paramValue uint8) bool {
				return paramValue <= max
			}
		}).
		RegisterFunc("range", func(min, max uint8) func(uint8) bool {
			return func(paramValue uint8) bool {
				return !(paramValue < min || paramValue > max)
			}
		})

	// Uint16 as uint16 type
	// 0 to 65535.
	Uint16 = NewMacro("uint16", "", false, false, func(paramValue string) (interface{}, bool) {
		v, err := strconv.ParseUint(paramValue, 10, 16)
		if err != nil {
			return err, false
		}
		return uint16(v), true
	}).
		RegisterFunc("min", func(min uint16) func(uint16) bool {
			return func(paramValue uint16) bool {
				return paramValue >= min
			}
		}).
		RegisterFunc("max", func(max uint16) func(uint16) bool {
			return func(paramValue uint16) bool {
				return paramValue <= max
			}
		}).
		RegisterFunc("range", func(min, max uint16) func(uint16) bool {
			return func(paramValue uint16) bool {
				return !(paramValue < min || paramValue > max)
			}
		})

	// Uint32 as uint32 type
	// 0 to 4294967295.
	Uint32 = NewMacro("uint32", "", false, false, func(paramValue string) (interface{}, bool) {
		v, err := strconv.ParseUint(paramValue, 10, 32)
		if err != nil {
			return err, false
		}
		return uint32(v), true
	}).
		RegisterFunc("min", func(min uint32) func(uint32) bool {
			return func(paramValue uint32) bool {
				return paramValue >= min
			}
		}).
		RegisterFunc("max", func(max uint32) func(uint32) bool {
			return func(paramValue uint32) bool {
				return paramValue <= max
			}
		}).
		RegisterFunc("range", func(min, max uint32) func(uint32) bool {
			return func(paramValue uint32) bool {
				return !(paramValue < min || paramValue > max)
			}
		})

	// Uint64 as uint64 type
	// 0 to 18446744073709551615.
	Uint64 = NewMacro("uint64", "", false, false, func(paramValue string) (interface{}, bool) {
		v, err := strconv.ParseUint(paramValue, 10, 64)
		if err != nil {
			return err, false
		}
		return v, true
	}).
		RegisterFunc("min", func(min uint64) func(uint64) bool {
			return func(paramValue uint64) bool {
				return paramValue >= min
			}
		}).
		RegisterFunc("max", func(max uint64) func(uint64) bool {
			return func(paramValue uint64) bool {
				return paramValue <= max
			}
		}).
		RegisterFunc("range", func(min, max uint64) func(uint64) bool {
			return func(paramValue uint64) bool {
				return !(paramValue < min || paramValue > max)
			}
		})

	// Bool or boolean as bool type
	// a string which is "1" or "t" or "T" or "TRUE" or "true" or "True"
	// or "0" or "f" or "F" or "FALSE" or "false" or "False".
	Bool = NewMacro("bool", "boolean", false, false, func(paramValue string) (interface{}, bool) {

		v, err := strconv.ParseBool(paramValue)
		if err != nil {
			return err, false
		}
		return v, true
	})

	// ErrParamNotAlphabetical is fired when the parameter value is not an alphabetical text.
	ErrParamNotAlphabetical = errors.New("parameter is not alphabetical")

	// Alphabetical letter type
	// letters only (upper or lowercase)
	Alphabetical = NewMacro("alphabetical", "", false, false, func(paramValue string) (interface{}, bool) {
		if !alphabeticalEval(paramValue) {
			return fmt.Errorf("%s: %w", paramValue, ErrParamNotAlphabetical), false
		}
		return paramValue, true
	})

	// ErrParamNotFile is fired when the parameter value is not a form of a file.
	ErrParamNotFile = errors.New("parameter is not a file")

	// File type
	// letters (upper or lowercase)
	// numbers (0-9)
	// underscore (_)
	// dash (-)
	// point (.)
	// no spaces! or other character
	File = NewMacro("file", "", false, false, func(paramValue string) (interface{}, bool) {
		if !fileEval(paramValue) {
			return fmt.Errorf("%s: %w", paramValue, ErrParamNotFile), false
		}
		return paramValue, true
	})
	// Path type
	// anything, should be the last part
	//
	// It allows everything, we have String and Path as different
	// types because I want to give the opportunity to the user
	// to organise the macro functions based on wildcard or single dynamic named path parameter.
	// Should be living in the latest path segment of a route path.
	Path = NewMacro("path", "", false, true, nil)

	// UUID string type for validating a uuidv4 (and v1) path parameter.
	// Read more at: https://tools.ietf.org/html/rfc4122.
	UUID = NewMacro("uuid", "uuidv4", false, false, func(paramValue string) (interface{}, bool) {
		_, err := uuid.Parse(paramValue)
		if err != nil {
			return err, false
		}

		return paramValue, true
	})

	// Email string type for validating an e-mail path parameter. It returns the address as string, instead of an *mail.Address.
	// Read more at go std mail.ParseAddress method. See the ':email' path parameter for a more strictly version of validation.
	Mail = NewMacro("mail", "", false, false, func(paramValue string) (interface{}, bool) {
		_, err := mail.ParseAddress(paramValue)
		if err != nil {
			return fmt.Errorf("%s: %w", paramValue, err), false
		}

		return paramValue, true
	})

	// Email string type for validating an e-mail path parameter. It returns the address as string, instead of an *mail.Address.
	// It is a combined validation using mail.ParseAddress and net.LookupMX so only valid domains can be passed.
	// It's a more strictly version of the ':mail' path parameter.
	Email = NewMacro("email", "", false, false, func(paramValue string) (interface{}, bool) {
		_, err := mail.ParseAddress(paramValue)
		if err != nil {
			return fmt.Errorf("%s: %w", paramValue, err), false
		}

		domainPart := strings.Split(paramValue, "@")[1]

		mx, err := net.LookupMX(domainPart)
		if err != nil {
			return fmt.Errorf("%s: %w", paramValue, err), false
		}

		if len(mx) == 0 {
			return fmt.Errorf("%s: mx is empty", paramValue), false
		}

		return paramValue, true
	})

	// Date type.
	Date = NewMacro("date", "", false, true, func(paramValue string) (interface{}, bool) {
		tt, err := time.Parse(simpleDateLayout, paramValue)
		if err != nil {
			return fmt.Errorf("%s: %w", paramValue, err), false
		}

		return tt, true
	})

	// ErrParamNotWeekday is fired when the parameter value is not a form of a time.Weekday.
	ErrParamNotWeekday = errors.New("parameter is not a valid weekday")

	// Weekday type, returns a type of time.Weekday.
	// Valid values:
	// 0 to 7 (leading zeros don't matter)  or "Sunday" to "Monday" or "sunday" to "monday".
	Weekday = NewMacro("weekday", "", false, false, func(paramValue string) (interface{}, bool) {
		d, ok := longDayNames[paramValue]
		if !ok {

			n, err := strconv.Atoi(paramValue)
			if err != nil {
				return fmt.Errorf("%s: %w", paramValue, err), false
			}

			if n < 0 || n > 6 {
				return fmt.Errorf("%s: %w", paramValue, ErrParamNotWeekday), false
			}

			return time.Weekday(n), true
		}

		return d, true
	})

	// Defaults contains the defaults macro and parameters types for the router.
	//
	// Read https://github.com/kataras/iris/tree/master/_examples/routing/macros for more details.
	Defaults = &Macros{
		String,
		Int,
		Int8,
		Int16,
		Int32,
		Int64,
		Uint,
		Uint8,
		Uint16,
		Uint32,
		Uint64,
		Bool,
		Alphabetical,
		File,
		Path,
		UUID,
		Mail,
		Email,
		Date,
		Weekday,
	}
)

Functions

func CountParams added in v12.2.0

func CountParams(fullpath string, macros Macros) int

CountParams returns the length of the dynamic path's input parameters.

func MustRegexp

func MustRegexp(expr string) func(string) bool

MustRegexp same as Regexp but it panics on the "expr" parse failure.

func Regexp

func Regexp(expr string) (func(string) bool, error)

Regexp accepts a regexp "expr" expression and returns its MatchString. The regexp is compiled before return.

Returns a not-nil error on regexp compile failure.

Types

type Macro

type Macro struct {
	Evaluator ParamEvaluator
	// contains filtered or unexported fields
}

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.

func NewMacro

func NewMacro(indent, alias string, master, trailing bool, evaluator ParamEvaluator) *Macro

NewMacro creates and returns a Macro that can be used as a registry for a new customized parameter type and its functions.

func (*Macro) Alias

func (m *Macro) Alias() string

Alias returns the alias of the parameter type, if any.

func (*Macro) HandleError added in v12.2.0

func (m *Macro) HandleError(fnHandler interface{}) *Macro

HandleError registers a handler which will be executed when a parameter evaluator returns false and a non nil value which is a type of `error`. The "fnHandler" value MUST BE a type of `func(iris.Context, paramIndex int, err error)`, otherwise the program will receive a panic before server startup. The status code of the ErrCode (`else` literal) is set before the error handler but it can be modified inside the handler itself.

func (*Macro) Indent

func (m *Macro) Indent() string

Indent returns the name of the parameter type.

func (*Macro) Master

func (m *Macro) Master() bool

Master returns true if that macro's parameter type is the default one if not :type is followed by a parameter type inside the route path.

func (*Macro) RegisterFunc

func (m *Macro) RegisterFunc(funcName string, fn interface{}) *Macro

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 (*Macro) Trailing

func (m *Macro) Trailing() bool

Trailing returns true if that macro's parameter type is wildcard and can accept one or more path segments as one parameter value. A wildcard should be registered in the last path segment only.

type Macros

type Macros []*Macro

Macros is just a type of a slice of *Macro which is responsible to register and search for macros based on the indent(parameter type).

func (*Macros) Get

func (ms *Macros) Get(indentOrAlias string) *Macro

Get returns the responsible macro for a parameter type, it can return nil.

func (*Macros) GetMaster

func (ms *Macros) GetMaster() *Macro

GetMaster returns the default macro and its parameter type, by default it will return the `String` macro which is responsible for the "string" parameter type.

func (*Macros) GetTrailings

func (ms *Macros) GetTrailings() (macros []*Macro)

GetTrailings returns the macros that have support for wildcards parameter types. By default it will return the `Path` macro which is responsible for the "path" parameter type.

func (*Macros) Lookup

func (ms *Macros) Lookup(pt ast.ParamType) *Macro

Lookup returns the responsible macro for a parameter type, it can return nil.

func (*Macros) Register

func (ms *Macros) Register(indent, alias string, isMaster, isTrailing bool, evaluator ParamEvaluator) *Macro

Register registers a custom Macro. The "indent" should not be empty and should be unique, it is the parameter type's name, i.e "string". The "alias" is optionally and it should be unique, it is the alias of the parameter type. "isMaster" and "isTrailing" is for default parameter type and wildcard respectfully. The "evaluator" is the function that is converted to an Iris handler which is executed every time before the main chain of a route's handlers that contains this macro of the specific parameter type.

Read https://github.com/kataras/iris/tree/master/_examples/routing/macros for more details.

func (*Macros) SetErrorHandler added in v12.2.0

func (ms *Macros) SetErrorHandler(fnHandler interface{})

SetErrorHandler registers a common type path parameter error handler. The "fnHandler" MUST be a type of handler.ParamErrorHandler: func(ctx iris.Context, paramIndex int, err error). It calls the Macro.HandleError method for each of the "ms" entries.

func (*Macros) Unregister

func (ms *Macros) Unregister(indent string) bool

Unregister removes a macro and its parameter type from the list.

type ParamEvaluator

type ParamEvaluator func(paramValue string) (interface{}, bool)

ParamEvaluator is the signature for param type evaluator. It accepts the param's value as string and returns the <T> value (which its type is used for the input argument of the parameter functions, if any) and a true value for passed, otherwise nil and false should be returned.

type ParamFunc

type ParamFunc struct {
	Name string
	Func ParamFuncBuilder
}

ParamFunc represents the parsed parameter function, it holds the parameter's name and the function which will build the evaluator func.

type ParamFuncBuilder

type ParamFuncBuilder func([]string) reflect.Value // the func(<T>) bool

ParamFuncBuilder is a func which accepts a param function's arguments (values) and returns a function as value, its job is to make the macros to be registered by user at the most generic possible way.

type Template

type Template struct {
	// Src is the original template given by the client
	Src    string          `json:"src"`
	Params []TemplateParam `json:"params"`
}

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.

func Parse

func Parse(src string, macros Macros) (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 (*Template) IsTrailing

func (t *Template) IsTrailing() bool

IsTrailing reports whether this Template is a traling one.

type TemplateParam

type TemplateParam struct {
	Src string `json:"src"` // the unparsed param'false source
	// Type is not useful anywhere here but maybe
	// it's useful on host to decide how to convert the path template to specific router's syntax
	Type    ast.ParamType `json:"type"`
	Name    string        `json:"name"`
	Index   int           `json:"index"`
	ErrCode int           `json:"errCode"`
	// Note that, the value MUST BE a type of `handler.ParamErrorHandler`.
	HandleError interface{} `json:"-"` /* It's not an typed value because of import-cycle,
	// neither a special struct required, see `handler.MakeFilter`. */
	TypeEvaluator ParamEvaluator  `json:"-"`
	Funcs         []reflect.Value `json:"-"`
	// contains filtered or unexported fields
}

TemplateParam is the parsed macro parameter's template they are being used to describe the param's syntax result.

func (*TemplateParam) CanEval

func (p *TemplateParam) CanEval() bool

CanEval returns true if this "p" TemplateParam should be evaluated in serve time. It is computed before server ran and it is used to determinate if a route needs to build a macro handler (middleware).

func (*TemplateParam) Eval

func (p *TemplateParam) Eval(paramValue string) (interface{}, bool)

Eval is the most critical part of the TemplateParam. It is responsible to return the type-based value if passed otherwise nil. If the "paramValue" is the correct type of the registered parameter type and all functions, if any, are passed.

It is called from the converted macro handler (middleware) from the higher-level component of "kataras/iris/macro/handler#MakeHandler".

Directories

Path Synopsis
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 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.
interpreter
ast

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL