@@ -14,6 +14,35 @@ export interface ParseOptions {
14
14
whitelist ?: string | string [ ] ;
15
15
}
16
16
17
+ /**
18
+ * Balanced bracket helper function.
19
+ */
20
+ function balanced ( open : string , close : string , str : string , index : number ) {
21
+ let count = 0 ;
22
+ let i = index ;
23
+
24
+ while ( i < str . length ) {
25
+ if ( str [ i ] === "\\" ) {
26
+ i += 2 ;
27
+ continue ;
28
+ }
29
+
30
+ if ( str [ i ] === close ) {
31
+ count -- ;
32
+
33
+ if ( count === 0 ) return i + 1 ;
34
+ }
35
+
36
+ if ( str [ i ] === open ) {
37
+ count ++ ;
38
+ }
39
+
40
+ i ++ ;
41
+ }
42
+
43
+ return - 1 ;
44
+ }
45
+
17
46
/**
18
47
* Parse a string for the raw tokens.
19
48
*/
@@ -66,54 +95,24 @@ export function parse(str: string, options: ParseOptions = {}): Token[] {
66
95
}
67
96
68
97
if ( str [ i ] === "(" ) {
69
- const prev = i ;
70
- let balanced = 1 ;
71
- let invalidGroup = false ;
72
-
73
- if ( str [ i + 1 ] === "?" ) {
74
- throw new TypeError ( "Path pattern must be a capturing group" ) ;
75
- }
76
-
77
- while ( ++ i < str . length ) {
78
- if ( str [ i ] === "\\" ) {
79
- pattern += str . substr ( i , 2 ) ;
80
- i ++ ;
81
- continue ;
82
- }
98
+ const end = balanced ( "(" , ")" , str , i ) ;
83
99
84
- if ( str [ i ] === ")" ) {
85
- balanced -- ;
100
+ if ( end > - 1 ) {
101
+ pattern = str . slice ( i + 1 , end - 1 ) ;
102
+ i = end ;
86
103
87
- if ( balanced === 0 ) {
88
- i ++ ;
89
- break ;
90
- }
104
+ if ( pattern [ 0 ] === "?" ) {
105
+ throw new TypeError ( "Path pattern must be a capturing group" ) ;
91
106
}
92
107
93
- pattern += str [ i ] ;
108
+ if ( / \( (? = [ ^ ? ] ) / . test ( pattern ) ) {
109
+ const validPattern = pattern . replace ( / \( (? = [ ^ ? ] ) / , "(?:" ) ;
94
110
95
- if ( str [ i ] === "(" ) {
96
- balanced ++ ;
97
-
98
- // Better errors on nested capturing groups.
99
- if ( str [ i + 1 ] !== "?" ) {
100
- pattern += "?:" ;
101
- invalidGroup = true ;
102
- }
111
+ throw new TypeError (
112
+ `Capturing groups are not allowed in pattern, use a non-capturing group: (${ validPattern } )`
113
+ ) ;
103
114
}
104
115
}
105
-
106
- if ( invalidGroup ) {
107
- throw new TypeError (
108
- `Capturing groups are not allowed in pattern, use a non-capturing group: (${ pattern } )`
109
- ) ;
110
- }
111
-
112
- // False positive.
113
- if ( balanced > 0 ) {
114
- i = prev ;
115
- pattern = "" ;
116
- }
117
116
}
118
117
119
118
// Add regular characters to the path string.
0 commit comments