Add path matcher.
This commit is contained in:
75
editorconfig/path_matcher.go
Normal file
75
editorconfig/path_matcher.go
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
package editorconfig
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Converts a string from a .editorconfig file to a Go-compatible regex, according to the rules
|
||||||
|
* documented under "Wildcard Patterns" here:
|
||||||
|
* http://docs.editorconfig.org/en/master/editorconfig-format.html#patterns
|
||||||
|
*
|
||||||
|
* * Matches any string of characters, except path separators (/)
|
||||||
|
* ** Matches any string of characters
|
||||||
|
* ? Matches any single character
|
||||||
|
* [seq] Matches any single character in seq
|
||||||
|
* [!seq] Matches any single character not in seq
|
||||||
|
* {s1,s2,s3} Matches any of the strings given (separated by commas, can be nested)
|
||||||
|
* {num1..num2} Matches any integer numbers between num1 and num2, where num1 and num2 can be either positive or negative
|
||||||
|
*/
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var metaCharsRegexp = []*regexp.Regexp{
|
||||||
|
// Characters .+$^!()
|
||||||
|
regexp.MustCompile(`([\.\+\$\^\!\(\)])`),
|
||||||
|
// [ not followed by a ]
|
||||||
|
regexp.MustCompile(`(\[[^\]]*)$`),
|
||||||
|
// ] not preceded by a [
|
||||||
|
regexp.MustCompile(`^([^\[]*\])`),
|
||||||
|
}
|
||||||
|
|
||||||
|
func ConvertWildcardPatternToGoRegexp(pattern string) *regexp.Regexp {
|
||||||
|
originalPattern := pattern
|
||||||
|
|
||||||
|
for _, r := range metaCharsRegexp {
|
||||||
|
pattern = r.ReplaceAllString(pattern, "\\$1")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle **
|
||||||
|
pattern = strings.Replace(pattern, `**`, `.+`, -1)
|
||||||
|
|
||||||
|
// Handle *
|
||||||
|
pattern = strings.Replace(pattern, `*`, `[^/\\]+`, -1)
|
||||||
|
|
||||||
|
// Handle ?
|
||||||
|
pattern = strings.Replace(pattern, `?`, `.`, -1)
|
||||||
|
|
||||||
|
// [seq] should work already.
|
||||||
|
|
||||||
|
// Handle [!seq]
|
||||||
|
pattern = strings.Replace(pattern, `[\!`, `[^`, -1)
|
||||||
|
|
||||||
|
// Handle {s1,s2,s3}
|
||||||
|
for i := 1; i < 7; i++ {
|
||||||
|
find := `\{([^,}]+)` + strings.Repeat(`,([^,}]+)`, i) + `\}`
|
||||||
|
replace := "($1"
|
||||||
|
for ii := 1; ii <= i; ii++ {
|
||||||
|
replace += "|$" + strconv.Itoa(ii+1)
|
||||||
|
}
|
||||||
|
replace += ")"
|
||||||
|
pattern = regexp.MustCompile(find).ReplaceAllString(pattern, replace)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle {num1..num2}
|
||||||
|
// @todo - This is currently not fully supported. If there is a numeric range, we only check
|
||||||
|
// that numbers are present; we don't check if the numbers present are within the correct range.
|
||||||
|
pattern = regexp.MustCompile(`\{-?\d+\\.\\.-?\d+\}`).ReplaceAllString(pattern, `[-0-9]+`)
|
||||||
|
|
||||||
|
r, err := regexp.Compile(pattern)
|
||||||
|
if err != nil {
|
||||||
|
ExitBecauseOfInternalError("A file pattern could not be parsed: " + originalPattern)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
46
editorconfig/path_matcher_test.go
Normal file
46
editorconfig/path_matcher_test.go
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package editorconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConvertWildcardPatternToGoRegexp(t *testing.T) {
|
||||||
|
RunConvertWildcardPatternToGoRegexp := func(input string, expected string) {
|
||||||
|
result := ConvertWildcardPatternToGoRegexp(input).String()
|
||||||
|
if result != expected {
|
||||||
|
t.Error("For " + input + " got " + result + " but expected " + expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that special regex characters are escaped.
|
||||||
|
RunConvertWildcardPatternToGoRegexp(`[hello :).sql`, `\[hello :\)\.sql`)
|
||||||
|
RunConvertWildcardPatternToGoRegexp(`]hello(`, `\]hello\(`)
|
||||||
|
|
||||||
|
// Test *
|
||||||
|
RunConvertWildcardPatternToGoRegexp(`*.go`, `[^/\\]+\.go`)
|
||||||
|
RunConvertWildcardPatternToGoRegexp(`folder/*.go`, `folder/[^/\\]+\.go`)
|
||||||
|
|
||||||
|
// Test **
|
||||||
|
RunConvertWildcardPatternToGoRegexp(`**.go`, `.+\.go`)
|
||||||
|
RunConvertWildcardPatternToGoRegexp(`folder (copy)/**.go`, `folder \(copy\)/.+\.go`)
|
||||||
|
|
||||||
|
// Test ?
|
||||||
|
RunConvertWildcardPatternToGoRegexp(`words-beginning-with-?.txt`, `words-beginning-with-.\.txt`)
|
||||||
|
RunConvertWildcardPatternToGoRegexp(`words beginning with ??.txt`, `words beginning with ..\.txt`)
|
||||||
|
|
||||||
|
// Test [seq]
|
||||||
|
RunConvertWildcardPatternToGoRegexp(`hexadecimal-ids/[a-f0-9]/document`, `hexadecimal-ids/[a-f0-9]/document`)
|
||||||
|
|
||||||
|
// Test [!seq]
|
||||||
|
RunConvertWildcardPatternToGoRegexp(`names-not-beginning-with-[!A-G]`, `names-not-beginning-with-[^A-G]`)
|
||||||
|
|
||||||
|
// Test {s1,s2,s3}
|
||||||
|
RunConvertWildcardPatternToGoRegexp(`animals/{aardvark,bunny}/pictures`, `animals/(aardvark|bunny)/pictures`)
|
||||||
|
RunConvertWildcardPatternToGoRegexp(`animals/{aardvark,bunny,cheetah,donkey}/pictures`, `animals/(aardvark|bunny|cheetah|donkey)/pictures`)
|
||||||
|
|
||||||
|
// Test {num1..num2} (this is not yet fully supported)
|
||||||
|
RunConvertWildcardPatternToGoRegexp(`photos/{-500..999}.jpg`, `photos/[-0-9]+\.jpg`)
|
||||||
|
|
||||||
|
// Test everything together.
|
||||||
|
RunConvertWildcardPatternToGoRegexp(`*/**/[a-z]/{photos,videos}/{0..5}.*`, `[^/\\]+/.+/[a-z]/(photos|videos)/[-0-9]+\.[^/\\]+`)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user