Skip to content

Commit d79dfe2

Browse files
committed
feat: scoping algorithm
1 parent 4cfb509 commit d79dfe2

File tree

2 files changed

+451
-0
lines changed

2 files changed

+451
-0
lines changed

x/secrets/scope.go

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
package secrets
2+
3+
import "strings"
4+
5+
type Scope interface {
6+
Forward(pattern Pattern) (Pattern, bool)
7+
}
8+
9+
//type ReversibleScope interface {
10+
// Scope
11+
// Reverse(id ID) ID
12+
//}
13+
14+
type dscope struct {
15+
pattern Pattern
16+
}
17+
18+
func (d dscope) Forward(pattern Pattern) (Pattern, bool) {
19+
components, _ := forward(split(d.pattern.String()), split(pattern.String()))
20+
fwd, err := ParsePattern(strings.Join(components, "/"))
21+
if err != nil {
22+
return nil, false
23+
}
24+
return fwd, true
25+
}
26+
27+
func NewDynamicScope(s string) (Scope, error) {
28+
p, err := ParsePattern(s)
29+
if err != nil {
30+
return nil, err
31+
}
32+
return dscope{
33+
pattern: p,
34+
}, nil
35+
}
36+
37+
//nolint:gocyclo
38+
func forward(pattern, path []string) ([]string, bool) {
39+
var fwd []string
40+
pi, si := 0, 0
41+
42+
for pi < len(pattern) && si < len(path) {
43+
switch pattern[pi] {
44+
case "**":
45+
if pi+1 == len(pattern) {
46+
return append(fwd, path[si:]...), true
47+
}
48+
49+
if path[si] == "**" {
50+
offset := pi
51+
// replace ** in path with the {*|**} mask coming from pattern
52+
// eg ** could get replaced with **/*, **/*/**, **/*/**/*, etc
53+
for offset+1 < len(pattern) && (pattern[offset+1] == "**" || pattern[offset+1] == "*") {
54+
offset++
55+
}
56+
next := pi + 1
57+
if offset > pi {
58+
next = offset
59+
}
60+
61+
if fwdSub, ok := forward(pattern[next:], path[si:]); ok {
62+
return append(append(fwd, pattern[pi:offset]...), fwdSub...), true
63+
}
64+
65+
// -> both act as **
66+
if fwdSub, ok := forward(pattern[pi+1:], path[si+1:]); ok {
67+
return append(append(fwd, "**"), fwdSub...), true
68+
}
69+
70+
return nil, false
71+
}
72+
73+
for skip := 0; si+skip <= len(path); skip++ {
74+
if fwdSub, ok := forward(pattern[pi+1:], path[si+skip:]); ok {
75+
return append(append(fwd, path[si:si+skip]...), fwdSub...), true
76+
}
77+
}
78+
return nil, false
79+
case "*":
80+
if path[si] == "**" {
81+
if si+1 == len(path) {
82+
fwd = append(fwd, "*")
83+
pi++
84+
if pi == len(pattern) {
85+
si++
86+
}
87+
} else {
88+
if fwdSub, ok := forward(pattern[pi:], append([]string{"*"}, path[si+1:]...)); ok {
89+
return append(fwd, fwdSub...), true
90+
}
91+
if fwdSub, ok := forward(pattern[pi:], path[si+1:]); ok {
92+
return append(fwd, fwdSub...), true
93+
}
94+
return nil, false
95+
}
96+
} else {
97+
fwd = append(fwd, path[si])
98+
pi++
99+
si++
100+
}
101+
default:
102+
switch path[si] {
103+
case "*", pattern[pi]:
104+
pi++
105+
si++
106+
case "**":
107+
if pi+1 == len(pattern) {
108+
if si+1 != len(path) {
109+
return nil, false
110+
}
111+
return append(fwd, path[si]), true
112+
}
113+
if si+1 == len(path) {
114+
pi++
115+
} else {
116+
if fwdSub, ok := forward(pattern[pi+1:], path[si:]); ok {
117+
return append(fwd, fwdSub...), true
118+
}
119+
if fwdSub, ok := forward(pattern[pi:], path[si+1:]); ok {
120+
return append(fwd, fwdSub...), true
121+
}
122+
if fwdSub, ok := forward(pattern[pi:], append([]string{"*"}, path[si+1:]...)); ok {
123+
return append(fwd, fwdSub...), true
124+
}
125+
return nil, false
126+
}
127+
128+
default:
129+
if pattern[pi] != path[si] {
130+
return nil, false
131+
}
132+
}
133+
134+
}
135+
}
136+
137+
if pi < len(pattern) || si < len(path) {
138+
return nil, false
139+
}
140+
141+
return fwd, true
142+
}

0 commit comments

Comments
 (0)