@@ -14,6 +14,35 @@ export interface ParseOptions {
1414 whitelist ?: string | string [ ] ;
1515}
1616
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+
1746/**
1847 * Parse a string for the raw tokens.
1948 */
@@ -66,54 +95,24 @@ export function parse(str: string, options: ParseOptions = {}): Token[] {
6695 }
6796
6897 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 ) ;
8399
84- if ( str [ i ] === ")" ) {
85- balanced -- ;
100+ if ( end > - 1 ) {
101+ pattern = str . slice ( i + 1 , end - 1 ) ;
102+ i = end ;
86103
87- if ( balanced === 0 ) {
88- i ++ ;
89- break ;
90- }
104+ if ( pattern [ 0 ] === "?" ) {
105+ throw new TypeError ( "Path pattern must be a capturing group" ) ;
91106 }
92107
93- pattern += str [ i ] ;
108+ if ( / \( (? = [ ^ ? ] ) / . test ( pattern ) ) {
109+ const validPattern = pattern . replace ( / \( (? = [ ^ ? ] ) / , "(?:" ) ;
94110
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+ ) ;
103114 }
104115 }
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- }
117116 }
118117
119118 // Add regular characters to the path string.
0 commit comments