main.go: support to trim subdomains with attrs (#3912)

This commit is contained in:
MkQtS 2026-08-05 14:35:11 +08:00 committed by GitHub
parent b7987cc2d7
commit 5dd30db805
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 26 additions and 20 deletions

34
main.go
View File

@ -408,33 +408,39 @@ func isMatchAttrFilters(entry *Entry, incFilter *Inclusion) bool {
return true return true
} }
// polishList trims redundant full/domain type subdomains and returns sorted lists
// A domain with attr(s) trims subdomains with same attr(s) and subdomains without attr
// A subdomain with attr(s) can only be trimed by parent domain with same attr(s)
func polishList(roughMap map[string]*Entry) []*Entry { func polishList(roughMap map[string]*Entry) []*Entry {
finalList := make([]*Entry, 0, len(roughMap)) finalList := make([]*Entry, 0, len(roughMap))
queuingList := make([]*Entry, 0, len(roughMap)) // Domain/full entries without attr queuingList := make([]*Entry, 0, len(roughMap))
domainsMap := make(map[string]bool) parentsMap := make(map[string]bool)
for _, entry := range roughMap { for _, entry := range roughMap {
switch entry.Type { // Bypass regexp, keyword and "full/domain with attr" switch entry.Type { // Bypass regexp and keyword
case dlc.RuleTypeRegexp, dlc.RuleTypeKeyword: case dlc.RuleTypeRegexp, dlc.RuleTypeKeyword:
finalList = append(finalList, entry) finalList = append(finalList, entry)
case dlc.RuleTypeDomain: case dlc.RuleTypeDomain:
domainsMap[entry.Value] = true parentsMap[entry.Value] = true
if len(entry.Attrs) != 0 { if len(entry.Attrs) != 0 {
finalList = append(finalList, entry) // `sub.example.org:@attr1,@attr2`
} else { // Ensure no dot exists except the domain (entry.Value) part
queuingList = append(queuingList, entry) _, domainAndAttrs, _ := strings.Cut(entry.Plain, ":")
parentsMap[domainAndAttrs] = true
} }
queuingList = append(queuingList, entry)
case dlc.RuleTypeFullDomain: case dlc.RuleTypeFullDomain:
if len(entry.Attrs) != 0 { queuingList = append(queuingList, entry)
finalList = append(finalList, entry)
} else {
queuingList = append(queuingList, entry)
}
} }
} }
// Remove redundant subdomains for full/domain without attr // Remove redundant subdomains for full/domain without attr
for _, qentry := range queuingList { for _, qentry := range queuingList {
isRedundant := false isRedundant := false
pd := qentry.Value // To be parent domain var pd string // To be parent domain (with attrs)
if len(qentry.Attrs) == 0 {
pd = qentry.Value
} else {
_, pd, _ = strings.Cut(qentry.Plain, ":")
}
if qentry.Type == dlc.RuleTypeFullDomain { if qentry.Type == dlc.RuleTypeFullDomain {
pd = "." + pd // So that `domain:example.org` overrides `full:example.org` pd = "." + pd // So that `domain:example.org` overrides `full:example.org`
} }
@ -444,7 +450,7 @@ func polishList(roughMap map[string]*Entry) []*Entry {
if !hasParent { if !hasParent {
break break
} }
if domainsMap[pd] { if parentsMap[pd] {
isRedundant = true isRedundant = true
break break
} }

View File

@ -108,12 +108,12 @@ func TestParseInclusion(t *testing.T) {
func TestPolishList(t *testing.T) { func TestPolishList(t *testing.T) {
rules := []struct{ typ, rule string }{ rules := []struct{ typ, rule string }{
{"domain", "example.com"}, {"domain", "example.com @cn"},
{"domain", "sub.example.com"}, // Redundant {"domain", "sub.example.com"}, // Redundant, no attribute
{"full", "www.example.com"}, // Redundant {"full", "www.example.com @cn"}, // Redundant, same attribute
{"full", "example.com"}, // Redundant {"full", "example.com"}, // Redundant, no attribute
{"full", "example.org"}, // Kept, no parent domain rule {"full", "example.org"}, // Kept, no parent domain rule
{"domain", "ads.example.com @ads"}, // Kept, has attribute {"domain", "ads.example.com @ads"}, // Kept, different attribute
{"keyword", "example"}, {"keyword", "example"},
} }
roughMap := make(map[string]*Entry, len(rules)) roughMap := make(map[string]*Entry, len(rules))
@ -124,7 +124,7 @@ func TestPolishList(t *testing.T) {
} }
roughMap[entry.Plain] = entry roughMap[entry.Plain] = entry
} }
want := []string{"domain:ads.example.com:@ads", "domain:example.com", "full:example.org", "keyword:example"} want := []string{"domain:ads.example.com:@ads", "domain:example.com:@cn", "full:example.org", "keyword:example"}
assertPlains(t, "polishList", polishList(roughMap), want) assertPlains(t, "polishList", polishList(roughMap), want)
} }