@@ -2,6 +2,8 @@ package secrets
22
33import (
44 "errors"
5+ "fmt"
6+ "strings"
57)
68
79var ErrInvalidPattern = errors .New ("invalid pattern" )
@@ -71,6 +73,9 @@ type Pattern interface {
7173 Includes (other Pattern ) bool
7274 // String formats the [Pattern] as a string
7375 String () string
76+
77+ ExpandID (other ID ) (ID , error )
78+ ExpandPattern (other Pattern ) (Pattern , error )
7479}
7580
7681type pattern string
@@ -118,6 +123,22 @@ func MustParsePattern(s string) Pattern {
118123 return pattern (s )
119124}
120125
126+ func (p pattern ) ExpandID (other ID ) (ID , error ) {
127+ val , err := replace1 (string (p ), other .String ())
128+ if err != nil {
129+ return nil , err
130+ }
131+ return id (val ), err
132+ }
133+
134+ func (p pattern ) ExpandPattern (other Pattern ) (Pattern , error ) {
135+ val , err := replace1 (string (p ), other .String ())
136+ if err != nil {
137+ return nil , err
138+ }
139+ return pattern (val ), err
140+ }
141+
121142// Filter returns a reduced [Pattern] that is subset equal to [filter].
122143// Returns false if there's no overlap between [filter] and [other].
123144// Examples:
@@ -134,3 +155,18 @@ func Filter(filter, other Pattern) (Pattern, bool) {
134155 }
135156 return nil , false
136157}
158+
159+ func replace1 (original , other string ) (string , error ) {
160+ components := split (original )
161+ var candidates []int
162+ for idx , val := range components {
163+ if val == "**" {
164+ candidates = append (candidates , idx )
165+ }
166+ }
167+ if len (candidates ) != 1 {
168+ return "" , fmt .Errorf ("expand only supports one expansion glob, pattern %s has %d" , original , len (candidates ))
169+ }
170+ components [candidates [0 ]] = other
171+ return strings .Join (components , "/" ), nil
172+ }
0 commit comments