mirror of
https://github.com/yusing/godoxy.git
synced 2025-05-19 20:32:35 +02:00
feat(rules.on): support & as logical AND
This commit is contained in:
parent
ad60f377ba
commit
1c182b5a7d
2 changed files with 122 additions and 5 deletions
|
@ -2,6 +2,7 @@ package rules
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
|
@ -230,19 +231,80 @@ var checkers = map[string]struct {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var asciiSpace = [256]uint8{'\t': 1, '\n': 1, '\v': 1, '\f': 1, '\r': 1, ' ': 1}
|
||||||
|
var andSeps = [256]uint8{'&': 1, '\n': 1}
|
||||||
|
|
||||||
|
func indexAnd(s string) int {
|
||||||
|
for i, c := range s {
|
||||||
|
if andSeps[c] != 0 {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func countAnd(s string) int {
|
||||||
|
n := 0
|
||||||
|
for _, c := range s {
|
||||||
|
if andSeps[c] != 0 {
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
// splitAnd splits a string by "&" and "\n" with all spaces removed.
|
||||||
|
// empty strings are not included in the result.
|
||||||
|
func splitAnd(s string) []string {
|
||||||
|
if s == "" {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
n := countAnd(s)
|
||||||
|
a := make([]string, n+1)
|
||||||
|
i := 0
|
||||||
|
for i < n {
|
||||||
|
end := indexAnd(s)
|
||||||
|
if end == -1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
beg := 0
|
||||||
|
// trim leading spaces
|
||||||
|
for beg < end && asciiSpace[s[beg]] != 0 {
|
||||||
|
beg++
|
||||||
|
}
|
||||||
|
// trim trailing spaces
|
||||||
|
next := end + 1
|
||||||
|
for end-1 > beg && asciiSpace[s[end-1]] != 0 {
|
||||||
|
end--
|
||||||
|
}
|
||||||
|
// skip empty segments
|
||||||
|
if end > beg {
|
||||||
|
a[i] = s[beg:end]
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
s = s[next:]
|
||||||
|
}
|
||||||
|
s = strings.TrimSpace(s)
|
||||||
|
if s != "" {
|
||||||
|
a[i] = s
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return a[:i]
|
||||||
|
}
|
||||||
|
|
||||||
// Parse implements strutils.Parser.
|
// Parse implements strutils.Parser.
|
||||||
func (on *RuleOn) Parse(v string) error {
|
func (on *RuleOn) Parse(v string) error {
|
||||||
on.raw = v
|
on.raw = v
|
||||||
|
|
||||||
lines := strutils.SplitLine(v)
|
rules := splitAnd(v)
|
||||||
checkAnd := make(CheckMatchAll, 0, len(lines))
|
checkAnd := make(CheckMatchAll, 0, len(rules))
|
||||||
|
|
||||||
errs := gperr.NewBuilder("rule.on syntax errors")
|
errs := gperr.NewBuilder("rule.on syntax errors")
|
||||||
for i, line := range lines {
|
for i, rule := range rules {
|
||||||
if line == "" {
|
if rule == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
parsed, err := parseOn(line)
|
parsed, err := parseOn(rule)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs.Add(err.Subjectf("line %d", i+1))
|
errs.Add(err.Subjectf("line %d", i+1))
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -12,6 +12,61 @@ import (
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestSplitAnd(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input string
|
||||||
|
want []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
input: "",
|
||||||
|
want: []string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single",
|
||||||
|
input: "rule",
|
||||||
|
want: []string{"rule"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple",
|
||||||
|
input: "rule1 & rule2",
|
||||||
|
want: []string{"rule1", "rule2"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple_newline",
|
||||||
|
input: "rule1\n\nrule2",
|
||||||
|
want: []string{"rule1", "rule2"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple_newline_and",
|
||||||
|
input: "rule1\nrule2 & rule3",
|
||||||
|
want: []string{"rule1", "rule2", "rule3"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty segment",
|
||||||
|
input: "rule1\n& &rule2& rule3",
|
||||||
|
want: []string{"rule1", "rule2", "rule3"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "double_and",
|
||||||
|
input: "rule1\nrule2 && rule3",
|
||||||
|
want: []string{"rule1", "rule2", "rule3"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "spaces_around",
|
||||||
|
input: " rule1\nrule2 & rule3 ",
|
||||||
|
want: []string{"rule1", "rule2", "rule3"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got := splitAnd(tt.input)
|
||||||
|
ExpectEqual(t, got, tt.want)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseOn(t *testing.T) {
|
func TestParseOn(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
|
Loading…
Add table
Reference in a new issue