-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathpatternUtils.ts
More file actions
85 lines (76 loc) · 2.65 KB
/
Copy pathpatternUtils.ts
File metadata and controls
85 lines (76 loc) · 2.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
export interface PatternValidationResult {
valid: boolean;
error?: string;
}
/**
* Validates a URL pattern string to ensure it meets specific criteria.
*
* The validation checks include:
* - The pattern is not empty or whitespace.
* - The pattern does not contain invalid characters: `<`, `>`, `"`, `|`, or `\`.
* - The pattern can be converted to a valid regular expression using `globToRegex`.
*
* @param pattern - The URL pattern string to validate.
* @returns An object indicating whether the pattern is valid and, if invalid, an error message.
*/
export const validateUrlPattern = (
pattern: string
): PatternValidationResult => {
if (!pattern.trim()) {
return { valid: false, error: "Pattern cannot be empty" };
}
const trimmedPattern = pattern.trim();
// Check for invalid characters
const invalidChars = /[<>"|\\]/;
if (invalidChars.test(trimmedPattern)) {
return { valid: false, error: "Pattern contains invalid characters" };
}
try {
// Convert glob pattern to regex and test if it's valid
const regexPattern = globToRegex(trimmedPattern);
new RegExp(regexPattern, "i");
return { valid: true };
} catch {
return { valid: false, error: "Invalid pattern format" };
}
};
export const globToRegex = (pattern: string): string => {
return pattern
.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") // Escape special regex chars
.replace(/\\\*/g, ".*") // Convert * to .*
.replace(/\\\?/g, "."); // Convert ? to .
};
/**
* Creates a regular expression from a URL pattern string, supporting wildcards.
*
* @param pattern - The URL pattern string, which may include '*' wildcards.
* @returns A RegExp object that matches URLs according to the given pattern.
*
* @example
* createPatternRegex("*.example.com");
* Matches: "https://sub.example.com", "http://foo.bar.example.com"
*
* createPatternRegex("example.com/path*");
* Matches: "https://example.com/path", "https://example.com/path/to/resource"
*/
export function createPatternRegex(pattern: string): RegExp {
// Escape regex special characters except '*'
let escaped = pattern.replace(/[-/\\^$+?.()|[\]{}]/g, "\\$&");
// Replace '*' with '.*'
escaped = escaped.replace(/\*/g, ".*");
// Build the final regex string
let regexStr = "^(https?:\\/\\/)?";
if (pattern.startsWith("*.")) {
// Wildcard subdomain
regexStr += "([\\w-]+\\.)+" + escaped.slice(2);
} else {
regexStr += escaped;
}
// Determine if pattern allows paths
if (pattern.endsWith("/*") || pattern.endsWith("*")) {
regexStr += "(\\/.*)?$";
} else {
regexStr += "\\/?$"; // Only allow optional trailing slash, not paths
}
return new RegExp(regexStr, "i");
}