-
-
Notifications
You must be signed in to change notification settings - Fork 282
Expand file tree
/
Copy pathfilters.go
More file actions
145 lines (119 loc) · 3.85 KB
/
filters.go
File metadata and controls
145 lines (119 loc) · 3.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package pongo2
import (
"fmt"
"maps"
)
// FilterFunction is the type filter functions must fulfil
type FilterFunction func(in *Value, param *Value) (out *Value, err error)
var builtinFilters = make(map[string]FilterFunction)
// copyFilters creates a shallow copy of a filter map.
func copyFilters(src map[string]FilterFunction) map[string]FilterFunction {
dst := make(map[string]FilterFunction, len(src))
maps.Copy(dst, src)
return dst
}
// BuiltinFilterExists returns true if the given filter is a built-in filter.
// Use TemplateSet.FilterExists to check filters in a specific template set.
func BuiltinFilterExists(name string) bool {
_, existing := builtinFilters[name]
return existing
}
// BuiltinTagExists returns true if the given tag is registered in builtinTags.
// Use TemplateSet.TagExists to check tags in a specific template set.
func BuiltinTagExists(name string) bool {
_, existing := builtinTags[name]
return existing
}
// registerFilterBuiltin registers a new filter to the global filter map.
// This is used during package initialization to register builtin filters.
func registerFilterBuiltin(name string, fn FilterFunction) error {
if BuiltinFilterExists(name) {
return fmt.Errorf("filter with name '%s' is already registered", name)
}
builtinFilters[name] = fn
return nil
}
// MustApplyFilter behaves like ApplyFilter, but panics on an error.
// This function uses builtinFilters. Use TemplateSet.MustApplyFilter for set-specific filters.
func MustApplyFilter(name string, value *Value, param *Value) *Value {
val, err := ApplyFilter(name, value, param)
if err != nil {
panic(err)
}
return val
}
// ApplyFilter applies a built-infilter to a given value using the given
// parameters. Returns a *pongo2.Value or an error. Use TemplateSet.ApplyFilter
// for set-specific filters.
func ApplyFilter(name string, value *Value, param *Value) (*Value, error) {
fn, existing := builtinFilters[name]
if !existing {
return nil, &Error{
Sender: "applyfilter",
OrigError: fmt.Errorf("filter with name '%s' not found", name),
}
}
// Make sure param is a *Value
if param == nil {
param = AsValue(nil)
}
return fn(value, param)
}
type filterCall struct {
token *Token
name string
parameter IEvaluator
filterFunc FilterFunction
}
func (fc *filterCall) Execute(v *Value, ctx *ExecutionContext) (*Value, error) {
var param *Value
var err error
if fc.parameter != nil {
param, err = fc.parameter.Evaluate(ctx)
if err != nil {
return nil, err
}
} else {
param = AsValue(nil)
}
filteredValue, err := fc.filterFunc(v, param)
if err != nil {
return nil, updateErrorToken(err, ctx.template, fc.token)
}
return filteredValue, nil
}
// Filter = IDENT | IDENT ":" FilterArg | IDENT "|" Filter
func (p *Parser) parseFilter() (*filterCall, error) {
identToken := p.MatchType(TokenIdentifier)
// Check filter ident
if identToken == nil {
return nil, p.Error("Filter name must be an identifier.", nil)
}
filter := &filterCall{
token: identToken,
name: identToken.Val,
}
// Check sandbox filter restriction
if _, isBanned := p.template.set.bannedFilters[identToken.Val]; isBanned {
return nil, p.Error(fmt.Sprintf("Usage of filter '%s' is not allowed (sandbox restriction active).", identToken.Val), identToken)
}
// Get the appropriate filter function and bind it
filterFn, exists := p.template.set.filters[identToken.Val]
if !exists {
return nil, p.Error(fmt.Sprintf("Filter '%s' does not exist.", identToken.Val), identToken)
}
filter.filterFunc = filterFn
// Check for filter-argument (2 tokens needed: ':' ARG)
if p.Match(TokenSymbol, ":") != nil {
if p.Peek(TokenSymbol, "}}") != nil {
return nil, p.Error("Filter parameter required after ':'.", nil)
}
// Get filter argument expression
v, err := p.parseVariableOrLiteral()
if err != nil {
return nil, err
}
filter.parameter = v
}
return filter, nil
}