diff options
Diffstat (limited to 'vendor/github.com/playwright-community/playwright-go/glob.go')
| -rw-r--r-- | vendor/github.com/playwright-community/playwright-go/glob.go | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/vendor/github.com/playwright-community/playwright-go/glob.go b/vendor/github.com/playwright-community/playwright-go/glob.go new file mode 100644 index 0000000..77deba3 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/glob.go @@ -0,0 +1,170 @@ +package playwright + +import ( + "net/url" + "regexp" + "strconv" + "strings" +) + +var escapedChars = map[rune]bool{ + '$': true, + '^': true, + '+': true, + '.': true, + '*': true, + '(': true, + ')': true, + '|': true, + '\\': true, + '?': true, + '{': true, + '}': true, + '[': true, + ']': true, +} + +func globMustToRegex(glob string) *regexp.Regexp { + tokens := []string{"^"} + inGroup := false + + for i := 0; i < len(glob); i++ { + c := rune(glob[i]) + if c == '\\' && i+1 < len(glob) { + char := rune(glob[i+1]) + if _, ok := escapedChars[char]; ok { + tokens = append(tokens, "\\"+string(char)) + } else { + tokens = append(tokens, string(char)) + } + i++ + } else if c == '*' { + beforeDeep := rune(0) + if i > 0 { + beforeDeep = rune(glob[i-1]) + } + starCount := 1 + for i+1 < len(glob) && glob[i+1] == '*' { + starCount++ + i++ + } + afterDeep := rune(0) + if i+1 < len(glob) { + afterDeep = rune(glob[i+1]) + } + isDeep := starCount > 1 && (beforeDeep == '/' || beforeDeep == 0) && (afterDeep == '/' || afterDeep == 0) + if isDeep { + tokens = append(tokens, "((?:[^/]*(?:/|$))*)") + i++ + } else { + tokens = append(tokens, "([^/]*)") + } + } else { + switch c { + case '{': + inGroup = true + tokens = append(tokens, "(") + case '}': + inGroup = false + tokens = append(tokens, ")") + case ',': + if inGroup { + tokens = append(tokens, "|") + } else { + tokens = append(tokens, "\\"+string(c)) + } + default: + if _, ok := escapedChars[c]; ok { + tokens = append(tokens, "\\"+string(c)) + } else { + tokens = append(tokens, string(c)) + } + } + } + } + + tokens = append(tokens, "$") + return regexp.MustCompile(strings.Join(tokens, "")) +} + +func resolveGlobToRegex(baseURL *string, glob string, isWebSocketUrl bool) *regexp.Regexp { + if isWebSocketUrl { + baseURL = toWebSocketBaseURL(baseURL) + } + glob = resolveGlobBase(baseURL, glob) + return globMustToRegex(glob) +} + +func resolveGlobBase(baseURL *string, match string) string { + if strings.HasPrefix(match, "*") { + return match + } + + tokenMap := make(map[string]string) + mapToken := func(original string, replacement string) string { + if len(original) == 0 { + return "" + } + tokenMap[replacement] = original + return replacement + } + // Escaped `\\?` behaves the same as `?` in our glob patterns. + match = strings.ReplaceAll(match, `\\?`, "?") + // Glob symbols may be escaped in the URL and some of them such as ? affect resolution, + // so we replace them with safe components first. + relativePath := strings.Split(match, "/") + for i, token := range relativePath { + if token == "." || token == ".." || token == "" { + continue + } + // Handle special case of http*://, note that the new schema has to be + // a web schema so that slashes are properly inserted after domain. + if i == 0 && strings.HasSuffix(token, ":") { + relativePath[i] = mapToken(token, "http:") + } else { + questionIndex := strings.Index(token, "?") + if questionIndex == -1 { + relativePath[i] = mapToken(token, "$_"+strconv.Itoa(i)+"_$") + } else { + newPrefix := mapToken(token[:questionIndex], "$_"+strconv.Itoa(i)+"_$") + newSuffix := mapToken(token[questionIndex:], "?$"+strconv.Itoa(i)+"_$") + relativePath[i] = newPrefix + newSuffix + } + } + } + resolved := constructURLBasedOnBaseURL(baseURL, strings.Join(relativePath, "/")) + for token, original := range tokenMap { + resolved = strings.ReplaceAll(resolved, token, original) + } + return resolved +} + +func constructURLBasedOnBaseURL(baseURL *string, givenURL string) string { + u, err := url.Parse(givenURL) + if err != nil { + return givenURL + } + if baseURL != nil { + base, err := url.Parse(*baseURL) + if err != nil { + return givenURL + } + u = base.ResolveReference(u) + } + if u.Path == "" { // In Node.js, new URL('http://localhost') returns 'http://localhost/'. + u.Path = "/" + } + return u.String() +} + +func toWebSocketBaseURL(baseURL *string) *string { + if baseURL == nil { + return nil + } + + // Allow http(s) baseURL to match ws(s) urls. + re := regexp.MustCompile(`(?m)^http(s?://)`) + wsBaseURL := re.ReplaceAllString(*baseURL, "ws$1") + + return &wsBaseURL +} |
