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
|
// Package glob implements very simple glob pattern matching used in various parts of the Matrix spec,
// such as push rules and moderation policy lists.
//
// See https://spec.matrix.org/v1.11/appendices/#glob-style-matching for more info.
package glob
import (
"strings"
)
type Glob interface {
Match(string) bool
}
var (
_ Glob = ExactGlob("")
_ Glob = PrefixGlob("")
_ Glob = SuffixGlob("")
_ Glob = ContainsGlob("")
_ Glob = (*PrefixAndSuffixGlob)(nil)
_ Glob = (*PrefixSuffixAndContainsGlob)(nil)
_ Glob = (*RegexGlob)(nil)
)
// Compile compiles a glob pattern into an object that can be used to efficiently match strings against the pattern.
//
// Simple globs will be converted into prefix/suffix/contains checks, while complicated ones will be compiled as regex.
func Compile(pattern string) Glob {
pattern = Simplify(pattern)
g := compileSimple(pattern)
if g != nil {
return g
}
g, _ = CompileRegex(pattern)
return g
}
// CompileWithImplicitContains is a wrapper for Compile which will replace exact matches with contains matches.
// i.e. if the pattern has no wildcards, it will be treated as if it was surrounded in asterisks (`foo` -> `*foo*`).
func CompileWithImplicitContains(pattern string) Glob {
g := Compile(pattern)
if _, isExact := g.(ExactGlob); isExact {
return ContainsGlob(pattern)
}
return g
}
// CompileSimple compiles a glob pattern into one of the non-regex forms.
//
// If the pattern can't be compiled into a simple form, it returns nil.
func CompileSimple(pattern string) Glob {
return compileSimple(Simplify(pattern))
}
func compileSimple(pattern string) Glob {
if strings.ContainsRune(pattern, '?') {
return nil
}
switch strings.Count(pattern, "*") {
case 0:
return ExactGlob(pattern)
case 1:
if strings.HasPrefix(pattern, "*") {
return SuffixGlob(pattern[1:])
} else if strings.HasSuffix(pattern, "*") {
return PrefixGlob(pattern[:len(pattern)-1])
} else {
parts := strings.Split(pattern, "*")
return PrefixAndSuffixGlob{
Prefix: parts[0],
Suffix: parts[1],
}
}
case 2:
if strings.HasPrefix(pattern, "*") && strings.HasSuffix(pattern, "*") {
return ContainsGlob(pattern[1 : len(pattern)-1])
}
parts := strings.Split(pattern, "*")
return PrefixSuffixAndContainsGlob{
Prefix: parts[0],
Contains: parts[1],
Suffix: parts[2],
}
default:
return nil
}
}
var sqlCompiler = strings.NewReplacer(
`\`, `\\`,
`%`, `\%`,
`_`, `\_`,
`*`, `%`,
`?`, `_`,
)
// ToSQL converts a Matrix glob pattern to a SQL LIKE pattern.
func ToSQL(pattern string) string {
return sqlCompiler.Replace(Simplify(pattern))
}
|