diff options
Diffstat (limited to 'vendor/go.mau.fi/util/glob/glob.go')
-rw-r--r-- | vendor/go.mau.fi/util/glob/glob.go | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/vendor/go.mau.fi/util/glob/glob.go b/vendor/go.mau.fi/util/glob/glob.go new file mode 100644 index 0000000..67fce3e --- /dev/null +++ b/vendor/go.mau.fi/util/glob/glob.go @@ -0,0 +1,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)) +} |