summary refs log tree commit diff
path: root/vendor/go.mau.fi/util/glob/glob.go
diff options
context:
space:
mode:
authorEmile <git@emile.space>2024-10-25 15:55:50 +0200
committerEmile <git@emile.space>2024-10-25 15:55:50 +0200
commitc90f36e3dd179d2de96f4f5fe38d8dc9a9de6dfe (patch)
tree89e9afb41c5bf76f48cfb09305a2d3db8d302b06 /vendor/go.mau.fi/util/glob/glob.go
parent98bbb0f559a8883bc47bae80607dbe326a448e61 (diff)
vendor HEAD main
Diffstat (limited to 'vendor/go.mau.fi/util/glob/glob.go')
-rw-r--r--vendor/go.mau.fi/util/glob/glob.go100
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))
+}