@@ -43,10 +43,16 @@ var unpackPseudos = {
43
43
} ;
44
44
45
45
var stripQuotesFromPseudos = {
46
- __proto__ : unpackPseudos ,
46
+ __proto__ : null ,
47
47
"contains" : true
48
48
} ;
49
49
50
+ var quotes = {
51
+ __proto__ : null ,
52
+ "\"" : true ,
53
+ "'" : true
54
+ } ;
55
+
50
56
//unescape function taken from https://github.com/jquery/sizzle/blob/master/src/sizzle.js#L139
51
57
function funescape ( _ , escaped , escapedWhitespace ) {
52
58
var high = "0x" + escaped - 0x10000 ;
@@ -66,24 +72,24 @@ function unescapeCSS(str){
66
72
return str . replace ( re_escape , funescape ) ;
67
73
}
68
74
69
- function getClosingPos ( selector ) {
70
- var pos = 1 , counter = 1 , len = selector . length ;
75
+ function parse ( selector , options ) {
76
+ var subselects = [ ] ;
71
77
72
- for ( ; counter > 0 && pos < len ; pos ++ ) {
73
- if ( selector . charAt ( pos ) === "(" ) counter ++ ;
74
- else if ( selector . charAt ( pos ) === ")" ) counter -- ;
75
- }
78
+ selector = parseSelector ( subselects , selector + "" , options ) ;
79
+
80
+ if ( selector !== "" ) {
81
+ throw new SyntaxError ( "Unmatched selector: " + selector ) ;
82
+ }
76
83
77
- return pos ;
84
+ return subselects ;
78
85
}
79
86
80
- function parse ( selector , options ) {
81
- selector = ( selector + "" ) . trimLeft ( ) ;
87
+ function parseSelector ( subselects , selector , options ) {
88
+ var tokens = [ ] ,
89
+ sawWS = false ,
90
+ data , firstChar , name , quot ;
82
91
83
- var subselects = [ ] ,
84
- tokens = [ ] ,
85
- sawWS = false ,
86
- data , firstChar , name ;
92
+ selector = selector . trimLeft ( ) ;
87
93
88
94
function getName ( ) {
89
95
var sub = selector . match ( re_name ) [ 0 ] ;
@@ -174,34 +180,77 @@ function parse(selector, options){
174
180
data = null ;
175
181
176
182
if ( selector . charAt ( 0 ) === "(" ) {
177
- var pos = getClosingPos ( selector ) ;
178
- data = selector . substr ( 1 , pos - 2 ) ;
179
- selector = selector . substr ( pos ) ;
183
+ if ( name in unpackPseudos ) {
184
+ quot = selector . charAt ( 1 ) ;
185
+ var quoted = quot in quotes ;
186
+
187
+ selector = selector . substr ( quoted + 1 ) ;
188
+
189
+ data = [ ] ;
190
+ selector = parseSelector ( data , selector , options ) ;
180
191
181
- if ( name in stripQuotesFromPseudos ) {
182
- var quot = data . charAt ( 0 ) ;
192
+ if ( quoted ) {
193
+ if ( selector . charAt ( 0 ) !== quot ) {
194
+ throw new SyntaxError ( "unmatched quotes in :" + name ) ;
195
+ } else {
196
+ selector = selector . substr ( 1 ) ;
197
+ }
198
+ }
199
+
200
+ if ( selector . charAt ( 0 ) !== ")" ) {
201
+ throw new SyntaxError ( "missing closing parenthesis in :" + name + " " + selector ) ;
202
+ }
183
203
184
- if ( quot === data . slice ( - 1 ) && ( quot === "'" || quot === "\"" ) ) {
185
- data = data . slice ( 1 , - 1 ) ;
186
- }
204
+ selector = selector . substr ( 1 ) ;
205
+ } else {
206
+ var pos = 1 , counter = 1 ;
187
207
188
- if ( name in unpackPseudos ) {
189
- data = parse ( data , options ) ;
208
+ for ( ; counter > 0 && pos < selector . length ; pos ++ ) {
209
+ if ( selector . charAt ( pos ) === "(" ) counter ++ ;
210
+ else if ( selector . charAt ( pos ) === ")" ) counter -- ;
211
+ }
212
+
213
+ if ( counter ) {
214
+ throw new SyntaxError ( "parenthesis not matched" ) ;
215
+ }
216
+
217
+ data = selector . substr ( 1 , pos - 2 ) ;
218
+ selector = selector . substr ( pos ) ;
219
+
220
+ if ( name in stripQuotesFromPseudos ) {
221
+ quot = data . charAt ( 0 ) ;
222
+
223
+ if ( quot === data . slice ( - 1 ) && quot in quotes ) {
224
+ data = data . slice ( 1 , - 1 ) ;
225
+ }
226
+
227
+ if ( name in unpackPseudos ) {
228
+ data = parse ( data , options ) ;
229
+ }
190
230
}
191
231
}
192
232
}
193
233
194
234
tokens . push ( { type : "pseudo" , name : name , data : data } ) ;
195
235
} else {
196
- //otherwise, the parser needs to throw or it would enter an infinite loop
197
- throw new SyntaxError ( "Unmatched selector: " + firstChar + selector ) ;
236
+ if ( tokens . length && tokens [ tokens . length - 1 ] . type === "descendant" ) {
237
+ tokens . pop ( ) ;
238
+ }
239
+ addToken ( subselects , tokens ) ;
240
+ return firstChar + selector ;
198
241
}
199
242
}
200
243
}
201
244
202
- if ( subselects . length > 0 && tokens . length === 0 ) {
203
- throw new SyntaxError ( "empty sub-selector" ) ;
204
- }
245
+ addToken ( subselects , tokens ) ;
246
+
247
+ return selector ;
248
+ }
249
+
250
+ function addToken ( subselects , tokens ) {
251
+ if ( subselects . length > 0 && tokens . length === 0 ) {
252
+ throw new SyntaxError ( "empty sub-selector" ) ;
253
+ }
254
+
205
255
subselects . push ( tokens ) ;
206
- return subselects ;
207
256
}
0 commit comments