@@ -26,6 +26,7 @@ export function querySelectorDeep(selector, root = document) {
2626}
2727
2828function _querySelectorDeep ( selector , findMany , root ) {
29+ selector = normalizeSelector ( selector )
2930 let lightElement = root . querySelector ( selector ) ;
3031
3132 if ( document . head . createShadowRoot || document . head . attachShadow ) {
@@ -150,4 +151,162 @@ function collectAllElementsDeep(selector = null, root) {
150151 findAllElements ( root . querySelectorAll ( '*' ) ) ;
151152
152153 return selector ? allElements . filter ( el => el . matches ( selector ) ) : allElements ;
153- }
154+ }
155+
156+
157+ // normalize-selector-rev-02.js
158+ /*
159+ author: kyle simpson (@getify)
160+ original source: https://gist.github.com/getify/9679380
161+
162+ modified for tests by david kaye (@dfkaye)
163+ 21 march 2014
164+
165+ rev-02 incorporate kyle's changes 3/2/42014
166+ */
167+ /* istanbul ignore next */
168+ function normalizeSelector ( sel ) {
169+
170+ // save unmatched text, if any
171+ function saveUnmatched ( ) {
172+ if ( unmatched ) {
173+ // whitespace needed after combinator?
174+ if ( tokens . length > 0 &&
175+ / ^ [ ~ + > ] $ / . test ( tokens [ tokens . length - 1 ] )
176+ ) {
177+ tokens . push ( " " ) ;
178+ }
179+
180+ // save unmatched text
181+ tokens . push ( unmatched ) ;
182+ }
183+ }
184+
185+ var tokens = [ ] , match , unmatched , regex , state = [ 0 ] ,
186+ next_match_idx = 0 , prev_match_idx ,
187+ not_escaped_pattern = / (?: [ ^ \\ ] | (?: ^ | [ ^ \\ ] ) (?: \\ \\ ) + ) $ / ,
188+ whitespace_pattern = / ^ \s + $ / ,
189+ state_patterns = [
190+ / \s + | \/ \* | [ " ' > ~ + \[ \( ] / g, // general
191+ / \s + | \/ \* | [ " ' \[ \] \( \) ] / g, // [..] set
192+ / \s + | \/ \* | [ " ' \[ \] \( \) ] / g, // (..) set
193+ null , // string literal (placeholder)
194+ / \* \/ / g // comment
195+ ]
196+ ;
197+
198+ sel = sel . trim ( ) ;
199+
200+ while ( true ) {
201+ unmatched = "" ;
202+
203+ regex = state_patterns [ state [ state . length - 1 ] ] ;
204+
205+ regex . lastIndex = next_match_idx ;
206+ match = regex . exec ( sel ) ;
207+
208+ // matched text to process?
209+ if ( match ) {
210+ prev_match_idx = next_match_idx ;
211+ next_match_idx = regex . lastIndex ;
212+
213+ // collect the previous string chunk not matched before this token
214+ if ( prev_match_idx < next_match_idx - match [ 0 ] . length ) {
215+ unmatched = sel . substring ( prev_match_idx , next_match_idx - match [ 0 ] . length ) ;
216+ }
217+
218+ // general, [ ] pair, ( ) pair?
219+ if ( state [ state . length - 1 ] < 3 ) {
220+ saveUnmatched ( ) ;
221+
222+ // starting a [ ] pair?
223+ if ( match [ 0 ] === "[" ) {
224+ state . push ( 1 ) ;
225+ }
226+ // starting a ( ) pair?
227+ else if ( match [ 0 ] === "(" ) {
228+ state . push ( 2 ) ;
229+ }
230+ // starting a string literal?
231+ else if ( / ^ [ " ' ] $ / . test ( match [ 0 ] ) ) {
232+ state . push ( 3 ) ;
233+ state_patterns [ 3 ] = new RegExp ( match [ 0 ] , "g" ) ;
234+ }
235+ // starting a comment?
236+ else if ( match [ 0 ] === "/*" ) {
237+ state . push ( 4 ) ;
238+ }
239+ // ending a [ ] or ( ) pair?
240+ else if ( / ^ [ \] \) ] $ / . test ( match [ 0 ] ) && state . length > 0 ) {
241+ state . pop ( ) ;
242+ }
243+ // handling whitespace or a combinator?
244+ else if ( / ^ (?: \s + | [ ~ + > ] ) $ / . test ( match [ 0 ] ) ) {
245+
246+ // need to insert whitespace before?
247+ if ( tokens . length > 0 &&
248+ ! whitespace_pattern . test ( tokens [ tokens . length - 1 ] ) &&
249+ state [ state . length - 1 ] === 0
250+ ) {
251+ // add normalized whitespace
252+ tokens . push ( " " ) ;
253+ }
254+
255+ // case-insensitive attribute selector CSS L4
256+ if ( state [ state . length - 1 ] === 1 &&
257+ tokens . length === 5 &&
258+ tokens [ 2 ] . charAt ( tokens [ 2 ] . length - 1 ) === '=' ) {
259+ tokens [ 4 ] = " " + tokens [ 4 ] ;
260+ }
261+
262+ // whitespace token we can skip?
263+ if ( whitespace_pattern . test ( match [ 0 ] ) ) {
264+ continue ;
265+ }
266+ }
267+
268+ // save matched text
269+ tokens . push ( match [ 0 ] ) ;
270+ }
271+ // otherwise, string literal or comment
272+ else {
273+ // save unmatched text
274+ tokens [ tokens . length - 1 ] += unmatched ;
275+
276+ // unescaped terminator to string literal or comment?
277+ if ( not_escaped_pattern . test ( tokens [ tokens . length - 1 ] ) ) {
278+ // comment terminator?
279+ if ( state [ state . length - 1 ] === 4 ) {
280+ // ok to drop comment?
281+ if ( tokens . length < 2 ||
282+ whitespace_pattern . test ( tokens [ tokens . length - 2 ] )
283+ ) {
284+ tokens . pop ( ) ;
285+ }
286+ // otherwise, turn comment into whitespace
287+ else {
288+ tokens [ tokens . length - 1 ] = " " ;
289+ }
290+
291+ // handled already
292+ match [ 0 ] = "" ;
293+ }
294+
295+ state . pop ( ) ;
296+ }
297+
298+ // append matched text to existing token
299+ tokens [ tokens . length - 1 ] += match [ 0 ] ;
300+ }
301+ }
302+ // otherwise, end of processing (no more matches)
303+ else {
304+ unmatched = sel . substr ( next_match_idx ) ;
305+ saveUnmatched ( ) ;
306+
307+ break ;
308+ }
309+ }
310+
311+ return tokens . join ( "" ) . trim ( ) ;
312+ }
0 commit comments